From 789baf5541fa78b666a9153b33c48373cdb1ef10 Mon Sep 17 00:00:00 2001 From: John Guo Date: Thu, 9 Jan 2025 12:00:45 +0800 Subject: [PATCH 01/48] fix(database/gdb): json type field incorrect scanning to string slice attribute --- cmd/gf/go.sum | 28 +- container/gvar/gvar.go | 196 +- container/gvar/gvar_basic.go | 105 + container/gvar/gvar_copy.go | 30 + container/gvar/gvar_scan.go | 7 +- container/gvar/gvar_set.go | 24 + container/gvar/gvar_time.go | 34 + contrib/config/apollo/go.mod | 13 +- contrib/config/apollo/go.sum | 30 +- contrib/config/consul/go.mod | 13 +- contrib/config/consul/go.sum | 43 +- contrib/config/kubecm/go.mod | 14 +- contrib/config/kubecm/go.sum | 34 +- contrib/config/nacos/go.mod | 13 +- contrib/config/nacos/go.sum | 30 +- contrib/config/polaris/go.mod | 14 +- contrib/config/polaris/go.sum | 29 +- contrib/drivers/clickhouse/go.mod | 15 +- contrib/drivers/clickhouse/go.sum | 34 +- contrib/drivers/dm/go.mod | 14 +- contrib/drivers/dm/go.sum | 34 +- contrib/drivers/mssql/go.mod | 14 +- contrib/drivers/mssql/go.sum | 42 +- contrib/drivers/mysql/go.mod | 14 +- contrib/drivers/mysql/go.sum | 34 +- .../mysql/mysql_z_unit_feature_hook_test.go | 211 +- .../mysql_z_unit_feature_model_struct_test.go | 963 +-- .../drivers/mysql/mysql_z_unit_issue_test.go | 2897 +++---- .../drivers/mysql/mysql_z_unit_model_test.go | 6896 +++++++++-------- .../{issue1380.sql => issues/1380.sql} | 0 .../{issue1401.sql => issues/1401.sql} | 0 .../{issue1412.sql => issues/1412.sql} | 0 .../{issue2105.sql => issues/2105.sql} | 0 .../{issue2119.sql => issues/2119.sql} | 0 .../{issue2439.sql => issues/2439.sql} | 0 .../{issue2643.sql => issues/2643.sql} | 0 .../{issue3086.sql => issues/3086.sql} | 0 .../{issue3218.sql => issues/3218.sql} | 0 .../{issue3626.sql => issues/3626.sql} | 0 .../{issue3754.sql => issues/3754.sql} | 0 .../{issue3915.sql => issues/3915.sql} | 0 .../{issue4034.sql => issues/4034.sql} | 0 .../drivers/mysql/testdata/issues/4086.sql | 10 + contrib/drivers/oracle/go.mod | 14 +- contrib/drivers/oracle/go.sum | 34 +- contrib/drivers/pgsql/go.mod | 14 +- contrib/drivers/pgsql/go.sum | 34 +- contrib/drivers/pgsql/pgsql_convert.go | 220 +- contrib/drivers/sqlite/go.mod | 15 +- contrib/drivers/sqlite/go.sum | 37 +- contrib/drivers/sqlitecgo/go.mod | 14 +- contrib/drivers/sqlitecgo/go.sum | 34 +- contrib/nosql/redis/go.mod | 14 +- contrib/nosql/redis/go.sum | 36 +- contrib/registry/consul/go.mod | 13 +- contrib/registry/consul/go.sum | 47 +- contrib/registry/etcd/go.mod | 10 +- contrib/registry/etcd/go.sum | 32 +- contrib/registry/file/go.mod | 14 +- contrib/registry/file/go.sum | 34 +- contrib/registry/nacos/go.mod | 13 +- contrib/registry/nacos/go.sum | 30 +- contrib/registry/polaris/go.mod | 12 +- contrib/registry/polaris/go.sum | 24 +- contrib/registry/zookeeper/go.mod | 14 +- contrib/registry/zookeeper/go.sum | 34 +- contrib/rpc/grpcx/go.mod | 13 +- contrib/rpc/grpcx/go.sum | 33 +- contrib/sdk/httpclient/go.mod | 14 +- contrib/sdk/httpclient/go.sum | 34 +- contrib/trace/otlpgrpc/go.mod | 13 +- contrib/trace/otlpgrpc/go.sum | 31 +- contrib/trace/otlphttp/go.mod | 13 +- contrib/trace/otlphttp/go.sum | 30 +- database/gdb/gdb.go | 1677 ++-- database/gdb/gdb_core.go | 1060 +-- database/gdb/gdb_core_structure.go | 880 +-- database/gdb/gdb_core_underlying.go | 865 ++- database/gdb/gdb_type_result.go | 247 +- database/gdb/gdb_type_value.go | 19 + database/gdb/internal/defines/defines.go | 36 + database/gdb/internal/fieldvar/fieldvar.go | 63 + .../gdb/internal/fieldvar/fieldvar_basic.go | 99 + .../gdb/internal/fieldvar/fieldvar_copy.go | 30 + database/gdb/internal/fieldvar/fieldvar_is.go | 51 + .../gdb/internal/fieldvar/fieldvar_map.go | 65 + .../gdb/internal/fieldvar/fieldvar_scan.go | 18 + .../gdb/internal/fieldvar/fieldvar_set.go | 14 + .../gdb/internal/fieldvar/fieldvar_slice.go | 86 + .../gdb/internal/fieldvar/fieldvar_struct.go | 23 + .../gdb/internal/fieldvar/fieldvar_time.go | 34 + example/go.mod | 10 +- example/go.sum | 28 +- 93 files changed, 9580 insertions(+), 8484 deletions(-) create mode 100644 container/gvar/gvar_basic.go create mode 100644 container/gvar/gvar_copy.go create mode 100644 container/gvar/gvar_set.go create mode 100644 container/gvar/gvar_time.go rename contrib/drivers/mysql/testdata/{issue1380.sql => issues/1380.sql} (100%) rename contrib/drivers/mysql/testdata/{issue1401.sql => issues/1401.sql} (100%) rename contrib/drivers/mysql/testdata/{issue1412.sql => issues/1412.sql} (100%) rename contrib/drivers/mysql/testdata/{issue2105.sql => issues/2105.sql} (100%) rename contrib/drivers/mysql/testdata/{issue2119.sql => issues/2119.sql} (100%) rename contrib/drivers/mysql/testdata/{issue2439.sql => issues/2439.sql} (100%) rename contrib/drivers/mysql/testdata/{issue2643.sql => issues/2643.sql} (100%) rename contrib/drivers/mysql/testdata/{issue3086.sql => issues/3086.sql} (100%) rename contrib/drivers/mysql/testdata/{issue3218.sql => issues/3218.sql} (100%) rename contrib/drivers/mysql/testdata/{issue3626.sql => issues/3626.sql} (100%) rename contrib/drivers/mysql/testdata/{issue3754.sql => issues/3754.sql} (100%) rename contrib/drivers/mysql/testdata/{issue3915.sql => issues/3915.sql} (100%) rename contrib/drivers/mysql/testdata/{issue4034.sql => issues/4034.sql} (100%) create mode 100644 contrib/drivers/mysql/testdata/issues/4086.sql create mode 100644 database/gdb/gdb_type_value.go create mode 100644 database/gdb/internal/defines/defines.go create mode 100644 database/gdb/internal/fieldvar/fieldvar.go create mode 100644 database/gdb/internal/fieldvar/fieldvar_basic.go create mode 100644 database/gdb/internal/fieldvar/fieldvar_copy.go create mode 100644 database/gdb/internal/fieldvar/fieldvar_is.go create mode 100644 database/gdb/internal/fieldvar/fieldvar_map.go create mode 100644 database/gdb/internal/fieldvar/fieldvar_scan.go create mode 100644 database/gdb/internal/fieldvar/fieldvar_set.go create mode 100644 database/gdb/internal/fieldvar/fieldvar_slice.go create mode 100644 database/gdb/internal/fieldvar/fieldvar_struct.go create mode 100644 database/gdb/internal/fieldvar/fieldvar_time.go diff --git a/cmd/gf/go.sum b/cmd/gf/go.sum index 1451be4ef79..47a75885b3e 100644 --- a/cmd/gf/go.sum +++ b/cmd/gf/go.sum @@ -39,20 +39,20 @@ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.8.2 h1:4g5n8QdJA7ZEuDfWFeVQKMhul6RtOT89ObYAgVnxN+U= -github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.8.2/go.mod h1:xW1mgNK0vTLfRSCnO0No8G4lCGNpXx1Jlhs6B1vzD+8= -github.com/gogf/gf/contrib/drivers/mssql/v2 v2.8.2 h1:aNscErx5mcC28Q1L0MsZFFXybzLY/IJhskyiPAbxB78= -github.com/gogf/gf/contrib/drivers/mssql/v2 v2.8.2/go.mod h1:yj6+Ds2BGzYcHthPvMnxhDRzq0o28HyO9E1Fsko0Lf8= -github.com/gogf/gf/contrib/drivers/mysql/v2 v2.8.2 h1:thK4DZT0irDrnhIxkap5JqBuBIJaXQ0IMvlIzuRGgVQ= -github.com/gogf/gf/contrib/drivers/mysql/v2 v2.8.2/go.mod h1:Vg7XaiwsQ27YmpDqzwCQ+yt10KntTvcP9iOoFL5DF40= -github.com/gogf/gf/contrib/drivers/oracle/v2 v2.8.2 h1:ZukTXB9drVDmSdrFjCYHVzHj0kAvGKISrrW3WKU1xTg= -github.com/gogf/gf/contrib/drivers/oracle/v2 v2.8.2/go.mod h1:wr+KA5h3+aJQk5XiA1qSNKxWBVrzlu8MVYKl1NqcQj4= -github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.8.2 h1:BsEBGoVfa4SPJ8GhNkH9PPtoSLydXK+VgcbpxyGF9Ps= -github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.8.2/go.mod h1:OSlAQeO7fZMbscxZomMCBcZWHSxpfeXIi6ELeKszSPU= -github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.8.2 h1:144IdPDn6xyHVQ5aP4qsstFvNOLqvWyz+GtH3JD1rWg= -github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.8.2/go.mod h1:xOgOp3SSdWHIEqviYC1kd3p6mJtfFkrcinBWdpgVUxc= -github.com/gogf/gf/v2 v2.8.2 h1:4k641rn+hV1COAKygqsqcTm8+lDTkcO8HQ4iBv/uTFs= -github.com/gogf/gf/v2 v2.8.2/go.mod h1:n++xPYGUUMadw6IygLEgGZqc6y6DRLrJKg5kqCrPLWY= +github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.8.3 h1:b/AQMTxiHKPHsidEdk471AC5pkfoK88a5cPmKnzE53U= +github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.8.3/go.mod h1:qYrF+x5urXLhce3pMcUAyccIsw3Oec0htynoDE4Boi4= +github.com/gogf/gf/contrib/drivers/mssql/v2 v2.8.3 h1:F7Gt1y6YsYOIvgrUlRK07H29BL77dEgLPXilTqqVC80= +github.com/gogf/gf/contrib/drivers/mssql/v2 v2.8.3/go.mod h1:K5prIMZwHANSZrqZbfm6PoEIMfLtd0PwR7u+hZD9HFs= +github.com/gogf/gf/contrib/drivers/mysql/v2 v2.8.3 h1:RtoBg5HWACFrgIrFkpzH94kxSd5EWefNAq5k6olNY6c= +github.com/gogf/gf/contrib/drivers/mysql/v2 v2.8.3/go.mod h1:elZjckHRCejwml5Kdx2zfhOUDiAV3r5i4BgXcKAeH00= +github.com/gogf/gf/contrib/drivers/oracle/v2 v2.8.3 h1:10/RCoWmvQ6PSm+leoS6CsKijH4dB38HOXLgP5+aScQ= +github.com/gogf/gf/contrib/drivers/oracle/v2 v2.8.3/go.mod h1:XSaHf3/vTlzj/zioUbzKmaffPuoKvPV639fT91caheM= +github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.8.3 h1:DvpoiVac1cwGVDTqC6wzFbDb+gXNzcceRgZUIcuTmaI= +github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.8.3/go.mod h1:zugvYVb6c/X9rJ8Gb6b5WkMe+bFz2BsxQ5OLf4RSZos= +github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.8.3 h1:3pdibfm4UOiTGGh6UD8jfMyGZBGH9ikrrIMU8i/XANA= +github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.8.3/go.mod h1:G5rfcFkBhtmZT4+CU7A3fJH3sNmP4WRIaJ+4JFeVE08= +github.com/gogf/gf/v2 v2.8.3 h1:h9Px3lqJnnH6It0AqHRz4/1hx0JmvaSf1IvUir5x1rA= +github.com/gogf/gf/v2 v2.8.3/go.mod h1:n++xPYGUUMadw6IygLEgGZqc6y6DRLrJKg5kqCrPLWY= github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f h1:7xfXR/BhG3JDqO1s45n65Oyx9t4E/UqDOXep6jXdLCM= github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f/go.mod h1:HnYoio6S7VaFJdryKcD/r9HgX+4QzYfr00XiXUo/xz0= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= diff --git a/container/gvar/gvar.go b/container/gvar/gvar.go index 3f7781421c6..99e13134f44 100644 --- a/container/gvar/gvar.go +++ b/container/gvar/gvar.go @@ -8,198 +8,48 @@ package gvar import ( - "time" - - "github.com/gogf/gf/v2/container/gtype" - "github.com/gogf/gf/v2/internal/deepcopy" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/util/gconv" - "github.com/gogf/gf/v2/util/gutil" + "github.com/gogf/gf/v2/container/gtype" + "github.com/gogf/gf/v2/internal/json" ) // Var is an universal variable type implementer. type Var struct { - value interface{} // Underlying value. - safe bool // Concurrent safe or not. + value interface{} // Underlying value. + safe bool // Concurrent safe or not. } // New creates and returns a new Var with given `value`. // The optional parameter `safe` specifies whether Var is used in concurrent-safety, // which is false in default. func New(value interface{}, safe ...bool) *Var { - if len(safe) > 0 && safe[0] { - return &Var{ - value: gtype.NewInterface(value), - safe: true, - } - } - return &Var{ - value: value, - } -} - -// Copy does a deep copy of current Var and returns a pointer to this Var. -func (v *Var) Copy() *Var { - return New(gutil.Copy(v.Val()), v.safe) -} - -// Clone does a shallow copy of current Var and returns a pointer to this Var. -func (v *Var) Clone() *Var { - return New(v.Val(), v.safe) -} - -// Set sets `value` to `v`, and returns the old value. -func (v *Var) Set(value interface{}) (old interface{}) { - if v.safe { - if t, ok := v.value.(*gtype.Interface); ok { - old = t.Set(value) - return - } - } - old = v.value - v.value = value - return -} - -// Val returns the current value of `v`. -func (v *Var) Val() interface{} { - if v == nil { - return nil - } - if v.safe { - if t, ok := v.value.(*gtype.Interface); ok { - return t.Val() - } - } - return v.value -} - -// Interface is alias of Val. -func (v *Var) Interface() interface{} { - return v.Val() -} - -// Bytes converts and returns `v` as []byte. -func (v *Var) Bytes() []byte { - return gconv.Bytes(v.Val()) -} - -// String converts and returns `v` as string. -func (v *Var) String() string { - return gconv.String(v.Val()) -} - -// Bool converts and returns `v` as bool. -func (v *Var) Bool() bool { - return gconv.Bool(v.Val()) -} - -// Int converts and returns `v` as int. -func (v *Var) Int() int { - return gconv.Int(v.Val()) -} - -// Int8 converts and returns `v` as int8. -func (v *Var) Int8() int8 { - return gconv.Int8(v.Val()) -} - -// Int16 converts and returns `v` as int16. -func (v *Var) Int16() int16 { - return gconv.Int16(v.Val()) -} - -// Int32 converts and returns `v` as int32. -func (v *Var) Int32() int32 { - return gconv.Int32(v.Val()) -} - -// Int64 converts and returns `v` as int64. -func (v *Var) Int64() int64 { - return gconv.Int64(v.Val()) -} - -// Uint converts and returns `v` as uint. -func (v *Var) Uint() uint { - return gconv.Uint(v.Val()) -} - -// Uint8 converts and returns `v` as uint8. -func (v *Var) Uint8() uint8 { - return gconv.Uint8(v.Val()) -} - -// Uint16 converts and returns `v` as uint16. -func (v *Var) Uint16() uint16 { - return gconv.Uint16(v.Val()) -} - -// Uint32 converts and returns `v` as uint32. -func (v *Var) Uint32() uint32 { - return gconv.Uint32(v.Val()) -} - -// Uint64 converts and returns `v` as uint64. -func (v *Var) Uint64() uint64 { - return gconv.Uint64(v.Val()) -} - -// Float32 converts and returns `v` as float32. -func (v *Var) Float32() float32 { - return gconv.Float32(v.Val()) -} - -// Float64 converts and returns `v` as float64. -func (v *Var) Float64() float64 { - return gconv.Float64(v.Val()) -} - -// Time converts and returns `v` as time.Time. -// The parameter `format` specifies the format of the time string using gtime, -// eg: Y-m-d H:i:s. -func (v *Var) Time(format ...string) time.Time { - return gconv.Time(v.Val(), format...) -} - -// Duration converts and returns `v` as time.Duration. -// If value of `v` is string, then it uses time.ParseDuration for conversion. -func (v *Var) Duration() time.Duration { - return gconv.Duration(v.Val()) -} - -// GTime converts and returns `v` as *gtime.Time. -// The parameter `format` specifies the format of the time string using gtime, -// eg: Y-m-d H:i:s. -func (v *Var) GTime(format ...string) *gtime.Time { - return gconv.GTime(v.Val(), format...) + if len(safe) > 0 && safe[0] { + return &Var{ + value: gtype.NewInterface(value), + safe: true, + } + } + return &Var{ + value: value, + } } // MarshalJSON implements the interface MarshalJSON for json.Marshal. -func (v Var) MarshalJSON() ([]byte, error) { - return json.Marshal(v.Val()) +func (v *Var) MarshalJSON() ([]byte, error) { + return json.Marshal(v.Val()) } // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. func (v *Var) UnmarshalJSON(b []byte) error { - var i interface{} - if err := json.UnmarshalUseNumber(b, &i); err != nil { - return err - } - v.Set(i) - return nil + var i interface{} + if err := json.UnmarshalUseNumber(b, &i); err != nil { + return err + } + v.Set(i) + return nil } // UnmarshalValue is an interface implement which sets any type of value for Var. func (v *Var) UnmarshalValue(value interface{}) error { - v.Set(value) - return nil -} - -// DeepCopy implements interface for deep copy of current type. -func (v *Var) DeepCopy() interface{} { - if v == nil { - return nil - } - return New(deepcopy.Copy(v.Val()), v.safe) + v.Set(value) + return nil } diff --git a/container/gvar/gvar_basic.go b/container/gvar/gvar_basic.go new file mode 100644 index 00000000000..9bd87ece7f5 --- /dev/null +++ b/container/gvar/gvar_basic.go @@ -0,0 +1,105 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gvar + +import ( + "github.com/gogf/gf/v2/container/gtype" + "github.com/gogf/gf/v2/util/gconv" +) + +// Val returns the current value of `v`. +func (v *Var) Val() interface{} { + if v == nil { + return nil + } + if v.safe { + if t, ok := v.value.(*gtype.Interface); ok { + return t.Val() + } + } + return v.value +} + +// Interface is alias of Val. +func (v *Var) Interface() interface{} { + return v.Val() +} + +// Bytes converts and returns `v` as []byte. +func (v *Var) Bytes() []byte { + return gconv.Bytes(v.Val()) +} + +// String converts and returns `v` as string. +func (v *Var) String() string { + return gconv.String(v.Val()) +} + +// Bool converts and returns `v` as bool. +func (v *Var) Bool() bool { + return gconv.Bool(v.Val()) +} + +// Int converts and returns `v` as int. +func (v *Var) Int() int { + return gconv.Int(v.Val()) +} + +// Int8 converts and returns `v` as int8. +func (v *Var) Int8() int8 { + return gconv.Int8(v.Val()) +} + +// Int16 converts and returns `v` as int16. +func (v *Var) Int16() int16 { + return gconv.Int16(v.Val()) +} + +// Int32 converts and returns `v` as int32. +func (v *Var) Int32() int32 { + return gconv.Int32(v.Val()) +} + +// Int64 converts and returns `v` as int64. +func (v *Var) Int64() int64 { + return gconv.Int64(v.Val()) +} + +// Uint converts and returns `v` as uint. +func (v *Var) Uint() uint { + return gconv.Uint(v.Val()) +} + +// Uint8 converts and returns `v` as uint8. +func (v *Var) Uint8() uint8 { + return gconv.Uint8(v.Val()) +} + +// Uint16 converts and returns `v` as uint16. +func (v *Var) Uint16() uint16 { + return gconv.Uint16(v.Val()) +} + +// Uint32 converts and returns `v` as uint32. +func (v *Var) Uint32() uint32 { + return gconv.Uint32(v.Val()) +} + +// Uint64 converts and returns `v` as uint64. +func (v *Var) Uint64() uint64 { + return gconv.Uint64(v.Val()) +} + +// Float32 converts and returns `v` as float32. +func (v *Var) Float32() float32 { + return gconv.Float32(v.Val()) +} + +// Float64 converts and returns `v` as float64. +func (v *Var) Float64() float64 { + return gconv.Float64(v.Val()) +} diff --git a/container/gvar/gvar_copy.go b/container/gvar/gvar_copy.go new file mode 100644 index 00000000000..2bb99919cf0 --- /dev/null +++ b/container/gvar/gvar_copy.go @@ -0,0 +1,30 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gvar + +import ( + "github.com/gogf/gf/v2/internal/deepcopy" + "github.com/gogf/gf/v2/util/gutil" +) + +// Copy does a deep copy of current Var and returns a pointer to this Var. +func (v *Var) Copy() *Var { + return New(gutil.Copy(v.Val()), v.safe) +} + +// Clone does a shallow copy of current Var and returns a pointer to this Var. +func (v *Var) Clone() *Var { + return New(v.Val(), v.safe) +} + +// DeepCopy implements interface for deep copy of current type. +func (v *Var) DeepCopy() interface{} { + if v == nil { + return nil + } + return New(deepcopy.Copy(v.Val()), v.safe) +} diff --git a/container/gvar/gvar_scan.go b/container/gvar/gvar_scan.go index 469005b5034..9d47a22f230 100644 --- a/container/gvar/gvar_scan.go +++ b/container/gvar/gvar_scan.go @@ -7,13 +7,12 @@ package gvar import ( - "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/gconv" ) -// Scan automatically checks the type of `pointer` and converts `params` to `pointer`. It supports `pointer` -// with type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct` for converting. +// Scan automatically checks the type of `pointer` and converts value of Var to `pointer`. // // See gconv.Scan. func (v *Var) Scan(pointer interface{}, mapping ...map[string]string) error { - return gconv.Scan(v.Val(), pointer, mapping...) + return gconv.Scan(v.Val(), pointer, mapping...) } diff --git a/container/gvar/gvar_set.go b/container/gvar/gvar_set.go new file mode 100644 index 00000000000..57ac97ae5b7 --- /dev/null +++ b/container/gvar/gvar_set.go @@ -0,0 +1,24 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gvar + +import ( + "github.com/gogf/gf/v2/container/gtype" +) + +// Set sets `value` to `v`, and returns the old value. +func (v *Var) Set(value interface{}) (old interface{}) { + if v.safe { + if t, ok := v.value.(*gtype.Interface); ok { + old = t.Set(value) + return + } + } + old = v.value + v.value = value + return +} diff --git a/container/gvar/gvar_time.go b/container/gvar/gvar_time.go new file mode 100644 index 00000000000..d709ce89fdd --- /dev/null +++ b/container/gvar/gvar_time.go @@ -0,0 +1,34 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gvar + +import ( + "time" + + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" +) + +// Time converts and returns `v` as time.Time. +// The parameter `format` specifies the format of the time string using gtime, +// eg: Y-m-d H:i:s. +func (v *Var) Time(format ...string) time.Time { + return gconv.Time(v.Val(), format...) +} + +// Duration converts and returns `v` as time.Duration. +// If value of `v` is string, then it uses time.ParseDuration for conversion. +func (v *Var) Duration() time.Duration { + return gconv.Duration(v.Val()) +} + +// GTime converts and returns `v` as *gtime.Time. +// The parameter `format` specifies the format of the time string using gtime, +// eg: Y-m-d H:i:s. +func (v *Var) GTime(format ...string) *gtime.Time { + return gconv.GTime(v.Val(), format...) +} diff --git a/contrib/config/apollo/go.mod b/contrib/config/apollo/go.mod index 5080c2b1489..5c8aa52f773 100644 --- a/contrib/config/apollo/go.mod +++ b/contrib/config/apollo/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/config/apollo/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/apolloconfig/agollo/v4 v4.3.1 @@ -15,6 +17,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -32,10 +35,10 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.8.1 // indirect github.com/subosito/gotenv v1.2.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/contrib/config/apollo/go.sum b/contrib/config/apollo/go.sum index ea5fb99d01d..6c1ae549b60 100644 --- a/contrib/config/apollo/go.sum +++ b/contrib/config/apollo/go.sum @@ -133,6 +133,7 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -150,6 +151,8 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= @@ -190,8 +193,9 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -237,6 +241,8 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -260,7 +266,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tevid/gohamcrest v1.1.1 h1:ou+xSqlIw1xfGTg1uq1nif/htZ2S3EzRqLm2BP+tYU0= @@ -280,14 +287,14 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= @@ -610,8 +617,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/contrib/config/consul/go.mod b/contrib/config/consul/go.mod index 06fdbe40d4e..8fc085975ac 100644 --- a/contrib/config/consul/go.mod +++ b/contrib/config/consul/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/config/consul/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/gogf/gf/v2 v2.8.3 @@ -17,6 +19,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect @@ -32,10 +35,10 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect diff --git a/contrib/config/consul/go.sum b/contrib/config/consul/go.sum index 65a46cfbeee..ad79d6148b6 100644 --- a/contrib/config/consul/go.sum +++ b/contrib/config/consul/go.sum @@ -23,6 +23,7 @@ github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -48,10 +49,14 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= @@ -59,8 +64,10 @@ github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWI github.com/hashicorp/consul/api v1.24.0 h1:u2XyStA2j0jnCiVUU7Qyrt8idjRn4ORhK6DlvZ3bWhA= github.com/hashicorp/consul/api v1.24.0/go.mod h1:NZJGRFYruc/80wYowkPFCp1LbGmJC9L8izrwfyVx/Wg= github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= +github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= @@ -71,19 +78,24 @@ github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJ github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= @@ -98,11 +110,13 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -146,8 +160,10 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -164,6 +180,8 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -172,20 +190,22 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= @@ -241,8 +261,9 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/contrib/config/kubecm/go.mod b/contrib/config/kubecm/go.mod index 262b1bf7ebc..c4c93b0a5e5 100644 --- a/contrib/config/kubecm/go.mod +++ b/contrib/config/kubecm/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/config/kubecm/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/gogf/gf/v2 v2.8.3 @@ -27,7 +29,7 @@ require ( github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.1.0 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect github.com/imdario/mergo v0.3.6 // indirect @@ -44,10 +46,10 @@ require ( github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/spf13/pflag v1.0.5 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect golang.org/x/sys v0.28.0 // indirect diff --git a/contrib/config/kubecm/go.sum b/contrib/config/kubecm/go.sum index 42d6e64aa1b..2d10f9e126a 100644 --- a/contrib/config/kubecm/go.sum +++ b/contrib/config/kubecm/go.sum @@ -76,6 +76,7 @@ github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -133,9 +134,10 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= @@ -158,7 +160,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -185,7 +188,9 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= +github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -193,7 +198,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= @@ -206,7 +212,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -216,14 +223,14 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -396,6 +403,7 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/contrib/config/nacos/go.mod b/contrib/config/nacos/go.mod index 1af537fd71b..21cfc50618a 100644 --- a/contrib/config/nacos/go.mod +++ b/contrib/config/nacos/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/config/nacos/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/gogf/gf/v2 v2.8.3 @@ -26,6 +28,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect @@ -45,10 +48,10 @@ require ( github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.21.0 // indirect diff --git a/contrib/config/nacos/go.sum b/contrib/config/nacos/go.sum index f2af4b1f192..04293714cfb 100644 --- a/contrib/config/nacos/go.sum +++ b/contrib/config/nacos/go.sum @@ -152,6 +152,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -163,6 +164,8 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= @@ -191,6 +194,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -218,7 +223,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nacos-group/nacos-sdk-go/v2 v2.2.5 h1:r0wwT7PayEjvEHzWXwr1ROi/JSqzujM4w+1L5ikThzQ= github.com/nacos-group/nacos-sdk-go/v2 v2.2.5/go.mod h1:OObBon0prVJVPoIbSZxpEkFiBfL0d1LcBtuAMiNn+8c= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= @@ -256,6 +260,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -266,7 +272,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= @@ -280,14 +287,14 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= @@ -585,8 +592,9 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= diff --git a/contrib/config/polaris/go.mod b/contrib/config/polaris/go.mod index b5ab5eab0ac..29b2bba97df 100644 --- a/contrib/config/polaris/go.mod +++ b/contrib/config/polaris/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/config/polaris/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/gogf/gf/v2 v2.8.3 @@ -19,7 +21,7 @@ require ( github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/uuid v1.3.1 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect @@ -41,10 +43,10 @@ require ( github.com/prometheus/procfs v0.7.3 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.21.0 // indirect diff --git a/contrib/config/polaris/go.sum b/contrib/config/polaris/go.sum index 703e7792333..e5a9f0216c8 100644 --- a/contrib/config/polaris/go.sum +++ b/contrib/config/polaris/go.sum @@ -302,6 +302,7 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -324,8 +325,8 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLe github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -368,8 +369,9 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -436,6 +438,8 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -459,7 +463,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -473,14 +478,14 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= diff --git a/contrib/drivers/clickhouse/go.mod b/contrib/drivers/clickhouse/go.mod index c5b0f724fd0..06b84525680 100644 --- a/contrib/drivers/clickhouse/go.mod +++ b/contrib/drivers/clickhouse/go.mod @@ -1,11 +1,13 @@ module github.com/gogf/gf/contrib/drivers/clickhouse/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/ClickHouse/clickhouse-go/v2 v2.0.15 github.com/gogf/gf/v2 v2.8.3 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.6.0 github.com/shopspring/decimal v1.3.1 ) @@ -19,6 +21,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -27,10 +30,10 @@ require ( github.com/paulmach/orb v0.7.1 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/contrib/drivers/clickhouse/go.sum b/contrib/drivers/clickhouse/go.sum index f6ef4d1c4ac..dc4fbd1c516 100644 --- a/contrib/drivers/clickhouse/go.sum +++ b/contrib/drivers/clickhouse/go.sum @@ -6,8 +6,10 @@ github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwj github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -30,8 +32,10 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= @@ -41,6 +45,10 @@ github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWI github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= @@ -67,6 +75,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= @@ -77,22 +87,23 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -132,8 +143,9 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/contrib/drivers/dm/go.mod b/contrib/drivers/dm/go.mod index ececa192f79..5182d9399af 100644 --- a/contrib/drivers/dm/go.mod +++ b/contrib/drivers/dm/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/drivers/dm/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 replace github.com/gogf/gf/v2 => ../../../ @@ -18,18 +20,20 @@ require ( github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/snappy v0.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/contrib/drivers/dm/go.sum b/contrib/drivers/dm/go.sum index 1b0ff9aff02..78ab2888972 100644 --- a/contrib/drivers/dm/go.sum +++ b/contrib/drivers/dm/go.sum @@ -4,7 +4,9 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -19,10 +21,17 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -36,18 +45,22 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -58,7 +71,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/contrib/drivers/mssql/go.mod b/contrib/drivers/mssql/go.mod index aff47d8fde9..80b7e8a0bbb 100644 --- a/contrib/drivers/mssql/go.mod +++ b/contrib/drivers/mssql/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/drivers/mssql/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/gogf/gf/v2 v2.8.3 @@ -17,18 +19,20 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect golang.org/x/crypto v0.30.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect diff --git a/contrib/drivers/mssql/go.sum b/contrib/drivers/mssql/go.sum index 5c588f2f825..c385394c417 100644 --- a/contrib/drivers/mssql/go.sum +++ b/contrib/drivers/mssql/go.sum @@ -1,14 +1,22 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -21,17 +29,25 @@ github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -47,19 +63,24 @@ github.com/microsoft/go-mssqldb v1.7.1/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpth github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= @@ -70,7 +91,8 @@ golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/contrib/drivers/mysql/go.mod b/contrib/drivers/mysql/go.mod index 13255823883..39f0c0f60d4 100644 --- a/contrib/drivers/mysql/go.mod +++ b/contrib/drivers/mysql/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/drivers/mysql/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/go-sql-driver/mysql v1.7.1 @@ -15,18 +17,20 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/contrib/drivers/mysql/go.sum b/contrib/drivers/mysql/go.sum index 3857f838de7..43343e25471 100644 --- a/contrib/drivers/mysql/go.sum +++ b/contrib/drivers/mysql/go.sum @@ -2,7 +2,9 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -17,10 +19,17 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -34,18 +43,22 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -54,7 +67,8 @@ golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/contrib/drivers/mysql/mysql_z_unit_feature_hook_test.go b/contrib/drivers/mysql/mysql_z_unit_feature_hook_test.go index 1330c158c25..4c97ab83c50 100644 --- a/contrib/drivers/mysql/mysql_z_unit_feature_hook_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_feature_hook_test.go @@ -7,130 +7,129 @@ package mysql_test import ( - "context" - "database/sql" - "fmt" - "testing" + "context" + "database/sql" + "fmt" + "testing" - "github.com/gogf/gf/v2/container/gvar" - "github.com/gogf/gf/v2/database/gdb" - "github.com/gogf/gf/v2/frame/g" - "github.com/gogf/gf/v2/test/gtest" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/test/gtest" ) func Test_Model_Hook_Select(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - m := db.Model(table).Hook(gdb.HookHandler{ - Select: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) { - result, err = in.Next(ctx) - if err != nil { - return - } - for i, record := range result { - record["test"] = gvar.New(100 + record["id"].Int()) - result[i] = record - } - return - }, - }) - all, err := m.Where(`id > 6`).OrderAsc(`id`).All() - t.AssertNil(err) - t.Assert(len(all), 4) - t.Assert(all[0]["id"].Int(), 7) - t.Assert(all[0]["test"].Int(), 107) - t.Assert(all[1]["test"].Int(), 108) - t.Assert(all[2]["test"].Int(), 109) - t.Assert(all[3]["test"].Int(), 110) - }) + gtest.C(t, func(t *gtest.T) { + m := db.Model(table).Hook(gdb.HookHandler{ + Select: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) { + result, err = in.Next(ctx) + if err != nil { + return + } + for i, record := range result { + record["test"] = gdb.NewValue(100 + record["id"].Int()) + result[i] = record + } + return + }, + }) + all, err := m.Where(`id > 6`).OrderAsc(`id`).All() + t.AssertNil(err) + t.Assert(len(all), 4) + t.Assert(all[0]["id"].Int(), 7) + t.Assert(all[0]["test"].Int(), 107) + t.Assert(all[1]["test"].Int(), 108) + t.Assert(all[2]["test"].Int(), 109) + t.Assert(all[3]["test"].Int(), 110) + }) } func Test_Model_Hook_Insert(t *testing.T) { - table := createTable() - defer dropTable(table) + table := createTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - m := db.Model(table).Hook(gdb.HookHandler{ - Insert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) { - for i, item := range in.Data { - item["passport"] = fmt.Sprintf(`test_port_%d`, item["id"]) - item["nickname"] = fmt.Sprintf(`test_name_%d`, item["id"]) - in.Data[i] = item - } - return in.Next(ctx) - }, - }) - _, err := m.Insert(g.Map{ - "id": 1, - "nickname": "name_1", - }) - t.AssertNil(err) - one, err := m.One() - t.AssertNil(err) - t.Assert(one["id"].Int(), 1) - t.Assert(one["passport"], `test_port_1`) - t.Assert(one["nickname"], `test_name_1`) - }) + gtest.C(t, func(t *gtest.T) { + m := db.Model(table).Hook(gdb.HookHandler{ + Insert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) { + for i, item := range in.Data { + item["passport"] = fmt.Sprintf(`test_port_%d`, item["id"]) + item["nickname"] = fmt.Sprintf(`test_name_%d`, item["id"]) + in.Data[i] = item + } + return in.Next(ctx) + }, + }) + _, err := m.Insert(g.Map{ + "id": 1, + "nickname": "name_1", + }) + t.AssertNil(err) + one, err := m.One() + t.AssertNil(err) + t.Assert(one["id"].Int(), 1) + t.Assert(one["passport"], `test_port_1`) + t.Assert(one["nickname"], `test_name_1`) + }) } func Test_Model_Hook_Update(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - m := db.Model(table).Hook(gdb.HookHandler{ - Update: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) { - switch value := in.Data.(type) { - case gdb.List: - for i, data := range value { - data["passport"] = `port` - data["nickname"] = `name` - value[i] = data - } - in.Data = value + gtest.C(t, func(t *gtest.T) { + m := db.Model(table).Hook(gdb.HookHandler{ + Update: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) { + switch value := in.Data.(type) { + case gdb.List: + for i, data := range value { + data["passport"] = `port` + data["nickname"] = `name` + value[i] = data + } + in.Data = value - case gdb.Map: - value["passport"] = `port` - value["nickname"] = `name` - in.Data = value - } - return in.Next(ctx) - }, - }) - _, err := m.Data(g.Map{ - "nickname": "name_1", - }).WherePri(1).Update() - t.AssertNil(err) + case gdb.Map: + value["passport"] = `port` + value["nickname"] = `name` + in.Data = value + } + return in.Next(ctx) + }, + }) + _, err := m.Data(g.Map{ + "nickname": "name_1", + }).WherePri(1).Update() + t.AssertNil(err) - one, err := m.One() - t.AssertNil(err) - t.Assert(one["id"].Int(), 1) - t.Assert(one["passport"], `port`) - t.Assert(one["nickname"], `name`) - }) + one, err := m.One() + t.AssertNil(err) + t.Assert(one["id"].Int(), 1) + t.Assert(one["passport"], `port`) + t.Assert(one["nickname"], `name`) + }) } func Test_Model_Hook_Delete(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - m := db.Model(table).Hook(gdb.HookHandler{ - Delete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) { - return db.Model(table).Data(g.Map{ - "nickname": `deleted`, - }).Where(in.Condition).Update() - }, - }) - _, err := m.Where(1).Delete() - t.AssertNil(err) + gtest.C(t, func(t *gtest.T) { + m := db.Model(table).Hook(gdb.HookHandler{ + Delete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) { + return db.Model(table).Data(g.Map{ + "nickname": `deleted`, + }).Where(in.Condition).Update() + }, + }) + _, err := m.Where(1).Delete() + t.AssertNil(err) - all, err := m.All() - t.AssertNil(err) - for _, item := range all { - t.Assert(item["nickname"].String(), `deleted`) - } - }) + all, err := m.All() + t.AssertNil(err) + for _, item := range all { + t.Assert(item["nickname"].String(), `deleted`) + } + }) } diff --git a/contrib/drivers/mysql/mysql_z_unit_feature_model_struct_test.go b/contrib/drivers/mysql/mysql_z_unit_feature_model_struct_test.go index 7d9902c799b..edf594d9674 100644 --- a/contrib/drivers/mysql/mysql_z_unit_feature_model_struct_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_feature_model_struct_test.go @@ -7,591 +7,476 @@ package mysql_test import ( - "database/sql" - "reflect" - "testing" - - "github.com/gogf/gf/v2/database/gdb" - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/frame/g" - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/test/gtest" - "github.com/gogf/gf/v2/text/gstr" - "github.com/gogf/gf/v2/util/gconv" + "database/sql" + "reflect" + "testing" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/test/gtest" + "github.com/gogf/gf/v2/util/gconv" ) func Test_Model_Embedded_Insert(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type Base struct { - Id int `json:"id"` - Uid int `json:"uid"` - CreateTime string `json:"create_time"` - } - type User struct { - Base - Passport string `json:"passport"` - Password string `json:"password"` - Nickname string `json:"nickname"` - } - result, err := db.Model(table).Data(User{ - Passport: "john-test", - Password: "123456", - Nickname: "John", - Base: Base{ - Id: 100, - Uid: 100, - CreateTime: gtime.Now().String(), - }, - }).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - value, err := db.Model(table).Fields("passport").Where("id=100").Value() - t.AssertNil(err) - t.Assert(value.String(), "john-test") - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type Base struct { + Id int `json:"id"` + Uid int `json:"uid"` + CreateTime string `json:"create_time"` + } + type User struct { + Base + Passport string `json:"passport"` + Password string `json:"password"` + Nickname string `json:"nickname"` + } + result, err := db.Model(table).Data(User{ + Passport: "john-test", + Password: "123456", + Nickname: "John", + Base: Base{ + Id: 100, + Uid: 100, + CreateTime: gtime.Now().String(), + }, + }).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + value, err := db.Model(table).Fields("passport").Where("id=100").Value() + t.AssertNil(err) + t.Assert(value.String(), "john-test") + }) } func Test_Model_Embedded_MapToStruct(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type Ids struct { - Id int `json:"id"` - Uid int `json:"uid"` - } - type Base struct { - Ids - CreateTime string `json:"create_time"` - } - type User struct { - Base - Passport string `json:"passport"` - Password string `json:"password"` - Nickname string `json:"nickname"` - } - data := g.Map{ - "id": 100, - "uid": 101, - "passport": "t1", - "password": "123456", - "nickname": "T1", - "create_time": gtime.Now().String(), - } - result, err := db.Model(table).Data(data).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - - one, err := db.Model(table).Where("id=100").One() - t.AssertNil(err) - - user := new(User) - - t.Assert(one.Struct(user), nil) - t.Assert(user.Id, data["id"]) - t.Assert(user.Passport, data["passport"]) - t.Assert(user.Password, data["password"]) - t.Assert(user.Nickname, data["nickname"]) - t.Assert(user.CreateTime, data["create_time"]) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type Ids struct { + Id int `json:"id"` + Uid int `json:"uid"` + } + type Base struct { + Ids + CreateTime string `json:"create_time"` + } + type User struct { + Base + Passport string `json:"passport"` + Password string `json:"password"` + Nickname string `json:"nickname"` + } + data := g.Map{ + "id": 100, + "uid": 101, + "passport": "t1", + "password": "123456", + "nickname": "T1", + "create_time": gtime.Now().String(), + } + result, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + + one, err := db.Model(table).Where("id=100").One() + t.AssertNil(err) + + user := new(User) + + t.Assert(one.Struct(user), nil) + t.Assert(user.Id, data["id"]) + t.Assert(user.Passport, data["passport"]) + t.Assert(user.Password, data["password"]) + t.Assert(user.Nickname, data["nickname"]) + t.Assert(user.CreateTime, data["create_time"]) + }) } func Test_Struct_Pointer_Attribute(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - type User struct { - Id *int - Passport *string - Password *string - Nickname string - } - - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - user := new(User) - err = one.Struct(user) - t.AssertNil(err) - t.Assert(*user.Id, 1) - t.Assert(*user.Passport, "user_1") - t.Assert(*user.Password, "pass_1") - t.Assert(user.Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - user := new(User) - err := db.Model(table).Scan(user, "id=1") - t.AssertNil(err) - t.Assert(*user.Id, 1) - t.Assert(*user.Passport, "user_1") - t.Assert(*user.Password, "pass_1") - t.Assert(user.Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - var user *User - err := db.Model(table).Scan(&user, "id=1") - t.AssertNil(err) - t.Assert(*user.Id, 1) - t.Assert(*user.Passport, "user_1") - t.Assert(*user.Password, "pass_1") - t.Assert(user.Nickname, "name_1") - }) + table := createInitTable() + defer dropTable(table) + + type User struct { + Id *int + Passport *string + Password *string + Nickname string + } + + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + user := new(User) + err = one.Struct(user) + t.AssertNil(err) + t.Assert(*user.Id, 1) + t.Assert(*user.Passport, "user_1") + t.Assert(*user.Password, "pass_1") + t.Assert(user.Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + user := new(User) + err := db.Model(table).Scan(user, "id=1") + t.AssertNil(err) + t.Assert(*user.Id, 1) + t.Assert(*user.Passport, "user_1") + t.Assert(*user.Password, "pass_1") + t.Assert(user.Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + var user *User + err := db.Model(table).Scan(&user, "id=1") + t.AssertNil(err) + t.Assert(*user.Id, 1) + t.Assert(*user.Passport, "user_1") + t.Assert(*user.Password, "pass_1") + t.Assert(user.Nickname, "name_1") + }) } func Test_Structs_Pointer_Attribute(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - type User struct { - Id *int - Passport *string - Password *string - Nickname string - } - // All - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).All("id < 3") - t.AssertNil(err) - users := make([]User, 0) - err = one.Structs(&users) - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).All("id < 3") - t.AssertNil(err) - users := make([]*User, 0) - err = one.Structs(&users) - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - var users []User - one, err := db.Model(table).All("id < 3") - t.AssertNil(err) - err = one.Structs(&users) - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - var users []*User - one, err := db.Model(table).All("id < 3") - t.AssertNil(err) - err = one.Structs(&users) - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) - // Structs - gtest.C(t, func(t *gtest.T) { - users := make([]User, 0) - err := db.Model(table).Scan(&users, "id < 3") - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - users := make([]*User, 0) - err := db.Model(table).Scan(&users, "id < 3") - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - var users []User - err := db.Model(table).Scan(&users, "id < 3") - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - var users []*User - err := db.Model(table).Scan(&users, "id < 3") - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) + table := createInitTable() + defer dropTable(table) + + type User struct { + Id *int + Passport *string + Password *string + Nickname string + } + // All + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).All("id < 3") + t.AssertNil(err) + users := make([]User, 0) + err = one.Structs(&users) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).All("id < 3") + t.AssertNil(err) + users := make([]*User, 0) + err = one.Structs(&users) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + var users []User + one, err := db.Model(table).All("id < 3") + t.AssertNil(err) + err = one.Structs(&users) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + var users []*User + one, err := db.Model(table).All("id < 3") + t.AssertNil(err) + err = one.Structs(&users) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) + // Structs + gtest.C(t, func(t *gtest.T) { + users := make([]User, 0) + err := db.Model(table).Scan(&users, "id < 3") + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + users := make([]*User, 0) + err := db.Model(table).Scan(&users, "id < 3") + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + var users []User + err := db.Model(table).Scan(&users, "id < 3") + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + var users []*User + err := db.Model(table).Scan(&users, "id < 3") + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) } func Test_Struct_Empty(t *testing.T) { - table := createTable() - defer dropTable(table) - - type User struct { - Id int - Passport string - Password string - Nickname string - } - - gtest.C(t, func(t *gtest.T) { - user := new(User) - err := db.Model(table).Where("id=100").Scan(user) - t.Assert(err, sql.ErrNoRows) - t.AssertNE(user, nil) - }) - - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Where("id=100").One() - t.AssertNil(err) - var user *User - t.Assert(one.Struct(&user), nil) - t.Assert(user, nil) - }) - - gtest.C(t, func(t *gtest.T) { - var user *User - err := db.Model(table).Where("id=100").Scan(&user) - t.AssertNil(err) - t.Assert(user, nil) - }) + table := createTable() + defer dropTable(table) + + type User struct { + Id int + Passport string + Password string + Nickname string + } + + gtest.C(t, func(t *gtest.T) { + user := new(User) + err := db.Model(table).Where("id=100").Scan(user) + t.Assert(err, sql.ErrNoRows) + t.AssertNE(user, nil) + }) + + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Where("id=100").One() + t.AssertNil(err) + var user *User + t.Assert(one.Struct(&user), nil) + t.Assert(user, nil) + }) + + gtest.C(t, func(t *gtest.T) { + var user *User + err := db.Model(table).Where("id=100").Scan(&user) + t.AssertNil(err) + t.Assert(user, nil) + }) } func Test_Structs_Empty(t *testing.T) { - table := createTable() - defer dropTable(table) - - type User struct { - Id int - Passport string - Password string - Nickname string - } - - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id>100").All() - t.AssertNil(err) - users := make([]User, 0) - t.Assert(all.Structs(&users), nil) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id>100").All() - t.AssertNil(err) - users := make([]User, 10) - t.Assert(all.Structs(&users), sql.ErrNoRows) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id>100").All() - t.AssertNil(err) - var users []User - t.Assert(all.Structs(&users), nil) - }) - - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id>100").All() - t.AssertNil(err) - users := make([]*User, 0) - t.Assert(all.Structs(&users), nil) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id>100").All() - t.AssertNil(err) - users := make([]*User, 10) - t.Assert(all.Structs(&users), sql.ErrNoRows) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id>100").All() - t.AssertNil(err) - var users []*User - t.Assert(all.Structs(&users), nil) - }) + table := createTable() + defer dropTable(table) + + type User struct { + Id int + Passport string + Password string + Nickname string + } + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id>100").All() + t.AssertNil(err) + users := make([]User, 0) + t.Assert(all.Structs(&users), nil) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id>100").All() + t.AssertNil(err) + users := make([]User, 10) + t.Assert(all.Structs(&users), sql.ErrNoRows) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id>100").All() + t.AssertNil(err) + var users []User + t.Assert(all.Structs(&users), nil) + }) + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id>100").All() + t.AssertNil(err) + users := make([]*User, 0) + t.Assert(all.Structs(&users), nil) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id>100").All() + t.AssertNil(err) + users := make([]*User, 10) + t.Assert(all.Structs(&users), sql.ErrNoRows) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id>100").All() + t.AssertNil(err) + var users []*User + t.Assert(all.Structs(&users), nil) + }) } type MyTime struct { - gtime.Time + gtime.Time } type MyTimeSt struct { - CreateTime MyTime + CreateTime MyTime } func (st *MyTimeSt) UnmarshalValue(v interface{}) error { - m := gconv.Map(v) - t, err := gtime.StrToTime(gconv.String(m["create_time"])) - if err != nil { - return err - } - st.CreateTime = MyTime{*t} - return nil + m := gconv.Map(v) + t, err := gtime.StrToTime(gconv.String(m["create_time"])) + if err != nil { + return err + } + st.CreateTime = MyTime{*t} + return nil } func Test_Model_Scan_CustomType_Time(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - st := new(MyTimeSt) - err := db.Model(table).Fields("create_time").Scan(st) - t.AssertNil(err) - t.Assert(st.CreateTime.String(), "2018-10-24 10:00:00") - }) - gtest.C(t, func(t *gtest.T) { - var stSlice []*MyTimeSt - err := db.Model(table).Fields("create_time").Scan(&stSlice) - t.AssertNil(err) - t.Assert(len(stSlice), TableSize) - t.Assert(stSlice[0].CreateTime.String(), "2018-10-24 10:00:00") - t.Assert(stSlice[9].CreateTime.String(), "2018-10-24 10:00:00") - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + st := new(MyTimeSt) + err := db.Model(table).Fields("create_time").Scan(st) + t.AssertNil(err) + t.Assert(st.CreateTime.String(), "2018-10-24 10:00:00") + }) + gtest.C(t, func(t *gtest.T) { + var stSlice []*MyTimeSt + err := db.Model(table).Fields("create_time").Scan(&stSlice) + t.AssertNil(err) + t.Assert(len(stSlice), TableSize) + t.Assert(stSlice[0].CreateTime.String(), "2018-10-24 10:00:00") + t.Assert(stSlice[9].CreateTime.String(), "2018-10-24 10:00:00") + }) } func Test_Model_Scan_CustomType_String(t *testing.T) { - type MyString string - - type MyStringSt struct { - Passport MyString - } - - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - st := new(MyStringSt) - err := db.Model(table).Fields("Passport").WherePri(1).Scan(st) - t.AssertNil(err) - t.Assert(st.Passport, "user_1") - }) - gtest.C(t, func(t *gtest.T) { - var sts []MyStringSt - err := db.Model(table).Fields("Passport").Order("id asc").Scan(&sts) - t.AssertNil(err) - t.Assert(len(sts), TableSize) - t.Assert(sts[0].Passport, "user_1") - }) + type MyString string + + type MyStringSt struct { + Passport MyString + } + + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + st := new(MyStringSt) + err := db.Model(table).Fields("Passport").WherePri(1).Scan(st) + t.AssertNil(err) + t.Assert(st.Passport, "user_1") + }) + gtest.C(t, func(t *gtest.T) { + var sts []MyStringSt + err := db.Model(table).Fields("Passport").Order("id asc").Scan(&sts) + t.AssertNil(err) + t.Assert(len(sts), TableSize) + t.Assert(sts[0].Passport, "user_1") + }) } type User struct { - Id int - Passport string - Password string - Nickname string - CreateTime *gtime.Time + Id int + Passport string + Password string + Nickname string + CreateTime *gtime.Time } func (user *User) UnmarshalValue(value interface{}) error { - if record, ok := value.(gdb.Record); ok { - *user = User{ - Id: record["id"].Int(), - Passport: record["passport"].String(), - Password: "", - Nickname: record["nickname"].String(), - CreateTime: record["create_time"].GTime(), - } - return nil - } - return gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported value type for UnmarshalValue: %v`, reflect.TypeOf(value)) + if record, ok := value.(gdb.Record); ok { + *user = User{ + Id: record["id"].Int(), + Passport: record["passport"].String(), + Password: "", + Nickname: record["nickname"].String(), + CreateTime: record["create_time"].GTime(), + } + return nil + } + return gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported value type for UnmarshalValue: %v`, reflect.TypeOf(value)) } func Test_Model_Scan_UnmarshalValue(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - var users []*User - err := db.Model(table).Order("id asc").Scan(&users) - t.AssertNil(err) - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - t.Assert(users[0].Passport, "user_1") - t.Assert(users[0].Password, "") - t.Assert(users[0].Nickname, "name_1") - t.Assert(users[0].CreateTime.String(), CreateTime) - - t.Assert(users[9].Id, 10) - t.Assert(users[9].Passport, "user_10") - t.Assert(users[9].Password, "") - t.Assert(users[9].Nickname, "name_10") - t.Assert(users[9].CreateTime.String(), CreateTime) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + var users []*User + err := db.Model(table).Order("id asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[0].Passport, "user_1") + t.Assert(users[0].Password, "") + t.Assert(users[0].Nickname, "name_1") + t.Assert(users[0].CreateTime.String(), CreateTime) + + t.Assert(users[9].Id, 10) + t.Assert(users[9].Passport, "user_10") + t.Assert(users[9].Password, "") + t.Assert(users[9].Nickname, "name_10") + t.Assert(users[9].CreateTime.String(), CreateTime) + }) } func Test_Model_Scan_Map(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - var users []*User - err := db.Model(table).Order("id asc").Scan(&users) - t.AssertNil(err) - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - t.Assert(users[0].Passport, "user_1") - t.Assert(users[0].Password, "") - t.Assert(users[0].Nickname, "name_1") - t.Assert(users[0].CreateTime.String(), CreateTime) - - t.Assert(users[9].Id, 10) - t.Assert(users[9].Passport, "user_10") - t.Assert(users[9].Password, "") - t.Assert(users[9].Nickname, "name_10") - t.Assert(users[9].CreateTime.String(), CreateTime) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + var users []*User + err := db.Model(table).Order("id asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[0].Passport, "user_1") + t.Assert(users[0].Password, "") + t.Assert(users[0].Nickname, "name_1") + t.Assert(users[0].CreateTime.String(), CreateTime) + + t.Assert(users[9].Id, 10) + t.Assert(users[9].Passport, "user_10") + t.Assert(users[9].Password, "") + t.Assert(users[9].Nickname, "name_10") + t.Assert(users[9].CreateTime.String(), CreateTime) + }) } func Test_Scan_AutoFilteringByStructAttributes(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - type User struct { - Id int - Passport string - } - // db.SetDebug(true) - gtest.C(t, func(t *gtest.T) { - var user *User - err := db.Model(table).OrderAsc("id").Scan(&user) - t.AssertNil(err) - t.Assert(user.Id, 1) - }) - gtest.C(t, func(t *gtest.T) { - var users []User - err := db.Model(table).OrderAsc("id").Scan(&users) - t.AssertNil(err) - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - }) -} - -func Test_Scan_JsonAttributes(t *testing.T) { - type GiftImage struct { - Uid string `json:"uid"` - Url string `json:"url"` - Status string `json:"status"` - Name string `json:"name"` - } - - type GiftComment struct { - Name string `json:"name"` - Field string `json:"field"` - Required bool `json:"required"` - } - - type Prop struct { - Name string `json:"name"` - Values []string `json:"values"` - } - - type Sku struct { - GiftId int64 `json:"gift_id"` - Name string `json:"name"` - ScorePrice int `json:"score_price"` - MarketPrice int `json:"market_price"` - CostPrice int `json:"cost_price"` - Stock int `json:"stock"` - } - - type Covers struct { - List []GiftImage `json:"list"` - } - - type GiftEntity struct { - Id int64 `json:"id"` - StoreId int64 `json:"store_id"` - GiftType int `json:"gift_type"` - GiftName string `json:"gift_name"` - Description string `json:"description"` - Covers Covers `json:"covers"` - Cover string `json:"cover"` - GiftCategoryId []int64 `json:"gift_category_id"` - HasProps bool `json:"has_props"` - OutSn string `json:"out_sn"` - IsLimitSell bool `json:"is_limit_sell"` - LimitSellType int `json:"limit_sell_type"` - LimitSellCycle string `json:"limit_sell_cycle"` - LimitSellCycleCount int `json:"limit_sell_cycle_count"` - LimitSellCustom bool `json:"limit_sell_custom"` // 只允许特定会员兑换 - LimitCustomerTags []int64 `json:"limit_customer_tags"` // 允许兑换的成员 - ScorePrice int `json:"score_price"` - MarketPrice float64 `json:"market_price"` - CostPrice int `json:"cost_price"` - Stock int `json:"stock"` - Props []Prop `json:"props"` - Skus []Sku `json:"skus"` - ExpressType []string `json:"express_type"` - Comments []GiftComment `json:"comments"` - Content string `json:"content"` - AtLeastRechargeCount int `json:"at_least_recharge_count"` - Status int `json:"status"` - } - - type User struct { - Id int - Passport string - } - - table := "jfy_gift" - array := gstr.SplitAndTrim(gtest.DataContent(`issue1380.sql`), ";") - for _, v := range array { - if _, err := db.Exec(ctx, v); err != nil { - gtest.Error(err) - } - } - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - var ( - entity = new(GiftEntity) - err = db.Model(table).Where("id", 17).Scan(entity) - ) - t.AssertNil(err) - t.Assert(len(entity.Skus), 2) - - t.Assert(entity.Skus[0].Name, "red") - t.Assert(entity.Skus[0].Stock, 10) - t.Assert(entity.Skus[0].GiftId, 1) - t.Assert(entity.Skus[0].CostPrice, 80) - t.Assert(entity.Skus[0].ScorePrice, 188) - t.Assert(entity.Skus[0].MarketPrice, 388) - - t.Assert(entity.Skus[1].Name, "blue") - t.Assert(entity.Skus[1].Stock, 100) - t.Assert(entity.Skus[1].GiftId, 2) - t.Assert(entity.Skus[1].CostPrice, 81) - t.Assert(entity.Skus[1].ScorePrice, 200) - t.Assert(entity.Skus[1].MarketPrice, 288) - - t.Assert(entity.Id, 17) - t.Assert(entity.StoreId, 100004) - t.Assert(entity.GiftType, 1) - t.Assert(entity.GiftName, "GIFT") - t.Assert(entity.Description, "支持个性定制的父亲节老师长辈的专属礼物") - t.Assert(len(entity.Covers.List), 3) - t.Assert(entity.OutSn, "259402") - t.Assert(entity.LimitCustomerTags, "[]") - t.Assert(entity.ScorePrice, 10) - t.Assert(len(entity.Props), 1) - t.Assert(len(entity.Comments), 2) - t.Assert(entity.Status, 99) - t.Assert(entity.Content, `

礼品详情

`) - }) + table := createInitTable() + defer dropTable(table) + + type User struct { + Id int + Passport string + } + // db.SetDebug(true) + gtest.C(t, func(t *gtest.T) { + var user *User + err := db.Model(table).OrderAsc("id").Scan(&user) + t.AssertNil(err) + t.Assert(user.Id, 1) + }) + gtest.C(t, func(t *gtest.T) { + var users []User + err := db.Model(table).OrderAsc("id").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + }) } diff --git a/contrib/drivers/mysql/mysql_z_unit_issue_test.go b/contrib/drivers/mysql/mysql_z_unit_issue_test.go index af4e43b29e1..2b909c85f28 100644 --- a/contrib/drivers/mysql/mysql_z_unit_issue_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_issue_test.go @@ -7,65 +7,180 @@ package mysql_test import ( - "context" - "fmt" - "sync" - "testing" - "time" - - "github.com/gogf/gf/v2/container/gvar" - "github.com/gogf/gf/v2/database/gdb" - "github.com/gogf/gf/v2/frame/g" - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/test/gtest" - "github.com/gogf/gf/v2/text/gregex" - "github.com/gogf/gf/v2/text/gstr" - "github.com/gogf/gf/v2/util/gmeta" - "github.com/gogf/gf/v2/util/guid" + "context" + "encoding/json" + "fmt" + "sync" + "testing" + "time" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/test/gtest" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gmeta" + "github.com/gogf/gf/v2/util/guid" ) +// https://github.com/gogf/gf/issues/1380 +func Test_Issue1380(t *testing.T) { + type GiftImage struct { + Uid string `json:"uid"` + Url string `json:"url"` + Status string `json:"status"` + Name string `json:"name"` + } + + type GiftComment struct { + Name string `json:"name"` + Field string `json:"field"` + Required bool `json:"required"` + } + + type Prop struct { + Name string `json:"name"` + Values []string `json:"values"` + } + + type Sku struct { + GiftId int64 `json:"gift_id"` + Name string `json:"name"` + ScorePrice int `json:"score_price"` + MarketPrice int `json:"market_price"` + CostPrice int `json:"cost_price"` + Stock int `json:"stock"` + } + + type Covers struct { + List []GiftImage `json:"list"` + } + + type GiftEntity struct { + Id int64 `json:"id"` + StoreId int64 `json:"store_id"` + GiftType int `json:"gift_type"` + GiftName string `json:"gift_name"` + Description string `json:"description"` + Covers Covers `json:"covers"` + Cover string `json:"cover"` + GiftCategoryId []int64 `json:"gift_category_id"` + HasProps bool `json:"has_props"` + OutSn string `json:"out_sn"` + IsLimitSell bool `json:"is_limit_sell"` + LimitSellType int `json:"limit_sell_type"` + LimitSellCycle string `json:"limit_sell_cycle"` + LimitSellCycleCount int `json:"limit_sell_cycle_count"` + LimitSellCustom bool `json:"limit_sell_custom"` // 只允许特定会员兑换 + LimitCustomerTags []int64 `json:"limit_customer_tags"` // 允许兑换的成员 + ScorePrice int `json:"score_price"` + MarketPrice float64 `json:"market_price"` + CostPrice int `json:"cost_price"` + Stock int `json:"stock"` + Props []Prop `json:"props"` + Skus []Sku `json:"skus"` + ExpressType []string `json:"express_type"` + Comments []GiftComment `json:"comments"` + Content string `json:"content"` + AtLeastRechargeCount int `json:"at_least_recharge_count"` + Status int `json:"status"` + } + + type User struct { + Id int + Passport string + } + + table := "jfy_gift" + array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `1380.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + var ( + entity = new(GiftEntity) + err = db.Model(table).Where("id", 17).Scan(entity) + ) + t.AssertNil(err) + t.Assert(len(entity.Skus), 2) + + t.Assert(entity.Skus[0].Name, "red") + t.Assert(entity.Skus[0].Stock, 10) + t.Assert(entity.Skus[0].GiftId, 1) + t.Assert(entity.Skus[0].CostPrice, 80) + t.Assert(entity.Skus[0].ScorePrice, 188) + t.Assert(entity.Skus[0].MarketPrice, 388) + + t.Assert(entity.Skus[1].Name, "blue") + t.Assert(entity.Skus[1].Stock, 100) + t.Assert(entity.Skus[1].GiftId, 2) + t.Assert(entity.Skus[1].CostPrice, 81) + t.Assert(entity.Skus[1].ScorePrice, 200) + t.Assert(entity.Skus[1].MarketPrice, 288) + + t.Assert(entity.Id, 17) + t.Assert(entity.StoreId, 100004) + t.Assert(entity.GiftType, 1) + t.Assert(entity.GiftName, "GIFT") + t.Assert(entity.Description, "支持个性定制的父亲节老师长辈的专属礼物") + t.Assert(len(entity.Covers.List), 3) + t.Assert(entity.OutSn, "259402") + t.Assert(entity.LimitCustomerTags, "[]") + t.Assert(entity.ScorePrice, 10) + t.Assert(len(entity.Props), 1) + t.Assert(len(entity.Comments), 2) + t.Assert(entity.Status, 99) + t.Assert(entity.Content, `

礼品详情

`) + }) +} + // https://github.com/gogf/gf/issues/1934 func Test_Issue1934(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Where(" id ", 1).One() - t.AssertNil(err) - t.Assert(one["id"], 1) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Where(" id ", 1).One() + t.AssertNil(err) + t.Assert(one["id"], 1) + }) } // https://github.com/gogf/gf/issues/1570 func Test_Issue1570(t *testing.T) { - var ( - tableUser = "user_" + gtime.TimestampMicroStr() - tableUserDetail = "user_detail_" + gtime.TimestampMicroStr() - tableUserScores = "user_scores_" + gtime.TimestampMicroStr() - ) - if _, err := db.Exec(ctx, fmt.Sprintf(` + var ( + tableUser = "user_" + gtime.TimestampMicroStr() + tableUserDetail = "user_detail_" + gtime.TimestampMicroStr() + tableUserScores = "user_scores_" + gtime.TimestampMicroStr() + ) + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE %s ( uid int(10) unsigned NOT NULL AUTO_INCREMENT, name varchar(45) NOT NULL, PRIMARY KEY (uid) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; `, tableUser)); err != nil { - gtest.Error(err) - } - defer dropTable(tableUser) + gtest.Error(err) + } + defer dropTable(tableUser) - if _, err := db.Exec(ctx, fmt.Sprintf(` + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE %s ( uid int(10) unsigned NOT NULL AUTO_INCREMENT, address varchar(45) NOT NULL, PRIMARY KEY (uid) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; `, tableUserDetail)); err != nil { - gtest.Error(err) - } - defer dropTable(tableUserDetail) + gtest.Error(err) + } + defer dropTable(tableUserDetail) - if _, err := db.Exec(ctx, fmt.Sprintf(` + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE %s ( id int(10) unsigned NOT NULL AUTO_INCREMENT, uid int(10) unsigned NOT NULL, @@ -73,279 +188,279 @@ CREATE TABLE %s ( PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; `, tableUserScores)); err != nil { - gtest.Error(err) - } - defer dropTable(tableUserScores) - - type EntityUser struct { - Uid int `json:"uid"` - Name string `json:"name"` - } - type EntityUserDetail struct { - Uid int `json:"uid"` - Address string `json:"address"` - } - type EntityUserScores struct { - Id int `json:"id"` - Uid int `json:"uid"` - Score int `json:"score"` - } - type Entity struct { - User *EntityUser - UserDetail *EntityUserDetail - UserScores []*EntityUserScores - } - - // Initialize the data. - gtest.C(t, func(t *gtest.T) { - var err error - for i := 1; i <= 5; i++ { - // User. - _, err = db.Insert(ctx, tableUser, g.Map{ - "uid": i, - "name": fmt.Sprintf(`name_%d`, i), - }) - t.AssertNil(err) - // Detail. - _, err = db.Insert(ctx, tableUserDetail, g.Map{ - "uid": i, - "address": fmt.Sprintf(`address_%d`, i), - }) - t.AssertNil(err) - // Scores. - for j := 1; j <= 5; j++ { - _, err = db.Insert(ctx, tableUserScores, g.Map{ - "uid": i, - "score": j, - }) - t.AssertNil(err) - } - } - }) - - // Result ScanList with struct elements and pointer attributes. - gtest.C(t, func(t *gtest.T) { - var users []Entity - // User - err := db.Model(tableUser). - Where("uid", g.Slice{3, 4}). - Fields("uid"). - Order("uid asc"). - ScanList(&users, "User") - t.AssertNil(err) - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(users[0].User, &EntityUser{3, ""}) - t.Assert(users[1].User, &EntityUser{4, ""}) - // Detail - err = db.Model(tableUserDetail). - Where("uid", gdb.ListItemValues(users, "User", "Uid")). - Order("uid asc"). - ScanList(&users, "UserDetail", "User", "uid:Uid") - t.AssertNil(err) - t.AssertNil(err) - t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"}) - t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"}) - // Scores - err = db.Model(tableUserScores). - Where("uid", gdb.ListItemValues(users, "User", "Uid")). - Order("id asc"). - ScanList(&users, "UserScores", "User", "uid:Uid") - t.AssertNil(err) - t.AssertNil(err) - t.Assert(len(users[0].UserScores), 5) - t.Assert(len(users[1].UserScores), 5) - t.Assert(users[0].UserScores[0].Uid, 3) - t.Assert(users[0].UserScores[0].Score, 1) - t.Assert(users[0].UserScores[4].Score, 5) - t.Assert(users[1].UserScores[0].Uid, 4) - t.Assert(users[1].UserScores[0].Score, 1) - t.Assert(users[1].UserScores[4].Score, 5) - }) + gtest.Error(err) + } + defer dropTable(tableUserScores) + + type EntityUser struct { + Uid int `json:"uid"` + Name string `json:"name"` + } + type EntityUserDetail struct { + Uid int `json:"uid"` + Address string `json:"address"` + } + type EntityUserScores struct { + Id int `json:"id"` + Uid int `json:"uid"` + Score int `json:"score"` + } + type Entity struct { + User *EntityUser + UserDetail *EntityUserDetail + UserScores []*EntityUserScores + } + + // Initialize the data. + gtest.C(t, func(t *gtest.T) { + var err error + for i := 1; i <= 5; i++ { + // User. + _, err = db.Insert(ctx, tableUser, g.Map{ + "uid": i, + "name": fmt.Sprintf(`name_%d`, i), + }) + t.AssertNil(err) + // Detail. + _, err = db.Insert(ctx, tableUserDetail, g.Map{ + "uid": i, + "address": fmt.Sprintf(`address_%d`, i), + }) + t.AssertNil(err) + // Scores. + for j := 1; j <= 5; j++ { + _, err = db.Insert(ctx, tableUserScores, g.Map{ + "uid": i, + "score": j, + }) + t.AssertNil(err) + } + } + }) + + // Result ScanList with struct elements and pointer attributes. + gtest.C(t, func(t *gtest.T) { + var users []Entity + // User + err := db.Model(tableUser). + Where("uid", g.Slice{3, 4}). + Fields("uid"). + Order("uid asc"). + ScanList(&users, "User") + t.AssertNil(err) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(users[0].User, &EntityUser{3, ""}) + t.Assert(users[1].User, &EntityUser{4, ""}) + // Detail + err = db.Model(tableUserDetail). + Where("uid", gdb.ListItemValues(users, "User", "Uid")). + Order("uid asc"). + ScanList(&users, "UserDetail", "User", "uid:Uid") + t.AssertNil(err) + t.AssertNil(err) + t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"}) + t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"}) + // Scores + err = db.Model(tableUserScores). + Where("uid", gdb.ListItemValues(users, "User", "Uid")). + Order("id asc"). + ScanList(&users, "UserScores", "User", "uid:Uid") + t.AssertNil(err) + t.AssertNil(err) + t.Assert(len(users[0].UserScores), 5) + t.Assert(len(users[1].UserScores), 5) + t.Assert(users[0].UserScores[0].Uid, 3) + t.Assert(users[0].UserScores[0].Score, 1) + t.Assert(users[0].UserScores[4].Score, 5) + t.Assert(users[1].UserScores[0].Uid, 4) + t.Assert(users[1].UserScores[0].Score, 1) + t.Assert(users[1].UserScores[4].Score, 5) + }) } // https://github.com/gogf/gf/issues/1401 func Test_Issue1401(t *testing.T) { - var ( - table1 = "parcels" - table2 = "parcel_items" - ) - array := gstr.SplitAndTrim(gtest.DataContent(`issue1401.sql`), ";") - for _, v := range array { - if _, err := db.Exec(ctx, v); err != nil { - gtest.Error(err) - } - } - defer dropTable(table1) - defer dropTable(table2) - - gtest.C(t, func(t *gtest.T) { - type NItem struct { - Id int `json:"id"` - ParcelId int `json:"parcel_id"` - } - - type ParcelItem struct { - gmeta.Meta `orm:"table:parcel_items"` - NItem - } - - type ParcelRsp struct { - gmeta.Meta `orm:"table:parcels"` - Id int `json:"id"` - Items []*ParcelItem `json:"items" orm:"with:parcel_id=Id"` - } - - parcelDetail := &ParcelRsp{} - err := db.Model(table1).With(parcelDetail.Items).Where("id", 3).Scan(&parcelDetail) - t.AssertNil(err) - t.Assert(parcelDetail.Id, 3) - t.Assert(len(parcelDetail.Items), 1) - t.Assert(parcelDetail.Items[0].Id, 2) - t.Assert(parcelDetail.Items[0].ParcelId, 3) - }) + var ( + table1 = "parcels" + table2 = "parcel_items" + ) + array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `1401.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable(table1) + defer dropTable(table2) + + gtest.C(t, func(t *gtest.T) { + type NItem struct { + Id int `json:"id"` + ParcelId int `json:"parcel_id"` + } + + type ParcelItem struct { + gmeta.Meta `orm:"table:parcel_items"` + NItem + } + + type ParcelRsp struct { + gmeta.Meta `orm:"table:parcels"` + Id int `json:"id"` + Items []*ParcelItem `json:"items" orm:"with:parcel_id=Id"` + } + + parcelDetail := &ParcelRsp{} + err := db.Model(table1).With(parcelDetail.Items).Where("id", 3).Scan(&parcelDetail) + t.AssertNil(err) + t.Assert(parcelDetail.Id, 3) + t.Assert(len(parcelDetail.Items), 1) + t.Assert(parcelDetail.Items[0].Id, 2) + t.Assert(parcelDetail.Items[0].ParcelId, 3) + }) } // https://github.com/gogf/gf/issues/1412 func Test_Issue1412(t *testing.T) { - var ( - table1 = "parcels" - table2 = "items" - ) - array := gstr.SplitAndTrim(gtest.DataContent(`issue1412.sql`), ";") - for _, v := range array { - if _, err := db.Exec(ctx, v); err != nil { - gtest.Error(err) - } - } - defer dropTable(table1) - defer dropTable(table2) - - gtest.C(t, func(t *gtest.T) { - type Items struct { - gmeta.Meta `orm:"table:items"` - Id int `json:"id"` - Name string `json:"name"` - } - - type ParcelRsp struct { - gmeta.Meta `orm:"table:parcels"` - Id int `json:"id"` - ItemId int `json:"item_id"` - Items Items `json:"items" orm:"with:Id=ItemId"` - } - - entity := &ParcelRsp{} - err := db.Model("parcels").With(Items{}).Where("id=3").Scan(&entity) - t.AssertNil(err) - t.Assert(entity.Id, 3) - t.Assert(entity.ItemId, 0) - t.Assert(entity.Items.Id, 0) - t.Assert(entity.Items.Name, "") - }) - - gtest.C(t, func(t *gtest.T) { - type Items struct { - gmeta.Meta `orm:"table:items"` - Id int `json:"id"` - Name string `json:"name"` - } - - type ParcelRsp struct { - gmeta.Meta `orm:"table:parcels"` - Id int `json:"id"` - ItemId int `json:"item_id"` - Items Items `json:"items" orm:"with:Id=ItemId"` - } - - entity := &ParcelRsp{} - err := db.Model("parcels").With(Items{}).Where("id=30000").Scan(&entity) - t.AssertNE(err, nil) - t.Assert(entity.Id, 0) - t.Assert(entity.ItemId, 0) - t.Assert(entity.Items.Id, 0) - t.Assert(entity.Items.Name, "") - }) + var ( + table1 = "parcels" + table2 = "items" + ) + array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `1412.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable(table1) + defer dropTable(table2) + + gtest.C(t, func(t *gtest.T) { + type Items struct { + gmeta.Meta `orm:"table:items"` + Id int `json:"id"` + Name string `json:"name"` + } + + type ParcelRsp struct { + gmeta.Meta `orm:"table:parcels"` + Id int `json:"id"` + ItemId int `json:"item_id"` + Items Items `json:"items" orm:"with:Id=ItemId"` + } + + entity := &ParcelRsp{} + err := db.Model("parcels").With(Items{}).Where("id=3").Scan(&entity) + t.AssertNil(err) + t.Assert(entity.Id, 3) + t.Assert(entity.ItemId, 0) + t.Assert(entity.Items.Id, 0) + t.Assert(entity.Items.Name, "") + }) + + gtest.C(t, func(t *gtest.T) { + type Items struct { + gmeta.Meta `orm:"table:items"` + Id int `json:"id"` + Name string `json:"name"` + } + + type ParcelRsp struct { + gmeta.Meta `orm:"table:parcels"` + Id int `json:"id"` + ItemId int `json:"item_id"` + Items Items `json:"items" orm:"with:Id=ItemId"` + } + + entity := &ParcelRsp{} + err := db.Model("parcels").With(Items{}).Where("id=30000").Scan(&entity) + t.AssertNE(err, nil) + t.Assert(entity.Id, 0) + t.Assert(entity.ItemId, 0) + t.Assert(entity.Items.Id, 0) + t.Assert(entity.Items.Name, "") + }) } // https://github.com/gogf/gf/issues/1002 func Test_Issue1002(t *testing.T) { - table := createTable() - defer dropTable(table) - - result, err := db.Model(table).Data(g.Map{ - "id": 1, - "passport": "port_1", - "password": "pass_1", - "nickname": "name_2", - "create_time": "2020-10-27 19:03:33", - }).Insert() - gtest.AssertNil(err) - n, _ := result.RowsAffected() - gtest.Assert(n, 1) - - // where + string. - gtest.C(t, func(t *gtest.T) { - v, err := db.Model(table).Fields("id").Where("create_time>'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'").Value() - t.AssertNil(err) - t.Assert(v.Int(), 1) - }) - gtest.C(t, func(t *gtest.T) { - v, err := db.Model(table).Fields("id").Where("create_time>'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'").Value() - t.AssertNil(err) - t.Assert(v.Int(), 1) - }) - // where + string arguments. - gtest.C(t, func(t *gtest.T) { - v, err := db.Model(table).Fields("id").Where("create_time>? and create_time? and create_time? and create_time? and create_time? and create_time? and create_time'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'").Value() + t.AssertNil(err) + t.Assert(v.Int(), 1) + }) + gtest.C(t, func(t *gtest.T) { + v, err := db.Model(table).Fields("id").Where("create_time>'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'").Value() + t.AssertNil(err) + t.Assert(v.Int(), 1) + }) + // where + string arguments. + gtest.C(t, func(t *gtest.T) { + v, err := db.Model(table).Fields("id").Where("create_time>? and create_time? and create_time? and create_time? and create_time? and create_time? and create_time b").All() - t.AssertNil(err) - t.Assert(len(all), 1) - t.Assert(all[0]["id"], 2) - - all, err = db.Model(table).Where(gdb.Raw("a > b")).All() - t.AssertNil(err) - t.Assert(len(all), 1) - t.Assert(all[0]["id"], 2) - - all, err = db.Model(table).WhereGT("a", gdb.Raw("`b`")).All() - t.AssertNil(err) - t.Assert(len(all), 1) - t.Assert(all[0]["id"], 2) - }) + table := "issue3915" + array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `3915.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + //db.SetDebug(true) + all, err := db.Model(table).Where("a < b").All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(all[0]["id"], 1) + + all, err = db.Model(table).Where(gdb.Raw("a < b")).All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(all[0]["id"], 1) + + all, err = db.Model(table).WhereLT("a", gdb.Raw("`b`")).All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(all[0]["id"], 1) + }) + + gtest.C(t, func(t *gtest.T) { + //db.SetDebug(true) + all, err := db.Model(table).Where("a > b").All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(all[0]["id"], 2) + + all, err = db.Model(table).Where(gdb.Raw("a > b")).All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(all[0]["id"], 2) + + all, err = db.Model(table).WhereGT("a", gdb.Raw("`b`")).All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(all[0]["id"], 2) + }) } type RoleBase struct { - gmeta.Meta `orm:"table:sys_role"` - Name string `json:"name" description:"角色名称" ` - Code string `json:"code" description:"角色 code" ` - Description string `json:"description" description:"描述信息" ` - Weight int `json:"weight" description:"排序" ` - StatusId int `json:"statusId" description:"发布状态" ` - CreatedAt *gtime.Time `json:"createdAt" description:"" ` - UpdatedAt *gtime.Time `json:"updatedAt" description:"" ` + gmeta.Meta `orm:"table:sys_role"` + Name string `json:"name" description:"角色名称" ` + Code string `json:"code" description:"角色 code" ` + Description string `json:"description" description:"描述信息" ` + Weight int `json:"weight" description:"排序" ` + StatusId int `json:"statusId" description:"发布状态" ` + CreatedAt *gtime.Time `json:"createdAt" description:"" ` + UpdatedAt *gtime.Time `json:"updatedAt" description:"" ` } type Role struct { - gmeta.Meta `orm:"table:sys_role"` - RoleBase - Id uint `json:"id" description:""` - Status *Status `json:"status" description:"发布状态" orm:"with:id=status_id" ` + gmeta.Meta `orm:"table:sys_role"` + RoleBase + Id uint `json:"id" description:""` + Status *Status `json:"status" description:"发布状态" orm:"with:id=status_id" ` } type StatusBase struct { - gmeta.Meta `orm:"table:sys_status"` - En string `json:"en" description:"英文名称" ` - Cn string `json:"cn" description:"中文名称" ` - Weight int `json:"weight" description:"排序权重" ` + gmeta.Meta `orm:"table:sys_status"` + En string `json:"en" description:"英文名称" ` + Cn string `json:"cn" description:"中文名称" ` + Weight int `json:"weight" description:"排序权重" ` } type Status struct { - gmeta.Meta `orm:"table:sys_status"` - StatusBase - Id uint `json:"id" description:""` + gmeta.Meta `orm:"table:sys_status"` + StatusBase + Id uint `json:"id" description:""` } // https://github.com/gogf/gf/issues/2119 func Test_Issue2119(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - tables := []string{ - "sys_role", - "sys_status", - } - - defer dropTable(tables[0]) - defer dropTable(tables[1]) - _ = tables - array := gstr.SplitAndTrim(gtest.DataContent(`issue2119.sql`), ";") - for _, v := range array { - _, err := db.Exec(ctx, v) - t.AssertNil(err) - } - roles := make([]*Role, 0) - err := db.Ctx(context.Background()).Model(&Role{}).WithAll().Scan(&roles) - t.AssertNil(err) - expectStatus := []*Status{ - { - StatusBase: StatusBase{ - En: "undecided", - Cn: "未决定", - Weight: 800, - }, - Id: 2, - }, - { - StatusBase: StatusBase{ - En: "on line", - Cn: "上线", - Weight: 900, - }, - Id: 1, - }, - { - StatusBase: StatusBase{ - En: "on line", - Cn: "上线", - Weight: 900, - }, - Id: 1, - }, - { - StatusBase: StatusBase{ - En: "on line", - Cn: "上线", - Weight: 900, - }, - Id: 1, - }, - { - StatusBase: StatusBase{ - En: "on line", - Cn: "上线", - Weight: 900, - }, - Id: 1, - }, - } - - for i := 0; i < len(roles); i++ { - t.Assert(roles[i].Status, expectStatus[i]) - } - }) + gtest.C(t, func(t *gtest.T) { + tables := []string{ + "sys_role", + "sys_status", + } + + defer dropTable(tables[0]) + defer dropTable(tables[1]) + _ = tables + array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `2119.sql`), ";") + for _, v := range array { + _, err := db.Exec(ctx, v) + t.AssertNil(err) + } + roles := make([]*Role, 0) + err := db.Ctx(context.Background()).Model(&Role{}).WithAll().Scan(&roles) + t.AssertNil(err) + expectStatus := []*Status{ + { + StatusBase: StatusBase{ + En: "undecided", + Cn: "未决定", + Weight: 800, + }, + Id: 2, + }, + { + StatusBase: StatusBase{ + En: "on line", + Cn: "上线", + Weight: 900, + }, + Id: 1, + }, + { + StatusBase: StatusBase{ + En: "on line", + Cn: "上线", + Weight: 900, + }, + Id: 1, + }, + { + StatusBase: StatusBase{ + En: "on line", + Cn: "上线", + Weight: 900, + }, + Id: 1, + }, + { + StatusBase: StatusBase{ + En: "on line", + Cn: "上线", + Weight: 900, + }, + Id: 1, + }, + } + + for i := 0; i < len(roles); i++ { + t.Assert(roles[i].Status, expectStatus[i]) + } + }) } // https://github.com/gogf/gf/issues/4034 func Test_Issue4034(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - table := "issue4034" - array := gstr.SplitAndTrim(gtest.DataContent(`issue4034.sql`), ";") - for _, v := range array { - _, err := db.Exec(ctx, v) - t.AssertNil(err) - } - defer dropTable(table) - - err := issue4034SaveDeviceAndToken(ctx, table) - t.AssertNil(err) - }) + gtest.C(t, func(t *gtest.T) { + table := "issue4034" + array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `4034.sql`), ";") + for _, v := range array { + _, err := db.Exec(ctx, v) + t.AssertNil(err) + } + defer dropTable(table) + + err := issue4034SaveDeviceAndToken(ctx, table) + t.AssertNil(err) + }) } func issue4034SaveDeviceAndToken(ctx context.Context, table string) error { - return db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { - if err := issue4034SaveAppDevice(ctx, table, tx); err != nil { - return err - } - return nil - }) + return db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { + if err := issue4034SaveAppDevice(ctx, table, tx); err != nil { + return err + } + return nil + }) } func issue4034SaveAppDevice(ctx context.Context, table string, tx gdb.TX) error { - _, err := db.Model(table).Safe().Ctx(ctx).TX(tx).Data(g.Map{ - "passport": "111", - "password": "222", - "nickname": "333", - }).Save() - return err + _, err := db.Model(table).Safe().Ctx(ctx).TX(tx).Data(g.Map{ + "passport": "111", + "password": "222", + "nickname": "333", + }).Save() + return err +} + +// https://github.com/gogf/gf/issues/4086 +func Test_Issue4086(t *testing.T) { + table := "issue4086" + defer dropTable(table) + array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `4086.sql`), ";") + for _, v := range array { + _, err := db.Exec(ctx, v) + gtest.AssertNil(err) + } + + gtest.C(t, func(t *gtest.T) { + type ProxyParam struct { + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` + Photos []string `json:"photos" orm:"photos"` + } + + var proxyParamList []*ProxyParam + err := db.Model(table).Ctx(ctx).Scan(&proxyParamList) + t.AssertNil(err) + t.Assert(len(proxyParamList), 2) + t.Assert(proxyParamList, []*ProxyParam{ + { + ProxyId: 1, + RecommendIds: []int64{584, 585}, + Photos: nil, + }, + { + ProxyId: 2, + RecommendIds: []int64{}, + Photos: nil, + }, + }) + }) + gtest.C(t, func(t *gtest.T) { + type ProxyParam struct { + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` + Photos []any `json:"photos" orm:"photos"` + } + + var proxyParamList []*ProxyParam + err := db.Model(table).Ctx(ctx).Scan(&proxyParamList) + t.AssertNil(err) + t.Assert(len(proxyParamList), 2) + t.Assert(proxyParamList, []*ProxyParam{ + { + ProxyId: 1, + RecommendIds: []int64{584, 585}, + Photos: nil, + }, + { + ProxyId: 2, + RecommendIds: []int64{}, + Photos: nil, + }, + }) + }) + gtest.C(t, func(t *gtest.T) { + type ProxyParam struct { + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` + Photos string `json:"photos" orm:"photos"` + } + + var proxyParamList []*ProxyParam + err := db.Model(table).Ctx(ctx).Scan(&proxyParamList) + t.AssertNil(err) + t.Assert(len(proxyParamList), 2) + t.Assert(proxyParamList, []*ProxyParam{ + { + ProxyId: 1, + RecommendIds: []int64{584, 585}, + Photos: "null", + }, + { + ProxyId: 2, + RecommendIds: []int64{}, + Photos: "", + }, + }) + }) + gtest.C(t, func(t *gtest.T) { + type ProxyParam struct { + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds string `json:"recommendIds" orm:"recommend_ids"` + Photos json.RawMessage `json:"photos" orm:"photos"` + } + + var proxyParamList []*ProxyParam + err := db.Model(table).Ctx(ctx).Scan(&proxyParamList) + t.AssertNil(err) + t.Assert(len(proxyParamList), 2) + t.Assert(proxyParamList, []*ProxyParam{ + { + ProxyId: 1, + RecommendIds: "[584, 585]", + Photos: json.RawMessage("null"), + }, + { + ProxyId: 2, + RecommendIds: "[]", + Photos: json.RawMessage("null"), + }, + }) + }) } diff --git a/contrib/drivers/mysql/mysql_z_unit_model_test.go b/contrib/drivers/mysql/mysql_z_unit_model_test.go index 9be10ff1313..9ae609d735c 100644 --- a/contrib/drivers/mysql/mysql_z_unit_model_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_model_test.go @@ -7,585 +7,584 @@ package mysql_test import ( - "bytes" - "context" - "database/sql" - "fmt" - "os" - "strings" - "testing" - "time" - - "github.com/gogf/gf/v2/container/garray" - "github.com/gogf/gf/v2/container/gvar" - "github.com/gogf/gf/v2/database/gdb" - "github.com/gogf/gf/v2/encoding/gjson" - "github.com/gogf/gf/v2/frame/g" - "github.com/gogf/gf/v2/os/gfile" - "github.com/gogf/gf/v2/os/glog" - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/test/gtest" - "github.com/gogf/gf/v2/text/gstr" - "github.com/gogf/gf/v2/util/guid" + "bytes" + "context" + "database/sql" + "fmt" + "os" + "strings" + "testing" + "time" + + "github.com/gogf/gf/v2/container/garray" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gfile" + "github.com/gogf/gf/v2/os/glog" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/test/gtest" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/guid" ) func Test_Model_Insert(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - user := db.Model(table) - result, err := user.Data(g.Map{ - "id": 1, - "uid": 1, - "passport": "t1", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "name_1", - "create_time": gtime.Now().String(), - }).Insert() - t.AssertNil(err) - n, _ := result.LastInsertId() - t.Assert(n, 1) - - result, err = db.Model(table).Data(g.Map{ - "id": "2", - "uid": "2", - "passport": "t2", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "name_2", - "create_time": gtime.Now().String(), - }).Insert() - t.AssertNil(err) - n, _ = result.RowsAffected() - t.Assert(n, 1) - - type User struct { - Id int `gconv:"id"` - Uid int `gconv:"uid"` - Passport string `json:"passport"` - Password string `gconv:"password"` - Nickname string `gconv:"nickname"` - CreateTime *gtime.Time `json:"create_time"` - } - // Model inserting. - result, err = db.Model(table).Data(User{ - Id: 3, - Uid: 3, - Passport: "t3", - Password: "25d55ad283aa400af464c76d713c07ad", - Nickname: "name_3", - }).Insert() - t.AssertNil(err) - n, _ = result.RowsAffected() - t.Assert(n, 1) - value, err := db.Model(table).Fields("passport").Where("id=3").Value() - t.AssertNil(err) - t.Assert(value.String(), "t3") - - result, err = db.Model(table).Data(&User{ - Id: 4, - Uid: 4, - Passport: "t4", - Password: "25d55ad283aa400af464c76d713c07ad", - Nickname: "T4", - CreateTime: gtime.Now(), - }).Insert() - t.AssertNil(err) - n, _ = result.RowsAffected() - t.Assert(n, 1) - value, err = db.Model(table).Fields("passport").Where("id=4").Value() - t.AssertNil(err) - t.Assert(value.String(), "t4") - - result, err = db.Model(table).Where("id>?", 1).Delete() - t.AssertNil(err) - n, _ = result.RowsAffected() - t.Assert(n, 3) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + user := db.Model(table) + result, err := user.Data(g.Map{ + "id": 1, + "uid": 1, + "passport": "t1", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_1", + "create_time": gtime.Now().String(), + }).Insert() + t.AssertNil(err) + n, _ := result.LastInsertId() + t.Assert(n, 1) + + result, err = db.Model(table).Data(g.Map{ + "id": "2", + "uid": "2", + "passport": "t2", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_2", + "create_time": gtime.Now().String(), + }).Insert() + t.AssertNil(err) + n, _ = result.RowsAffected() + t.Assert(n, 1) + + type User struct { + Id int `gconv:"id"` + Uid int `gconv:"uid"` + Passport string `json:"passport"` + Password string `gconv:"password"` + Nickname string `gconv:"nickname"` + CreateTime *gtime.Time `json:"create_time"` + } + // Model inserting. + result, err = db.Model(table).Data(User{ + Id: 3, + Uid: 3, + Passport: "t3", + Password: "25d55ad283aa400af464c76d713c07ad", + Nickname: "name_3", + }).Insert() + t.AssertNil(err) + n, _ = result.RowsAffected() + t.Assert(n, 1) + value, err := db.Model(table).Fields("passport").Where("id=3").Value() + t.AssertNil(err) + t.Assert(value.String(), "t3") + + result, err = db.Model(table).Data(&User{ + Id: 4, + Uid: 4, + Passport: "t4", + Password: "25d55ad283aa400af464c76d713c07ad", + Nickname: "T4", + CreateTime: gtime.Now(), + }).Insert() + t.AssertNil(err) + n, _ = result.RowsAffected() + t.Assert(n, 1) + value, err = db.Model(table).Fields("passport").Where("id=4").Value() + t.AssertNil(err) + t.Assert(value.String(), "t4") + + result, err = db.Model(table).Where("id>?", 1).Delete() + t.AssertNil(err) + n, _ = result.RowsAffected() + t.Assert(n, 3) + }) } // Fix issue: https://github.com/gogf/gf/issues/819 func Test_Model_Insert_WithStructAndSliceAttribute(t *testing.T) { - table := createTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - type Password struct { - Salt string `json:"salt"` - Pass string `json:"pass"` - } - data := g.Map{ - "id": 1, - "passport": "t1", - "password": &Password{"123", "456"}, - "nickname": []string{"A", "B", "C"}, - "create_time": gtime.Now().String(), - } - _, err := db.Model(table).Data(data).Insert() - t.AssertNil(err) - - one, err := db.Model(table).One("id", 1) - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["create_time"], data["create_time"]) - t.Assert(one["nickname"], gjson.New(data["nickname"]).MustToJson()) - }) + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type Password struct { + Salt string `json:"salt"` + Pass string `json:"pass"` + } + data := g.Map{ + "id": 1, + "passport": "t1", + "password": &Password{"123", "456"}, + "nickname": []string{"A", "B", "C"}, + "create_time": gtime.Now().String(), + } + _, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + + one, err := db.Model(table).One("id", 1) + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["create_time"], data["create_time"]) + t.Assert(one["nickname"], gjson.New(data["nickname"]).MustToJson()) + }) } func Test_Model_Insert_KeyFieldNameMapping(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - Nickname string - CreateTime string - } - data := User{ - Id: 1, - Passport: "user_1", - Password: "pass_1", - Nickname: "name_1", - CreateTime: "2020-10-10 12:00:01", - } - _, err := db.Model(table).Data(data).Insert() - t.AssertNil(err) - - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data.Passport) - t.Assert(one["create_time"], data.CreateTime) - t.Assert(one["nickname"], data.Nickname) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + Nickname string + CreateTime string + } + data := User{ + Id: 1, + Passport: "user_1", + Password: "pass_1", + Nickname: "name_1", + CreateTime: "2020-10-10 12:00:01", + } + _, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data.Passport) + t.Assert(one["create_time"], data.CreateTime) + t.Assert(one["nickname"], data.Nickname) + }) } func Test_Model_Update_KeyFieldNameMapping(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - Nickname string - CreateTime string - } - data := User{ - Id: 1, - Passport: "user_10", - Password: "pass_10", - Nickname: "name_10", - CreateTime: "2020-10-10 12:00:01", - } - _, err := db.Model(table).Data(data).WherePri(1).Update() - t.AssertNil(err) - - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data.Passport) - t.Assert(one["create_time"], data.CreateTime) - t.Assert(one["nickname"], data.Nickname) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + Nickname string + CreateTime string + } + data := User{ + Id: 1, + Passport: "user_10", + Password: "pass_10", + Nickname: "name_10", + CreateTime: "2020-10-10 12:00:01", + } + _, err := db.Model(table).Data(data).WherePri(1).Update() + t.AssertNil(err) + + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data.Passport) + t.Assert(one["create_time"], data.CreateTime) + t.Assert(one["nickname"], data.Nickname) + }) } func Test_Model_Insert_Time(t *testing.T) { - table := createTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "t1", - "password": "p1", - "nickname": "n1", - "create_time": "2020-10-10 20:09:18.334", - } - _, err := db.Model(table).Data(data).Insert() - t.AssertNil(err) - - one, err := db.Model(table).One("id", 1) - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["create_time"], "2020-10-10 20:09:18") - t.Assert(one["nickname"], data["nickname"]) - }) + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "t1", + "password": "p1", + "nickname": "n1", + "create_time": "2020-10-10 20:09:18.334", + } + _, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + + one, err := db.Model(table).One("id", 1) + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["create_time"], "2020-10-10 20:09:18") + t.Assert(one["nickname"], data["nickname"]) + }) } func Test_Model_BatchInsertWithArrayStruct(t *testing.T) { - table := createTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - user := db.Model(table) - array := garray.New() - for i := 1; i <= TableSize; i++ { - array.Append(g.Map{ - "id": i, - "uid": i, - "passport": fmt.Sprintf("t%d", i), - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": fmt.Sprintf("name_%d", i), - "create_time": gtime.Now().String(), - }) - } - - result, err := user.Data(array).Insert() - t.AssertNil(err) - n, _ := result.LastInsertId() - t.Assert(n, TableSize) - }) + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + user := db.Model(table) + array := garray.New() + for i := 1; i <= TableSize; i++ { + array.Append(g.Map{ + "id": i, + "uid": i, + "passport": fmt.Sprintf("t%d", i), + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": fmt.Sprintf("name_%d", i), + "create_time": gtime.Now().String(), + }) + } + + result, err := user.Data(array).Insert() + t.AssertNil(err) + n, _ := result.LastInsertId() + t.Assert(n, TableSize) + }) } func Test_Model_InsertIgnore(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).Data(g.Map{ - "id": 1, - "uid": 1, - "passport": "t1", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "name_1", - "create_time": gtime.Now().String(), - }).Insert() - t.AssertNE(err, nil) - }) - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).Data(g.Map{ - "id": 1, - "uid": 1, - "passport": "t1", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "name_1", - "create_time": gtime.Now().String(), - }).InsertIgnore() - t.AssertNil(err) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).Data(g.Map{ + "id": 1, + "uid": 1, + "passport": "t1", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_1", + "create_time": gtime.Now().String(), + }).Insert() + t.AssertNE(err, nil) + }) + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).Data(g.Map{ + "id": 1, + "uid": 1, + "passport": "t1", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_1", + "create_time": gtime.Now().String(), + }).InsertIgnore() + t.AssertNil(err) + }) } func Test_Model_Batch(t *testing.T) { - // batch insert - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - result, err := db.Model(table).Data(g.List{ - { - "id": 2, - "uid": 2, - "passport": "t2", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "name_2", - "create_time": gtime.Now().String(), - }, - { - "id": 3, - "uid": 3, - "passport": "t3", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "name_3", - "create_time": gtime.Now().String(), - }, - }).Batch(1).Insert() - if err != nil { - gtest.Error(err) - } - n, _ := result.RowsAffected() - 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.Model(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() - defer dropTable(table) - result, err := db.Model(table).All() - t.AssertNil(err) - t.Assert(len(result), TableSize) - for _, v := range result { - v["nickname"].Set(v["nickname"].String() + v["id"].String()) - } - r, e := db.Model(table).Data(result).Save() - t.Assert(e, nil) - n, e := r.RowsAffected() - t.Assert(e, nil) - t.Assert(n, TableSize*2) - }) - - // batch replace - gtest.C(t, func(t *gtest.T) { - table := createInitTable() - defer dropTable(table) - result, err := db.Model(table).All() - t.AssertNil(err) - t.Assert(len(result), TableSize) - for _, v := range result { - v["nickname"].Set(v["nickname"].String() + v["id"].String()) - } - r, e := db.Model(table).Data(result).Replace() - t.Assert(e, nil) - n, e := r.RowsAffected() - t.Assert(e, nil) - t.Assert(n, TableSize*2) - }) + // batch insert + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + result, err := db.Model(table).Data(g.List{ + { + "id": 2, + "uid": 2, + "passport": "t2", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_2", + "create_time": gtime.Now().String(), + }, + { + "id": 3, + "uid": 3, + "passport": "t3", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_3", + "create_time": gtime.Now().String(), + }, + }).Batch(1).Insert() + if err != nil { + gtest.Error(err) + } + n, _ := result.RowsAffected() + 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.Model(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() + defer dropTable(table) + result, err := db.Model(table).All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + for _, v := range result { + v["nickname"].Set(v["nickname"].String() + v["id"].String()) + } + r, e := db.Model(table).Data(result).Save() + t.Assert(e, nil) + n, e := r.RowsAffected() + t.Assert(e, nil) + t.Assert(n, TableSize*2) + }) + + // batch replace + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + result, err := db.Model(table).All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + for _, v := range result { + v["nickname"].Set(v["nickname"].String() + v["id"].String()) + } + r, e := db.Model(table).Data(result).Replace() + t.Assert(e, nil) + n, e := r.RowsAffected() + t.Assert(e, nil) + t.Assert(n, TableSize*2) + }) } func Test_Model_Replace(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data(g.Map{ - "id": 1, - "passport": "t11", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "T11", - "create_time": "2018-10-24 10:00:00", - }).Replace() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data(g.Map{ + "id": 1, + "passport": "t11", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "T11", + "create_time": "2018-10-24 10:00:00", + }).Replace() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) } func Test_Model_Save(t *testing.T) { - table := createTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data(g.Map{ - "id": 1, - "passport": "t111", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "T111", - "create_time": "2018-10-24 10:00:00", - }).Save() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data(g.Map{ + "id": 1, + "passport": "t111", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "T111", + "create_time": "2018-10-24 10:00:00", + }).Save() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) } func Test_Model_Update(t *testing.T) { - table := createInitTable() - defer dropTable(table) - // UPDATE...LIMIT - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data("nickname", "T100").Where(1).Order("id desc").Limit(2).Update() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 2) - - v1, err := db.Model(table).Fields("nickname").Where("id", 10).Value() - t.AssertNil(err) - t.Assert(v1.String(), "T100") - - v2, err := db.Model(table).Fields("nickname").Where("id", 8).Value() - t.AssertNil(err) - t.Assert(v2.String(), "name_8") - }) - - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data("passport", "user_22").Where("passport=?", "user_2").Update() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data("passport", "user_2").Where("passport='user_22'").Update() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - - // Update + Data(string) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data("passport='user_33'").Where("passport='user_3'").Update() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - // Update + Fields(string) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Fields("passport").Data(g.Map{ - "passport": "user_44", - "none": "none", - }).Where("passport='user_4'").Update() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) + table := createInitTable() + defer dropTable(table) + // UPDATE...LIMIT + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data("nickname", "T100").Where(1).Order("id desc").Limit(2).Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 2) + + v1, err := db.Model(table).Fields("nickname").Where("id", 10).Value() + t.AssertNil(err) + t.Assert(v1.String(), "T100") + + v2, err := db.Model(table).Fields("nickname").Where("id", 8).Value() + t.AssertNil(err) + t.Assert(v2.String(), "name_8") + }) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data("passport", "user_22").Where("passport=?", "user_2").Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data("passport", "user_2").Where("passport='user_22'").Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + + // Update + Data(string) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data("passport='user_33'").Where("passport='user_3'").Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + // Update + Fields(string) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Fields("passport").Data(g.Map{ + "passport": "user_44", + "none": "none", + }).Where("passport='user_4'").Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) } func Test_Model_UpdateAndGetAffected(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - n, err := db.Model(table).Data("nickname", "T100"). - Where(1).Order("id desc").Limit(2). - UpdateAndGetAffected() - t.AssertNil(err) - t.Assert(n, 2) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + n, err := db.Model(table).Data("nickname", "T100"). + Where(1).Order("id desc").Limit(2). + UpdateAndGetAffected() + t.AssertNil(err) + t.Assert(n, 2) + }) } func Test_Model_Clone(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - md := db.Model(table).Safe(true).Where("id IN(?)", g.Slice{1, 3}) - count, err := md.Count() - t.AssertNil(err) + gtest.C(t, func(t *gtest.T) { + md := db.Model(table).Safe(true).Where("id IN(?)", g.Slice{1, 3}) + count, err := md.Count() + t.AssertNil(err) - record, err := md.Safe(true).Order("id DESC").One() - t.AssertNil(err) + record, err := md.Safe(true).Order("id DESC").One() + t.AssertNil(err) - result, err := md.Safe(true).Order("id ASC").All() - t.AssertNil(err) + result, err := md.Safe(true).Order("id ASC").All() + t.AssertNil(err) - t.Assert(count, int64(2)) - t.Assert(record["id"].Int(), 3) - t.Assert(len(result), 2) - t.Assert(result[0]["id"].Int(), 1) - t.Assert(result[1]["id"].Int(), 3) - }) + t.Assert(count, int64(2)) + t.Assert(record["id"].Int(), 3) + t.Assert(len(result), 2) + t.Assert(result[0]["id"].Int(), 1) + t.Assert(result[1]["id"].Int(), 3) + }) } func Test_Model_Safe(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - md := db.Model(table).Safe(false).Where("id IN(?)", g.Slice{1, 3}) - count, err := md.Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - - md.Where("id = ?", 1) - count, err = md.Count() - t.AssertNil(err) - t.Assert(count, int64(1)) - }) - gtest.C(t, func(t *gtest.T) { - md := db.Model(table).Safe(true).Where("id IN(?)", g.Slice{1, 3}) - count, err := md.Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - - md.Where("id = ?", 1) - count, err = md.Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - }) - - gtest.C(t, func(t *gtest.T) { - md := db.Model(table).Safe().Where("id IN(?)", g.Slice{1, 3}) - count, err := md.Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - - md.Where("id = ?", 1) - count, err = md.Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - }) - gtest.C(t, func(t *gtest.T) { - md1 := db.Model(table).Safe() - md2 := md1.Where("id in (?)", g.Slice{1, 3}) - count, err := md2.Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - - all, err := md2.All() - t.AssertNil(err) - t.Assert(len(all), 2) - - all, err = md2.Page(1, 10).All() - t.AssertNil(err) - t.Assert(len(all), 2) - }) - - gtest.C(t, func(t *gtest.T) { - table := createInitTable() - defer dropTable(table) - - md1 := db.Model(table).Where("id>", 0).Safe() - md2 := md1.Where("id in (?)", g.Slice{1, 3}) - md3 := md1.Where("id in (?)", g.Slice{4, 5, 6}) - - // 1,3 - count, err := md2.Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - - all, err := md2.Order("id asc").All() - t.AssertNil(err) - t.Assert(len(all), 2) - t.Assert(all[0]["id"].Int(), 1) - t.Assert(all[1]["id"].Int(), 3) - - all, err = md2.Page(1, 10).All() - t.AssertNil(err) - t.Assert(len(all), 2) - - // 4,5,6 - count, err = md3.Count() - t.AssertNil(err) - t.Assert(count, int64(3)) - - all, err = md3.Order("id asc").All() - t.AssertNil(err) - t.Assert(len(all), 3) - t.Assert(all[0]["id"].Int(), 4) - t.Assert(all[1]["id"].Int(), 5) - t.Assert(all[2]["id"].Int(), 6) - - all, err = md3.Page(1, 10).All() - t.AssertNil(err) - t.Assert(len(all), 3) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + md := db.Model(table).Safe(false).Where("id IN(?)", g.Slice{1, 3}) + count, err := md.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + + md.Where("id = ?", 1) + count, err = md.Count() + t.AssertNil(err) + t.Assert(count, int64(1)) + }) + gtest.C(t, func(t *gtest.T) { + md := db.Model(table).Safe(true).Where("id IN(?)", g.Slice{1, 3}) + count, err := md.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + + md.Where("id = ?", 1) + count, err = md.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + }) + + gtest.C(t, func(t *gtest.T) { + md := db.Model(table).Safe().Where("id IN(?)", g.Slice{1, 3}) + count, err := md.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + + md.Where("id = ?", 1) + count, err = md.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + }) + gtest.C(t, func(t *gtest.T) { + md1 := db.Model(table).Safe() + md2 := md1.Where("id in (?)", g.Slice{1, 3}) + count, err := md2.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + + all, err := md2.All() + t.AssertNil(err) + t.Assert(len(all), 2) + + all, err = md2.Page(1, 10).All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + + md1 := db.Model(table).Where("id>", 0).Safe() + md2 := md1.Where("id in (?)", g.Slice{1, 3}) + md3 := md1.Where("id in (?)", g.Slice{4, 5, 6}) + + // 1,3 + count, err := md2.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + + all, err := md2.Order("id asc").All() + t.AssertNil(err) + t.Assert(len(all), 2) + t.Assert(all[0]["id"].Int(), 1) + t.Assert(all[1]["id"].Int(), 3) + + all, err = md2.Page(1, 10).All() + t.AssertNil(err) + t.Assert(len(all), 2) + + // 4,5,6 + count, err = md3.Count() + t.AssertNil(err) + t.Assert(count, int64(3)) + + all, err = md3.Order("id asc").All() + t.AssertNil(err) + t.Assert(len(all), 3) + t.Assert(all[0]["id"].Int(), 4) + t.Assert(all[1]["id"].Int(), 5) + t.Assert(all[2]["id"].Int(), 6) + + all, err = md3.Page(1, 10).All() + t.AssertNil(err) + t.Assert(len(all), 3) + }) } func Test_Model_All(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).All() - t.AssertNil(err) - t.Assert(len(result), TableSize) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Where("id<0").All() - t.Assert(result, nil) - t.AssertNil(err) - }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("id<0").All() + t.Assert(result, nil) + t.AssertNil(err) + }) } func Test_Model_Fields(t *testing.T) { - tableName1 := createInitTable() - defer dropTable(tableName1) + tableName1 := createInitTable() + defer dropTable(tableName1) - tableName2 := "user_" + gtime.Now().TimestampNanoStr() - if _, err := db.Exec(ctx, fmt.Sprintf(` + tableName2 := "user_" + gtime.Now().TimestampNanoStr() + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE %s ( id int(10) unsigned NOT NULL AUTO_INCREMENT, name varchar(45) NULL, @@ -593,1921 +592,1924 @@ func Test_Model_Fields(t *testing.T) { PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; `, tableName2, - )); err != nil { - gtest.AssertNil(err) - } - defer dropTable(tableName2) - - r, err := db.Insert(ctx, tableName2, g.Map{ - "id": 1, - "name": "table2_1", - "age": 18, - }) - gtest.AssertNil(err) - n, _ := r.RowsAffected() - gtest.Assert(n, 1) - - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(tableName1).As("u").Fields("u.passport,u.id").Where("u.id<2").All() - t.AssertNil(err) - t.Assert(len(all), 1) - t.Assert(len(all[0]), 2) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(tableName1).As("u1"). - LeftJoin(tableName1, "u2", "u2.id=u1.id"). - Fields("u1.passport,u1.id,u2.id AS u2id"). - Where("u1.id<2"). - All() - t.AssertNil(err) - t.Assert(len(all), 1) - t.Assert(len(all[0]), 3) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(tableName1).As("u1"). - LeftJoin(tableName2, "u2", "u2.id=u1.id"). - Fields("u1.passport,u1.id,u2.name,u2.age"). - Where("u1.id<2"). - All() - t.AssertNil(err) - t.Assert(len(all), 1) - t.Assert(len(all[0]), 4) - t.Assert(all[0]["id"], 1) - t.Assert(all[0]["age"], 18) - t.Assert(all[0]["name"], "table2_1") - t.Assert(all[0]["passport"], "user_1") - }) + )); err != nil { + gtest.AssertNil(err) + } + defer dropTable(tableName2) + + r, err := db.Insert(ctx, tableName2, g.Map{ + "id": 1, + "name": "table2_1", + "age": 18, + }) + gtest.AssertNil(err) + n, _ := r.RowsAffected() + gtest.Assert(n, 1) + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(tableName1).As("u").Fields("u.passport,u.id").Where("u.id<2").All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(len(all[0]), 2) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(tableName1).As("u1"). + LeftJoin(tableName1, "u2", "u2.id=u1.id"). + Fields("u1.passport,u1.id,u2.id AS u2id"). + Where("u1.id<2"). + All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(len(all[0]), 3) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(tableName1).As("u1"). + LeftJoin(tableName2, "u2", "u2.id=u1.id"). + Fields("u1.passport,u1.id,u2.name,u2.age"). + Where("u1.id<2"). + All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(len(all[0]), 4) + t.Assert(all[0]["id"], 1) + t.Assert(all[0]["age"], 18) + t.Assert(all[0]["name"], "table2_1") + t.Assert(all[0]["passport"], "user_1") + }) } func Test_Model_One(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - record, err := db.Model(table).Where("id", 1).One() - t.AssertNil(err) - t.Assert(record["nickname"].String(), "name_1") - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + record, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.Assert(record["nickname"].String(), "name_1") + }) - gtest.C(t, func(t *gtest.T) { - record, err := db.Model(table).Where("id", 0).One() - t.AssertNil(err) - t.Assert(record, nil) - }) + gtest.C(t, func(t *gtest.T) { + record, err := db.Model(table).Where("id", 0).One() + t.AssertNil(err) + t.Assert(record, nil) + }) } func Test_Model_Value(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).Fields("nickname").Where("id", 1).Value() - t.AssertNil(err) - t.Assert(value.String(), "name_1") - }) + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Fields("nickname").Where("id", 1).Value() + t.AssertNil(err) + t.Assert(value.String(), "name_1") + }) - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).Fields("nickname").Where("id", 0).Value() - t.AssertNil(err) - t.Assert(value, nil) - }) + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Fields("nickname").Where("id", 0).Value() + t.AssertNil(err) + t.Assert(value, nil) + }) } func Test_Model_Array(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id", g.Slice{1, 2, 3}).All() - t.AssertNil(err) - t.Assert(all.Array("id"), g.Slice{1, 2, 3}) - t.Assert(all.Array("nickname"), g.Slice{"name_1", "name_2", "name_3"}) - }) - gtest.C(t, func(t *gtest.T) { - array, err := db.Model(table).Fields("nickname").Where("id", g.Slice{1, 2, 3}).Array() - t.AssertNil(err) - t.Assert(array, g.Slice{"name_1", "name_2", "name_3"}) - }) - gtest.C(t, func(t *gtest.T) { - array, err := db.Model(table).Array("nickname", "id", g.Slice{1, 2, 3}) - t.AssertNil(err) - t.Assert(array, g.Slice{"name_1", "name_2", "name_3"}) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id", g.Slice{1, 2, 3}).All() + t.AssertNil(err) + t.Assert(all.Array("id"), g.Slice{1, 2, 3}) + t.Assert(all.Array("nickname"), g.Slice{"name_1", "name_2", "name_3"}) + }) + + gtest.C(t, func(t *gtest.T) { + array, err := db.Model(table).Fields("nickname").Where("id", g.Slice{1, 2, 3}).Array() + t.AssertNil(err) + t.Assert(array, g.Slice{"name_1", "name_2", "name_3"}) + }) + gtest.C(t, func(t *gtest.T) { + array, err := db.Model(table).Array("nickname", "id", g.Slice{1, 2, 3}) + t.AssertNil(err) + t.Assert(array, g.Slice{"name_1", "name_2", "name_3"}) + }) } func Test_Model_Count(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) - // Count with cache, check internal ctx data feature. - gtest.C(t, func(t *gtest.T) { - for i := 0; i < 10; i++ { - count, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Name: guid.S(), - Force: false, - }).Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - } - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).FieldsEx("id").Where("id>8").Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Fields("distinct id,nickname").Where("id>8").Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - }) - // COUNT...LIMIT... - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Page(1, 2).Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) + // Count with cache, check internal ctx data feature. + gtest.C(t, func(t *gtest.T) { + for i := 0; i < 10; i++ { + count, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Name: guid.S(), + Force: false, + }).Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + } + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).FieldsEx("id").Where("id>8").Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Fields("distinct id,nickname").Where("id>8").Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + }) + // COUNT...LIMIT... + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Page(1, 2).Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) } func Test_Model_Exist(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - exist, err := db.Model(table).Exist() - t.AssertNil(err) - t.Assert(exist, TableSize > 0) - exist, err = db.Model(table).Where("id", -1).Exist() - t.AssertNil(err) - t.Assert(exist, false) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + exist, err := db.Model(table).Exist() + t.AssertNil(err) + t.Assert(exist, TableSize > 0) + exist, err = db.Model(table).Where("id", -1).Exist() + t.AssertNil(err) + t.Assert(exist, false) + }) } func Test_Model_Value_WithCache(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).Value() - t.AssertNil(err) - t.Assert(value.Int(), 0) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data(g.MapStrAny{ - "id": 1, - "passport": fmt.Sprintf(`passport_%d`, 1), - "password": fmt.Sprintf(`password_%d`, 1), - "nickname": fmt.Sprintf(`nickname_%d`, 1), - }).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).Value("id") - t.AssertNil(err) - t.Assert(value.Int(), 1) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).Value() + t.AssertNil(err) + t.Assert(value.Int(), 0) + }) + return + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data(g.MapStrAny{ + "id": 1, + "passport": fmt.Sprintf(`passport_%d`, 1), + "password": fmt.Sprintf(`password_%d`, 1), + "nickname": fmt.Sprintf(`nickname_%d`, 1), + }).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).Value("id") + t.AssertNil(err) + t.Assert(value.Int(), 1) + }) } func Test_Model_Count_WithCache(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).Count() - t.AssertNil(err) - t.Assert(count, int64(0)) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data(g.MapStrAny{ - "id": 1, - "passport": fmt.Sprintf(`passport_%d`, 1), - "password": fmt.Sprintf(`password_%d`, 1), - "nickname": fmt.Sprintf(`nickname_%d`, 1), - }).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).Count() - t.AssertNil(err) - t.Assert(count, int64(1)) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).Count() + t.AssertNil(err) + t.Assert(count, int64(0)) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data(g.MapStrAny{ + "id": 1, + "passport": fmt.Sprintf(`passport_%d`, 1), + "password": fmt.Sprintf(`password_%d`, 1), + "nickname": fmt.Sprintf(`nickname_%d`, 1), + }).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).Count() + t.AssertNil(err) + t.Assert(count, int64(1)) + }) } func Test_Model_Count_All_WithCache(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).Count() - t.AssertNil(err) - t.Assert(count, int64(0)) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data(g.MapStrAny{ - "id": 1, - "passport": fmt.Sprintf(`passport_%d`, 1), - "password": fmt.Sprintf(`password_%d`, 1), - "nickname": fmt.Sprintf(`nickname_%d`, 1), - }).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).Count() - t.AssertNil(err) - t.Assert(count, int64(1)) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data(g.MapStrAny{ - "id": 2, - "passport": fmt.Sprintf(`passport_%d`, 2), - "password": fmt.Sprintf(`password_%d`, 2), - "nickname": fmt.Sprintf(`nickname_%d`, 2), - }).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).Count() - t.AssertNil(err) - t.Assert(count, int64(1)) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).Count() + t.AssertNil(err) + t.Assert(count, int64(0)) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data(g.MapStrAny{ + "id": 1, + "passport": fmt.Sprintf(`passport_%d`, 1), + "password": fmt.Sprintf(`password_%d`, 1), + "nickname": fmt.Sprintf(`nickname_%d`, 1), + }).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).Count() + t.AssertNil(err) + t.Assert(count, int64(1)) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data(g.MapStrAny{ + "id": 2, + "passport": fmt.Sprintf(`passport_%d`, 2), + "password": fmt.Sprintf(`password_%d`, 2), + "nickname": fmt.Sprintf(`nickname_%d`, 2), + }).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).Count() + t.AssertNil(err) + t.Assert(count, int64(1)) + }) } func Test_Model_CountColumn_WithCache(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).CountColumn("id") - t.AssertNil(err) - t.Assert(count, int64(0)) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data(g.MapStrAny{ - "id": 1, - "passport": fmt.Sprintf(`passport_%d`, 1), - "password": fmt.Sprintf(`password_%d`, 1), - "nickname": fmt.Sprintf(`nickname_%d`, 1), - }).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).CountColumn("id") - t.AssertNil(err) - t.Assert(count, int64(1)) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).CountColumn("id") + t.AssertNil(err) + t.Assert(count, int64(0)) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data(g.MapStrAny{ + "id": 1, + "passport": fmt.Sprintf(`passport_%d`, 1), + "password": fmt.Sprintf(`password_%d`, 1), + "nickname": fmt.Sprintf(`nickname_%d`, 1), + }).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).CountColumn("id") + t.AssertNil(err) + t.Assert(count, int64(1)) + }) } func Test_Model_Select(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime gtime.Time - } - gtest.C(t, func(t *gtest.T) { - var users []User - err := db.Model(table).Scan(&users) - t.AssertNil(err) - t.Assert(len(users), TableSize) - }) + table := createInitTable() + defer dropTable(table) + + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + gtest.C(t, func(t *gtest.T) { + var users []User + err := db.Model(table).Scan(&users) + t.AssertNil(err) + t.Assert(len(users), TableSize) + }) } func Test_Model_Struct(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime gtime.Time - } - user := new(User) - err := db.Model(table).Where("id=1").Scan(user) - t.AssertNil(err) - t.Assert(user.NickName, "name_1") - t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") - }) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - user := new(User) - err := db.Model(table).Where("id=1").Scan(user) - t.AssertNil(err) - t.Assert(user.NickName, "name_1") - t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") - }) - // Auto creating struct object. - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - user := (*User)(nil) - err := db.Model(table).Where("id=1").Scan(&user) - t.AssertNil(err) - t.Assert(user.NickName, "name_1") - t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") - }) - // Just using Scan. - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - user := (*User)(nil) - err := db.Model(table).Where("id=1").Scan(&user) - if err != nil { - gtest.Error(err) - } - t.Assert(user.NickName, "name_1") - t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") - }) - // sql.ErrNoRows - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - user := new(User) - err := db.Model(table).Where("id=-1").Scan(user) - t.Assert(err, sql.ErrNoRows) - }) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - var user *User - err := db.Model(table).Where("id=-1").Scan(&user) - t.AssertNil(err) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=1").Scan(user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=1").Scan(user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") + }) + // Auto creating struct object. + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := (*User)(nil) + err := db.Model(table).Where("id=1").Scan(&user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") + }) + // Just using Scan. + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := (*User)(nil) + err := db.Model(table).Where("id=1").Scan(&user) + if err != nil { + gtest.Error(err) + } + t.Assert(user.NickName, "name_1") + t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") + }) + // sql.ErrNoRows + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=-1").Scan(user) + t.Assert(err, sql.ErrNoRows) + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var user *User + err := db.Model(table).Where("id=-1").Scan(&user) + t.AssertNil(err) + }) } func Test_Model_Struct_CustomType(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - type MyInt int - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id MyInt - Passport string - Password string - NickName string - CreateTime gtime.Time - } - user := new(User) - err := db.Model(table).Where("id=1").Scan(user) - t.AssertNil(err) - t.Assert(user.NickName, "name_1") - t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") - }) + table := createInitTable() + defer dropTable(table) + + type MyInt int + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id MyInt + Passport string + Password string + NickName string + CreateTime gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=1").Scan(user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") + }) } func Test_Model_Structs(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime gtime.Time - } - var users []User - err := db.Model(table).Order("id asc").Scan(&users) - if err != nil { - gtest.Error(err) - } - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - t.Assert(users[1].Id, 2) - t.Assert(users[2].Id, 3) - t.Assert(users[0].NickName, "name_1") - t.Assert(users[1].NickName, "name_2") - t.Assert(users[2].NickName, "name_3") - t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") - }) - // Auto create struct slice. - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - var users []*User - err := db.Model(table).Order("id asc").Scan(&users) - if err != nil { - gtest.Error(err) - } - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - t.Assert(users[1].Id, 2) - t.Assert(users[2].Id, 3) - t.Assert(users[0].NickName, "name_1") - t.Assert(users[1].NickName, "name_2") - t.Assert(users[2].NickName, "name_3") - t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") - }) - // Just using Scan. - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - var users []*User - err := db.Model(table).Order("id asc").Scan(&users) - if err != nil { - gtest.Error(err) - } - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - t.Assert(users[1].Id, 2) - t.Assert(users[2].Id, 3) - t.Assert(users[0].NickName, "name_1") - t.Assert(users[1].NickName, "name_2") - t.Assert(users[2].NickName, "name_3") - t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") - }) - // sql.ErrNoRows - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - var users []*User - err := db.Model(table).Where("id<0").Scan(&users) - t.AssertNil(err) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + var users []User + err := db.Model(table).Order("id asc").Scan(&users) + if err != nil { + gtest.Error(err) + } + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[1].Id, 2) + t.Assert(users[2].Id, 3) + t.Assert(users[0].NickName, "name_1") + t.Assert(users[1].NickName, "name_2") + t.Assert(users[2].NickName, "name_3") + t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") + }) + // Auto create struct slice. + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var users []*User + err := db.Model(table).Order("id asc").Scan(&users) + if err != nil { + gtest.Error(err) + } + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[1].Id, 2) + t.Assert(users[2].Id, 3) + t.Assert(users[0].NickName, "name_1") + t.Assert(users[1].NickName, "name_2") + t.Assert(users[2].NickName, "name_3") + t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") + }) + // Just using Scan. + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var users []*User + err := db.Model(table).Order("id asc").Scan(&users) + if err != nil { + gtest.Error(err) + } + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[1].Id, 2) + t.Assert(users[2].Id, 3) + t.Assert(users[0].NickName, "name_1") + t.Assert(users[1].NickName, "name_2") + t.Assert(users[2].NickName, "name_3") + t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") + }) + // sql.ErrNoRows + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var users []*User + err := db.Model(table).Where("id<0").Scan(&users) + t.AssertNil(err) + }) } func Test_Model_StructsWithOrmTag(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - dbInvalid.SetDebug(true) - defer dbInvalid.SetDebug(false) - gtest.C(t, func(t *gtest.T) { - type User struct { - Uid int `orm:"id"` - Passport string - Password string `orm:"password"` - Name string `orm:"nick_name"` - Time gtime.Time `orm:"create_time"` - } - var ( - users []User - buffer = bytes.NewBuffer(nil) - ) - dbInvalid.GetLogger().(*glog.Logger).SetWriter(buffer) - defer dbInvalid.GetLogger().(*glog.Logger).SetWriter(os.Stdout) - dbInvalid.Model(table).Order("id asc").Scan(&users) - // fmt.Println(buffer.String()) - t.Assert( - gstr.Contains( - buffer.String(), - "SELECT `id`,`Passport`,`password`,`nick_name`,`create_time` FROM `user", - ), - true, - ) - }) - - // db.SetDebug(true) - // defer db.SetDebug(false) - gtest.C(t, func(t *gtest.T) { - type A struct { - Passport string - Password string - } - type B struct { - A - NickName string - } - one, err := db.Model(table).Fields(&B{}).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 3) - t.Assert(one["nickname"], "name_2") - t.Assert(one["passport"], "user_2") - t.Assert(one["password"], "pass_2") - }) + table := createInitTable() + defer dropTable(table) + + dbInvalid.SetDebug(true) + defer dbInvalid.SetDebug(false) + gtest.C(t, func(t *gtest.T) { + type User struct { + Uid int `orm:"id"` + Passport string + Password string `orm:"password"` + Name string `orm:"nick_name"` + Time gtime.Time `orm:"create_time"` + } + var ( + users []User + buffer = bytes.NewBuffer(nil) + ) + dbInvalid.GetLogger().(*glog.Logger).SetWriter(buffer) + defer dbInvalid.GetLogger().(*glog.Logger).SetWriter(os.Stdout) + dbInvalid.Model(table).Order("id asc").Scan(&users) + // fmt.Println(buffer.String()) + t.Assert( + gstr.Contains( + buffer.String(), + "SELECT `id`,`Passport`,`password`,`nick_name`,`create_time` FROM `user", + ), + true, + ) + }) + + // db.SetDebug(true) + // defer db.SetDebug(false) + gtest.C(t, func(t *gtest.T) { + type A struct { + Passport string + Password string + } + type B struct { + A + NickName string + } + one, err := db.Model(table).Fields(&B{}).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 3) + t.Assert(one["nickname"], "name_2") + t.Assert(one["passport"], "user_2") + t.Assert(one["password"], "pass_2") + }) } func Test_Model_Scan(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime gtime.Time - } - user := new(User) - err := db.Model(table).Where("id=1").Scan(user) - t.AssertNil(err) - t.Assert(user.NickName, "name_1") - t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") - }) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - user := new(User) - err := db.Model(table).Where("id=1").Scan(user) - t.AssertNil(err) - t.Assert(user.NickName, "name_1") - t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") - }) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime gtime.Time - } - var users []User - err := db.Model(table).Order("id asc").Scan(&users) - t.AssertNil(err) - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - t.Assert(users[1].Id, 2) - t.Assert(users[2].Id, 3) - t.Assert(users[0].NickName, "name_1") - t.Assert(users[1].NickName, "name_2") - t.Assert(users[2].NickName, "name_3") - t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") - }) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - var users []*User - err := db.Model(table).Order("id asc").Scan(&users) - t.AssertNil(err) - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - t.Assert(users[1].Id, 2) - t.Assert(users[2].Id, 3) - t.Assert(users[0].NickName, "name_1") - t.Assert(users[1].NickName, "name_2") - t.Assert(users[2].NickName, "name_3") - t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") - }) - // sql.ErrNoRows - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - var ( - user = new(User) - users = new([]*User) - ) - err1 := db.Model(table).Where("id < 0").Scan(user) - err2 := db.Model(table).Where("id < 0").Scan(users) - t.Assert(err1, sql.ErrNoRows) - t.Assert(err2, nil) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=1").Scan(user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=1").Scan(user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + var users []User + err := db.Model(table).Order("id asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[1].Id, 2) + t.Assert(users[2].Id, 3) + t.Assert(users[0].NickName, "name_1") + t.Assert(users[1].NickName, "name_2") + t.Assert(users[2].NickName, "name_3") + t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var users []*User + err := db.Model(table).Order("id asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[1].Id, 2) + t.Assert(users[2].Id, 3) + t.Assert(users[0].NickName, "name_1") + t.Assert(users[1].NickName, "name_2") + t.Assert(users[2].NickName, "name_3") + t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") + }) + // sql.ErrNoRows + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var ( + user = new(User) + users = new([]*User) + ) + err1 := db.Model(table).Where("id < 0").Scan(user) + err2 := db.Model(table).Where("id < 0").Scan(users) + t.Assert(err1, sql.ErrNoRows) + t.Assert(err2, nil) + }) } func Test_Model_Scan_NilSliceAttrWhenNoRecordsFound(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime gtime.Time - } - type Response struct { - Users []User `json:"users"` - } - var res Response - err := db.Model(table).Scan(&res.Users) - t.AssertNil(err) - t.Assert(res.Users, nil) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + type Response struct { + Users []User `json:"users"` + } + var res Response + err := db.Model(table).Scan(&res.Users) + t.AssertNil(err) + t.Assert(res.Users, nil) + }) } func Test_Model_OrderBy(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Order("id DESC").All() - t.AssertNil(err) - t.Assert(len(result), TableSize) - t.Assert(result[0]["nickname"].String(), fmt.Sprintf("name_%d", TableSize)) - }) - - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Order(gdb.Raw("NULL")).All() - t.AssertNil(err) - t.Assert(len(result), TableSize) - t.Assert(result[0]["nickname"].String(), "name_1") - }) - - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Order(gdb.Raw("field(id, 10,1,2,3,4,5,6,7,8,9)")).All() - t.AssertNil(err) - t.Assert(len(result), TableSize) - t.Assert(result[0]["nickname"].String(), "name_10") - t.Assert(result[1]["nickname"].String(), "name_1") - t.Assert(result[2]["nickname"].String(), "name_2") - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Order("id DESC").All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + t.Assert(result[0]["nickname"].String(), fmt.Sprintf("name_%d", TableSize)) + }) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Order(gdb.Raw("NULL")).All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + t.Assert(result[0]["nickname"].String(), "name_1") + }) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Order(gdb.Raw("field(id, 10,1,2,3,4,5,6,7,8,9)")).All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + t.Assert(result[0]["nickname"].String(), "name_10") + t.Assert(result[1]["nickname"].String(), "name_1") + t.Assert(result[2]["nickname"].String(), "name_2") + }) } func Test_Model_GroupBy(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Group("id").All() - t.AssertNil(err) - t.Assert(len(result), TableSize) - t.Assert(result[0]["nickname"].String(), "name_1") - }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Group("id").All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + t.Assert(result[0]["nickname"].String(), "name_1") + }) } func Test_Model_Data(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - table := createInitTable() - defer dropTable(table) - result, err := db.Model(table).Data("nickname=?", "test").Where("id=?", 3).Update() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - users := make([]g.MapStrAny, 0) - for i := 1; i <= 10; i++ { - users = append(users, g.MapStrAny{ - "id": i, - "passport": fmt.Sprintf(`passport_%d`, i), - "password": fmt.Sprintf(`password_%d`, i), - "nickname": fmt.Sprintf(`nickname_%d`, i), - }) - } - result, err := db.Model(table).Data(users).Batch(2).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 10) - }) - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - users := garray.New() - for i := 1; i <= 10; i++ { - users.Append(g.MapStrAny{ - "id": i, - "passport": fmt.Sprintf(`passport_%d`, i), - "password": fmt.Sprintf(`password_%d`, i), - "nickname": fmt.Sprintf(`nickname_%d`, i), - }) - } - result, err := db.Model(table).Data(users).Batch(2).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 10) - }) + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + result, err := db.Model(table).Data("nickname=?", "test").Where("id=?", 3).Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + users := make([]g.MapStrAny, 0) + for i := 1; i <= 10; i++ { + users = append(users, g.MapStrAny{ + "id": i, + "passport": fmt.Sprintf(`passport_%d`, i), + "password": fmt.Sprintf(`password_%d`, i), + "nickname": fmt.Sprintf(`nickname_%d`, i), + }) + } + result, err := db.Model(table).Data(users).Batch(2).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 10) + }) + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + users := garray.New() + for i := 1; i <= 10; i++ { + users.Append(g.MapStrAny{ + "id": i, + "passport": fmt.Sprintf(`passport_%d`, i), + "password": fmt.Sprintf(`password_%d`, i), + "nickname": fmt.Sprintf(`nickname_%d`, i), + }) + } + result, err := db.Model(table).Data(users).Batch(2).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 10) + }) } func Test_Model_Delete(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - // DELETE...LIMIT - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Where(1).Limit(2).Delete() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 2) - }) + // DELETE...LIMIT + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(1).Limit(2).Delete() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 2) + }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Where(1).Delete() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, TableSize-2) - }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(1).Delete() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, TableSize-2) + }) } func Test_Model_Offset(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Limit(2).Offset(5).Order("id").All() - t.AssertNil(err) - t.Assert(len(result), 2) - t.Assert(result[0]["id"], 6) - t.Assert(result[1]["id"], 7) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Limit(2).Offset(5).Order("id").All() + t.AssertNil(err) + t.Assert(len(result), 2) + t.Assert(result[0]["id"], 6) + t.Assert(result[1]["id"], 7) + }) } func Test_Model_Page(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Page(3, 3).Order("id").All() - t.AssertNil(err) - t.Assert(len(result), 3) - t.Assert(result[0]["id"], 7) - t.Assert(result[1]["id"], 8) - }) - gtest.C(t, func(t *gtest.T) { - model := db.Model(table).Safe().Order("id") - all, err := model.Page(3, 3).All() - count, err := model.Count() - t.AssertNil(err) - t.Assert(len(all), 3) - t.Assert(all[0]["id"], "7") - t.Assert(count, int64(TableSize)) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Page(3, 3).Order("id").All() + t.AssertNil(err) + t.Assert(len(result), 3) + t.Assert(result[0]["id"], 7) + t.Assert(result[1]["id"], 8) + }) + gtest.C(t, func(t *gtest.T) { + model := db.Model(table).Safe().Order("id") + all, err := model.Page(3, 3).All() + count, err := model.Count() + t.AssertNil(err) + t.Assert(len(all), 3) + t.Assert(all[0]["id"], "7") + t.Assert(count, int64(TableSize)) + }) } func Test_Model_Option_Map(t *testing.T) { - // Insert - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - r, err := db.Model(table).Fields("id, passport").Data(g.Map{ - "id": 1, - "passport": "1", - "password": "1", - "nickname": "1", - }).Insert() - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - one, err := db.Model(table).Where("id", 1).One() - t.AssertNil(err) - t.AssertNE(one["password"].String(), "1") - t.AssertNE(one["nickname"].String(), "1") - t.Assert(one["passport"].String(), "1") - }) - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - r, err := db.Model(table).OmitEmptyData().Data(g.Map{ - "id": 1, - "passport": 0, - "password": 0, - "nickname": "1", - }).Insert() - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - one, err := db.Model(table).Where("id", 1).One() - t.AssertNil(err) - t.AssertNE(one["passport"].String(), "0") - t.AssertNE(one["password"].String(), "0") - t.Assert(one["nickname"].String(), "1") - }) - - // Replace - gtest.C(t, func(t *gtest.T) { - table := createInitTable() - defer dropTable(table) - _, err := db.Model(table).OmitEmptyData().Data(g.Map{ - "id": 1, - "passport": 0, - "password": 0, - "nickname": "1", - }).Replace() - t.AssertNil(err) - one, err := db.Model(table).Where("id", 1).One() - t.AssertNil(err) - t.AssertNE(one["passport"].String(), "0") - t.AssertNE(one["password"].String(), "0") - t.Assert(one["nickname"].String(), "1") - }) - - // Save - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - r, err := db.Model(table).Fields("id, passport").Data(g.Map{ - "id": 1, - "passport": "1", - "password": "1", - "nickname": "1", - }).Save() - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - one, err := db.Model(table).Where("id", 1).One() - t.AssertNil(err) - t.AssertNE(one["password"].String(), "1") - t.AssertNE(one["nickname"].String(), "1") - t.Assert(one["passport"].String(), "1") - }) - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - _, err := db.Model(table).OmitEmptyData().Data(g.Map{ - "id": 1, - "passport": 0, - "password": 0, - "nickname": "1", - }).Save() - t.AssertNil(err) - one, err := db.Model(table).Where("id", 1).One() - t.AssertNil(err) - t.AssertNE(one["passport"].String(), "0") - t.AssertNE(one["password"].String(), "0") - t.Assert(one["nickname"].String(), "1") - - _, err = db.Model(table).Data(g.Map{ - "id": 1, - "passport": 0, - "password": 0, - "nickname": "1", - }).Save() - t.AssertNil(err) - one, err = db.Model(table).Where("id", 1).One() - t.AssertNil(err) - t.Assert(one["passport"].String(), "0") - t.Assert(one["password"].String(), "0") - t.Assert(one["nickname"].String(), "1") - }) - - // Update - gtest.C(t, func(t *gtest.T) { - table := createInitTable() - defer dropTable(table) - - r, err := db.Model(table).Data(g.Map{"nickname": ""}).Where("id", 1).Update() - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - - _, err = db.Model(table).OmitEmptyData().Data(g.Map{"nickname": ""}).Where("id", 2).Update() - t.AssertNE(err, nil) - - r, err = db.Model(table).OmitEmpty().Data(g.Map{"nickname": "", "password": "123"}).Where("id", 3).Update() - t.AssertNil(err) - n, _ = r.RowsAffected() - t.Assert(n, 1) - - _, err = db.Model(table).OmitEmpty().Fields("nickname").Data(g.Map{"nickname": "", "password": "123"}).Where("id", 4).Update() - t.AssertNE(err, nil) - - r, err = db.Model(table).OmitEmpty(). - Fields("password").Data(g.Map{ - "nickname": "", - "passport": "123", - "password": "456", - }).Where("id", 5).Update() - t.AssertNil(err) - n, _ = r.RowsAffected() - t.Assert(n, 1) - - one, err := db.Model(table).Where("id", 5).One() - t.AssertNil(err) - t.Assert(one["password"], "456") - t.AssertNE(one["passport"].String(), "") - t.AssertNE(one["passport"].String(), "123") - }) + // Insert + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + r, err := db.Model(table).Fields("id, passport").Data(g.Map{ + "id": 1, + "passport": "1", + "password": "1", + "nickname": "1", + }).Insert() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + one, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.AssertNE(one["password"].String(), "1") + t.AssertNE(one["nickname"].String(), "1") + t.Assert(one["passport"].String(), "1") + }) + + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + r, err := db.Model(table).OmitEmptyData().Data(g.Map{ + "id": 1, + "passport": 0, + "password": 0, + "nickname": "1", + }).Insert() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + one, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.AssertNE(one["passport"].String(), "0") + t.AssertNE(one["password"].String(), "0") + t.Assert(one["nickname"].String(), "1") + }) + + // Replace + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + _, err := db.Model(table).OmitEmptyData().Data(g.Map{ + "id": 1, + "passport": 0, + "password": 0, + "nickname": "1", + }).Replace() + t.AssertNil(err) + one, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.AssertNE(one["passport"].String(), "0") + t.AssertNE(one["password"].String(), "0") + t.Assert(one["nickname"].String(), "1") + }) + + // Save + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + r, err := db.Model(table).Fields("id, passport").Data(g.Map{ + "id": 1, + "passport": "1", + "password": "1", + "nickname": "1", + }).Save() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + one, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.AssertNE(one["password"].String(), "1") + t.AssertNE(one["nickname"].String(), "1") + t.Assert(one["passport"].String(), "1") + }) + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + _, err := db.Model(table).OmitEmptyData().Data(g.Map{ + "id": 1, + "passport": 0, + "password": 0, + "nickname": "1", + }).Save() + t.AssertNil(err) + one, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.AssertNE(one["passport"].String(), "0") + t.AssertNE(one["password"].String(), "0") + t.Assert(one["nickname"].String(), "1") + + _, err = db.Model(table).Data(g.Map{ + "id": 1, + "passport": 0, + "password": 0, + "nickname": "1", + }).Save() + t.AssertNil(err) + one, err = db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.Assert(one["passport"].String(), "0") + t.Assert(one["password"].String(), "0") + t.Assert(one["nickname"].String(), "1") + }) + + // Update + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + + r, err := db.Model(table).Data(g.Map{"nickname": ""}).Where("id", 1).Update() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + + _, err = db.Model(table).OmitEmptyData().Data(g.Map{"nickname": ""}).Where("id", 2).Update() + t.AssertNE(err, nil) + + r, err = db.Model(table).OmitEmpty().Data(g.Map{"nickname": "", "password": "123"}).Where("id", 3).Update() + t.AssertNil(err) + n, _ = r.RowsAffected() + t.Assert(n, 1) + + _, err = db.Model(table).OmitEmpty().Fields("nickname").Data(g.Map{"nickname": "", "password": "123"}).Where("id", 4).Update() + t.AssertNE(err, nil) + + r, err = db.Model(table).OmitEmpty(). + Fields("password").Data(g.Map{ + "nickname": "", + "passport": "123", + "password": "456", + }).Where("id", 5).Update() + t.AssertNil(err) + n, _ = r.RowsAffected() + t.Assert(n, 1) + + one, err := db.Model(table).Where("id", 5).One() + t.AssertNil(err) + t.Assert(one["password"], "456") + t.AssertNE(one["passport"].String(), "") + t.AssertNE(one["passport"].String(), "123") + }) } func Test_Model_Option_List(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - r, err := db.Model(table).Fields("id, password").Data(g.List{ - g.Map{ - "id": 1, - "passport": "1", - "password": "1", - "nickname": "1", - }, - g.Map{ - "id": 2, - "passport": "2", - "password": "2", - "nickname": "2", - }, - }).Save() - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 2) - list, err := db.Model(table).Order("id asc").All() - t.AssertNil(err) - t.Assert(len(list), 2) - t.Assert(list[0]["id"].String(), "1") - t.Assert(list[0]["nickname"].String(), "") - t.Assert(list[0]["passport"].String(), "") - t.Assert(list[0]["password"].String(), "1") - - t.Assert(list[1]["id"].String(), "2") - t.Assert(list[1]["nickname"].String(), "") - t.Assert(list[1]["passport"].String(), "") - t.Assert(list[1]["password"].String(), "2") - }) - - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - r, err := db.Model(table).OmitEmpty().Fields("id, password").Data(g.List{ - g.Map{ - "id": 1, - "passport": "1", - "password": 0, - "nickname": "1", - }, - g.Map{ - "id": 2, - "passport": "2", - "password": "2", - "nickname": "2", - }, - }).Save() - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 2) - list, err := db.Model(table).Order("id asc").All() - t.AssertNil(err) - t.Assert(len(list), 2) - t.Assert(list[0]["id"].String(), "1") - t.Assert(list[0]["nickname"].String(), "") - t.Assert(list[0]["passport"].String(), "") - t.Assert(list[0]["password"].String(), "0") - - t.Assert(list[1]["id"].String(), "2") - t.Assert(list[1]["nickname"].String(), "") - t.Assert(list[1]["passport"].String(), "") - t.Assert(list[1]["password"].String(), "2") - }) + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + r, err := db.Model(table).Fields("id, password").Data(g.List{ + g.Map{ + "id": 1, + "passport": "1", + "password": "1", + "nickname": "1", + }, + g.Map{ + "id": 2, + "passport": "2", + "password": "2", + "nickname": "2", + }, + }).Save() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 2) + list, err := db.Model(table).Order("id asc").All() + t.AssertNil(err) + t.Assert(len(list), 2) + t.Assert(list[0]["id"].String(), "1") + t.Assert(list[0]["nickname"].String(), "") + t.Assert(list[0]["passport"].String(), "") + t.Assert(list[0]["password"].String(), "1") + + t.Assert(list[1]["id"].String(), "2") + t.Assert(list[1]["nickname"].String(), "") + t.Assert(list[1]["passport"].String(), "") + t.Assert(list[1]["password"].String(), "2") + }) + + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + r, err := db.Model(table).OmitEmpty().Fields("id, password").Data(g.List{ + g.Map{ + "id": 1, + "passport": "1", + "password": 0, + "nickname": "1", + }, + g.Map{ + "id": 2, + "passport": "2", + "password": "2", + "nickname": "2", + }, + }).Save() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 2) + list, err := db.Model(table).Order("id asc").All() + t.AssertNil(err) + t.Assert(len(list), 2) + t.Assert(list[0]["id"].String(), "1") + t.Assert(list[0]["nickname"].String(), "") + t.Assert(list[0]["passport"].String(), "") + t.Assert(list[0]["password"].String(), "0") + + t.Assert(list[1]["id"].String(), "2") + t.Assert(list[1]["nickname"].String(), "") + t.Assert(list[1]["passport"].String(), "") + t.Assert(list[1]["password"].String(), "2") + }) } func Test_Model_OmitEmpty(t *testing.T) { - table := fmt.Sprintf(`table_%s`, gtime.TimestampNanoStr()) - if _, err := db.Exec(ctx, fmt.Sprintf(` + table := fmt.Sprintf(`table_%s`, gtime.TimestampNanoStr()) + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE IF NOT EXISTS %s ( id int(10) unsigned NOT NULL AUTO_INCREMENT, name varchar(45) NOT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; `, table)); err != nil { - gtest.Error(err) - } - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).OmitEmpty().Data(g.Map{ - "id": 1, - "name": "", - }).Save() - t.AssertNE(err, nil) - }) - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).OmitEmptyData().Data(g.Map{ - "id": 1, - "name": "", - }).Save() - t.AssertNE(err, nil) - }) - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).OmitEmptyWhere().Data(g.Map{ - "id": 1, - "name": "", - }).Save() - t.AssertNil(err) - }) + gtest.Error(err) + } + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).OmitEmpty().Data(g.Map{ + "id": 1, + "name": "", + }).Save() + t.AssertNE(err, nil) + }) + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).OmitEmptyData().Data(g.Map{ + "id": 1, + "name": "", + }).Save() + t.AssertNE(err, nil) + }) + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).OmitEmptyWhere().Data(g.Map{ + "id": 1, + "name": "", + }).Save() + t.AssertNil(err) + }) } func Test_Model_OmitNil(t *testing.T) { - table := fmt.Sprintf(`table_%s`, gtime.TimestampNanoStr()) - if _, err := db.Exec(ctx, fmt.Sprintf(` + table := fmt.Sprintf(`table_%s`, gtime.TimestampNanoStr()) + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE IF NOT EXISTS %s ( id int(10) unsigned NOT NULL AUTO_INCREMENT, name varchar(45) NOT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; `, table)); err != nil { - gtest.Error(err) - } - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).OmitNil().Data(g.Map{ - "id": 1, - "name": nil, - }).Save() - t.AssertNE(err, nil) - }) - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).OmitNil().Data(g.Map{ - "id": 1, - "name": "", - }).Save() - t.AssertNil(err) - }) - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).OmitNilWhere().Data(g.Map{ - "id": 1, - "name": "", - }).Save() - t.AssertNil(err) - }) + gtest.Error(err) + } + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).OmitNil().Data(g.Map{ + "id": 1, + "name": nil, + }).Save() + t.AssertNE(err, nil) + }) + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).OmitNil().Data(g.Map{ + "id": 1, + "name": "", + }).Save() + t.AssertNil(err) + }) + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).OmitNilWhere().Data(g.Map{ + "id": 1, + "name": "", + }).Save() + t.AssertNil(err) + }) } func Test_Model_FieldsEx(t *testing.T) { - table := createInitTable() - defer dropTable(table) - // Select. - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table).FieldsEx("create_time, id").Where("id in (?)", g.Slice{1, 2}).Order("id asc").All() - t.AssertNil(err) - t.Assert(len(r), 2) - t.Assert(len(r[0]), 4) - t.Assert(r[0]["id"], "") - t.Assert(r[0]["passport"], "user_1") - t.Assert(r[0]["password"], "pass_1") - t.Assert(r[0]["nickname"], "name_1") - t.Assert(r[0]["create_time"], "") - t.Assert(r[1]["id"], "") - t.Assert(r[1]["passport"], "user_2") - t.Assert(r[1]["password"], "pass_2") - t.Assert(r[1]["nickname"], "name_2") - t.Assert(r[1]["create_time"], "") - }) - // Update. - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table).FieldsEx("password").Data(g.Map{"nickname": "123", "password": "456"}).Where("id", 3).Update() - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - - one, err := db.Model(table).Where("id", 3).One() - t.AssertNil(err) - t.Assert(one["nickname"], "123") - t.AssertNE(one["password"], "456") - }) + table := createInitTable() + defer dropTable(table) + // Select. + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).FieldsEx("create_time, id").Where("id in (?)", g.Slice{1, 2}).Order("id asc").All() + t.AssertNil(err) + t.Assert(len(r), 2) + t.Assert(len(r[0]), 4) + t.Assert(r[0]["id"], "") + t.Assert(r[0]["passport"], "user_1") + t.Assert(r[0]["password"], "pass_1") + t.Assert(r[0]["nickname"], "name_1") + t.Assert(r[0]["create_time"], "") + t.Assert(r[1]["id"], "") + t.Assert(r[1]["passport"], "user_2") + t.Assert(r[1]["password"], "pass_2") + t.Assert(r[1]["nickname"], "name_2") + t.Assert(r[1]["create_time"], "") + }) + // Update. + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).FieldsEx("password").Data(g.Map{"nickname": "123", "password": "456"}).Where("id", 3).Update() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + + one, err := db.Model(table).Where("id", 3).One() + t.AssertNil(err) + t.Assert(one["nickname"], "123") + t.AssertNE(one["password"], "456") + }) } func Test_Model_FieldsEx_WithReservedWords(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - var ( - table = "fieldsex_test_table" - sqlTpcPath = gtest.DataPath("reservedwords_table_tpl.sql") - sqlContent = gfile.GetContents(sqlTpcPath) - ) - t.AssertNE(sqlContent, "") - if _, err := db.Exec(ctx, fmt.Sprintf(sqlContent, table)); err != nil { - t.AssertNil(err) - } - defer dropTable(table) - _, err := db.Model(table).FieldsEx("content").One() - t.AssertNil(err) - }) + gtest.C(t, func(t *gtest.T) { + var ( + table = "fieldsex_test_table" + sqlTpcPath = gtest.DataPath("reservedwords_table_tpl.sql") + sqlContent = gfile.GetContents(sqlTpcPath) + ) + t.AssertNE(sqlContent, "") + if _, err := db.Exec(ctx, fmt.Sprintf(sqlContent, table)); err != nil { + t.AssertNil(err) + } + defer dropTable(table) + _, err := db.Model(table).FieldsEx("content").One() + t.AssertNil(err) + }) } func Test_Model_Prefix(t *testing.T) { - db := dbPrefix - table := fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano()) - createInitTableWithDb(db, TableNamePrefix1+table) - defer dropTable(TableNamePrefix1 + table) - // Select. - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table).Where("id in (?)", g.Slice{1, 2}).Order("id asc").All() - t.AssertNil(err) - t.Assert(len(r), 2) - t.Assert(r[0]["id"], "1") - t.Assert(r[1]["id"], "2") - }) - // Select with alias. - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table+" as u").Where("u.id in (?)", g.Slice{1, 2}).Order("u.id asc").All() - t.AssertNil(err) - t.Assert(len(r), 2) - t.Assert(r[0]["id"], "1") - t.Assert(r[1]["id"], "2") - }) - // Select with alias to struct. - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - } - var users []User - err := db.Model(table+" u").Where("u.id in (?)", g.Slice{1, 5}).Order("u.id asc").Scan(&users) - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(users[0].Id, 1) - t.Assert(users[1].Id, 5) - }) - // Select with alias and join statement. - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table+" as u1").LeftJoin(table+" as u2", "u2.id=u1.id").Where("u1.id in (?)", g.Slice{1, 2}).Order("u1.id asc").All() - t.AssertNil(err) - t.Assert(len(r), 2) - t.Assert(r[0]["id"], "1") - t.Assert(r[1]["id"], "2") - }) - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table).As("u1").LeftJoin(table+" as u2", "u2.id=u1.id").Where("u1.id in (?)", g.Slice{1, 2}).Order("u1.id asc").All() - t.AssertNil(err) - t.Assert(len(r), 2) - t.Assert(r[0]["id"], "1") - t.Assert(r[1]["id"], "2") - }) + db := dbPrefix + table := fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano()) + createInitTableWithDb(db, TableNamePrefix1+table) + defer dropTable(TableNamePrefix1 + table) + // Select. + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).Where("id in (?)", g.Slice{1, 2}).Order("id asc").All() + t.AssertNil(err) + t.Assert(len(r), 2) + t.Assert(r[0]["id"], "1") + t.Assert(r[1]["id"], "2") + }) + // Select with alias. + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table+" as u").Where("u.id in (?)", g.Slice{1, 2}).Order("u.id asc").All() + t.AssertNil(err) + t.Assert(len(r), 2) + t.Assert(r[0]["id"], "1") + t.Assert(r[1]["id"], "2") + }) + // Select with alias to struct. + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + } + var users []User + err := db.Model(table+" u").Where("u.id in (?)", g.Slice{1, 5}).Order("u.id asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(users[0].Id, 1) + t.Assert(users[1].Id, 5) + }) + // Select with alias and join statement. + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table+" as u1").LeftJoin(table+" as u2", "u2.id=u1.id").Where("u1.id in (?)", g.Slice{1, 2}).Order("u1.id asc").All() + t.AssertNil(err) + t.Assert(len(r), 2) + t.Assert(r[0]["id"], "1") + t.Assert(r[1]["id"], "2") + }) + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).As("u1").LeftJoin(table+" as u2", "u2.id=u1.id").Where("u1.id in (?)", g.Slice{1, 2}).Order("u1.id asc").All() + t.AssertNil(err) + t.Assert(len(r), 2) + t.Assert(r[0]["id"], "1") + t.Assert(r[1]["id"], "2") + }) } func Test_Model_Schema1(t *testing.T) { - // db.SetDebug(true) - - db = db.Schema(TestSchema1) - table := fmt.Sprintf(`%s_%s`, TableName, gtime.TimestampNanoStr()) - createInitTableWithDb(db, table) - db = db.Schema(TestSchema2) - createInitTableWithDb(db, table) - defer func() { - db = db.Schema(TestSchema1) - dropTableWithDb(db, table) - db = db.Schema(TestSchema2) - dropTableWithDb(db, table) - db = db.Schema(TestSchema1) - }() - // Method. - gtest.C(t, func(t *gtest.T) { - db = db.Schema(TestSchema1) - r, err := db.Model(table).Update(g.Map{"nickname": "name_100"}, "id=1") - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - - v, err := db.Model(table).Value("nickname", "id=1") - t.AssertNil(err) - t.Assert(v.String(), "name_100") - - db = db.Schema(TestSchema2) - v, err = db.Model(table).Value("nickname", "id=1") - t.AssertNil(err) - t.Assert(v.String(), "name_1") - }) - // Model. - gtest.C(t, func(t *gtest.T) { - v, err := db.Model(table).Schema(TestSchema1).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_2") - - r, err := db.Model(table).Schema(TestSchema1).Update(g.Map{"nickname": "name_200"}, "id=2") - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - - v, err = db.Model(table).Schema(TestSchema1).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_200") - - v, err = db.Model(table).Schema(TestSchema2).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_2") - - v, err = db.Model(table).Schema(TestSchema1).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_200") - }) - // Model. - gtest.C(t, func(t *gtest.T) { - i := 1000 - _, err := db.Model(table).Schema(TestSchema1).Insert(g.Map{ - "id": i, - "passport": fmt.Sprintf(`user_%d`, i), - "password": fmt.Sprintf(`pass_%d`, i), - "nickname": fmt.Sprintf(`name_%d`, i), - "create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(), - "none-exist-field": 1, - }) - t.AssertNil(err) - - v, err := db.Model(table).Schema(TestSchema1).Value("nickname", "id=?", i) - t.AssertNil(err) - t.Assert(v.String(), "name_1000") - - v, err = db.Model(table).Schema(TestSchema2).Value("nickname", "id=?", i) - t.AssertNil(err) - t.Assert(v.String(), "") - }) + // db.SetDebug(true) + + db = db.Schema(TestSchema1) + table := fmt.Sprintf(`%s_%s`, TableName, gtime.TimestampNanoStr()) + createInitTableWithDb(db, table) + db = db.Schema(TestSchema2) + createInitTableWithDb(db, table) + defer func() { + db = db.Schema(TestSchema1) + dropTableWithDb(db, table) + db = db.Schema(TestSchema2) + dropTableWithDb(db, table) + db = db.Schema(TestSchema1) + }() + // Method. + gtest.C(t, func(t *gtest.T) { + db = db.Schema(TestSchema1) + r, err := db.Model(table).Update(g.Map{"nickname": "name_100"}, "id=1") + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + + v, err := db.Model(table).Value("nickname", "id=1") + t.AssertNil(err) + t.Assert(v.String(), "name_100") + + db = db.Schema(TestSchema2) + v, err = db.Model(table).Value("nickname", "id=1") + t.AssertNil(err) + t.Assert(v.String(), "name_1") + }) + // Model. + gtest.C(t, func(t *gtest.T) { + v, err := db.Model(table).Schema(TestSchema1).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_2") + + r, err := db.Model(table).Schema(TestSchema1).Update(g.Map{"nickname": "name_200"}, "id=2") + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + + v, err = db.Model(table).Schema(TestSchema1).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_200") + + v, err = db.Model(table).Schema(TestSchema2).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_2") + + v, err = db.Model(table).Schema(TestSchema1).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_200") + }) + // Model. + gtest.C(t, func(t *gtest.T) { + i := 1000 + _, err := db.Model(table).Schema(TestSchema1).Insert(g.Map{ + "id": i, + "passport": fmt.Sprintf(`user_%d`, i), + "password": fmt.Sprintf(`pass_%d`, i), + "nickname": fmt.Sprintf(`name_%d`, i), + "create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(), + "none-exist-field": 1, + }) + t.AssertNil(err) + + v, err := db.Model(table).Schema(TestSchema1).Value("nickname", "id=?", i) + t.AssertNil(err) + t.Assert(v.String(), "name_1000") + + v, err = db.Model(table).Schema(TestSchema2).Value("nickname", "id=?", i) + t.AssertNil(err) + t.Assert(v.String(), "") + }) } func Test_Model_Schema2(t *testing.T) { - // db.SetDebug(true) - - db = db.Schema(TestSchema1) - table := fmt.Sprintf(`%s_%s`, TableName, gtime.TimestampNanoStr()) - createInitTableWithDb(db, table) - db = db.Schema(TestSchema2) - createInitTableWithDb(db, table) - defer func() { - db = db.Schema(TestSchema1) - dropTableWithDb(db, table) - db = db.Schema(TestSchema2) - dropTableWithDb(db, table) - - db = db.Schema(TestSchema1) - }() - // Schema. - gtest.C(t, func(t *gtest.T) { - v, err := db.Schema(TestSchema1).Model(table).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_2") - - r, err := db.Schema(TestSchema1).Model(table).Update(g.Map{"nickname": "name_200"}, "id=2") - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - - v, err = db.Schema(TestSchema1).Model(table).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_200") - - v, err = db.Schema(TestSchema2).Model(table).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_2") - - v, err = db.Schema(TestSchema1).Model(table).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_200") - }) - // Schema. - gtest.C(t, func(t *gtest.T) { - i := 1000 - _, err := db.Schema(TestSchema1).Model(table).Insert(g.Map{ - "id": i, - "passport": fmt.Sprintf(`user_%d`, i), - "password": fmt.Sprintf(`pass_%d`, i), - "nickname": fmt.Sprintf(`name_%d`, i), - "create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(), - "none-exist-field": 1, - }) - t.AssertNil(err) - - v, err := db.Schema(TestSchema1).Model(table).Value("nickname", "id=?", i) - t.AssertNil(err) - t.Assert(v.String(), "name_1000") - - v, err = db.Schema(TestSchema2).Model(table).Value("nickname", "id=?", i) - t.AssertNil(err) - t.Assert(v.String(), "") - }) + // db.SetDebug(true) + + db = db.Schema(TestSchema1) + table := fmt.Sprintf(`%s_%s`, TableName, gtime.TimestampNanoStr()) + createInitTableWithDb(db, table) + db = db.Schema(TestSchema2) + createInitTableWithDb(db, table) + defer func() { + db = db.Schema(TestSchema1) + dropTableWithDb(db, table) + db = db.Schema(TestSchema2) + dropTableWithDb(db, table) + + db = db.Schema(TestSchema1) + }() + // Schema. + gtest.C(t, func(t *gtest.T) { + v, err := db.Schema(TestSchema1).Model(table).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_2") + + r, err := db.Schema(TestSchema1).Model(table).Update(g.Map{"nickname": "name_200"}, "id=2") + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + + v, err = db.Schema(TestSchema1).Model(table).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_200") + + v, err = db.Schema(TestSchema2).Model(table).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_2") + + v, err = db.Schema(TestSchema1).Model(table).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_200") + }) + // Schema. + gtest.C(t, func(t *gtest.T) { + i := 1000 + _, err := db.Schema(TestSchema1).Model(table).Insert(g.Map{ + "id": i, + "passport": fmt.Sprintf(`user_%d`, i), + "password": fmt.Sprintf(`pass_%d`, i), + "nickname": fmt.Sprintf(`name_%d`, i), + "create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(), + "none-exist-field": 1, + }) + t.AssertNil(err) + + v, err := db.Schema(TestSchema1).Model(table).Value("nickname", "id=?", i) + t.AssertNil(err) + t.Assert(v.String(), "name_1000") + + v, err = db.Schema(TestSchema2).Model(table).Value("nickname", "id=?", i) + t.AssertNil(err) + t.Assert(v.String(), "") + }) } func Test_Model_FieldsExStruct(t *testing.T) { - table := createTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int `orm:"id" json:"id"` - Passport string `orm:"password" json:"pass_port"` - Password string `orm:"password" json:"password"` - NickName string `orm:"nickname" json:"nick__name"` - } - user := &User{ - Id: 1, - Passport: "111", - Password: "222", - NickName: "333", - } - r, err := db.Model(table).FieldsEx("create_time, password").OmitEmpty().Data(user).Insert() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 1) - }) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int `orm:"id" json:"id"` - Passport string `orm:"password" json:"pass_port"` - Password string `orm:"password" json:"password"` - NickName string `orm:"nickname" json:"nick__name"` - } - users := make([]*User, 0) - for i := 100; i < 110; i++ { - users = append(users, &User{ - Id: i, - Passport: fmt.Sprintf(`passport_%d`, i), - Password: fmt.Sprintf(`password_%d`, i), - NickName: fmt.Sprintf(`nickname_%d`, i), - }) - } - r, err := db.Model(table).FieldsEx("create_time, password"). - OmitEmpty(). - Batch(2). - Data(users). - Insert() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 10) - }) + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int `orm:"id" json:"id"` + Passport string `orm:"password" json:"pass_port"` + Password string `orm:"password" json:"password"` + NickName string `orm:"nickname" json:"nick__name"` + } + user := &User{ + Id: 1, + Passport: "111", + Password: "222", + NickName: "333", + } + r, err := db.Model(table).FieldsEx("create_time, password").OmitEmpty().Data(user).Insert() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int `orm:"id" json:"id"` + Passport string `orm:"password" json:"pass_port"` + Password string `orm:"password" json:"password"` + NickName string `orm:"nickname" json:"nick__name"` + } + users := make([]*User, 0) + for i := 100; i < 110; i++ { + users = append(users, &User{ + Id: i, + Passport: fmt.Sprintf(`passport_%d`, i), + Password: fmt.Sprintf(`password_%d`, i), + NickName: fmt.Sprintf(`nickname_%d`, i), + }) + } + r, err := db.Model(table).FieldsEx("create_time, password"). + OmitEmpty(). + Batch(2). + Data(users). + Insert() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 10) + }) } func Test_Model_OmitEmpty_Time(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int `orm:"id" json:"id"` - Passport string `orm:"password" json:"pass_port"` - Password string `orm:"password" json:"password"` - Time time.Time `orm:"create_time" ` - } - user := &User{ - Id: 1, - Passport: "111", - Password: "222", - Time: time.Time{}, - } - r, err := db.Model(table).OmitEmpty().Data(user).WherePri(1).Update() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 1) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int `orm:"id" json:"id"` + Passport string `orm:"password" json:"pass_port"` + Password string `orm:"password" json:"password"` + Time time.Time `orm:"create_time" ` + } + user := &User{ + Id: 1, + Passport: "111", + Password: "222", + Time: time.Time{}, + } + r, err := db.Model(table).OmitEmpty().Data(user).WherePri(1).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + }) } func Test_Result_Chunk(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table).Order("id asc").All() - t.AssertNil(err) - chunks := r.Chunk(3) - t.Assert(len(chunks), 4) - t.Assert(chunks[0][0]["id"].Int(), 1) - t.Assert(chunks[1][0]["id"].Int(), 4) - t.Assert(chunks[2][0]["id"].Int(), 7) - t.Assert(chunks[3][0]["id"].Int(), 10) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).Order("id asc").All() + t.AssertNil(err) + chunks := r.Chunk(3) + t.Assert(len(chunks), 4) + t.Assert(chunks[0][0]["id"].Int(), 1) + t.Assert(chunks[1][0]["id"].Int(), 4) + t.Assert(chunks[2][0]["id"].Int(), 7) + t.Assert(chunks[3][0]["id"].Int(), 10) + }) } func Test_Model_DryRun(t *testing.T) { - table := createInitTable() - defer dropTable(table) - db.SetDryRun(true) - defer db.SetDryRun(false) - - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["id"], 1) - }) - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table).Data("passport", "port_1").WherePri(1).Update() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 0) - }) + table := createInitTable() + defer dropTable(table) + db.SetDryRun(true) + defer db.SetDryRun(false) + + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["id"], 1) + }) + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).Data("passport", "port_1").WherePri(1).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 0) + }) } func Test_Model_Join_SubQuery(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - subQuery := fmt.Sprintf("select * from `%s`", table) - r, err := db.Model(table, "t1").Fields("t2.id").LeftJoin(subQuery, "t2", "t2.id=t1.id").Array() - t.AssertNil(err) - t.Assert(len(r), TableSize) - t.Assert(r[0], "1") - t.Assert(r[TableSize-1], TableSize) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + subQuery := fmt.Sprintf("select * from `%s`", table) + r, err := db.Model(table, "t1").Fields("t2.id").LeftJoin(subQuery, "t2", "t2.id=t1.id").Array() + t.AssertNil(err) + t.Assert(len(r), TableSize) + t.Assert(r[0], "1") + t.Assert(r[TableSize-1], TableSize) + }) } func Test_Model_Cache(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test1", - Force: false, - }).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_1") - - r, err := db.Model(table).Data("passport", "user_100").WherePri(1).Update() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 1) - - one, err = db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test1", - Force: false, - }).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_1") - - time.Sleep(time.Second * 2) - - one, err = db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test1", - Force: false, - }).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_100") - }) - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test2", - Force: false, - }).WherePri(2).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_2") - - r, err := db.Model(table).Data("passport", "user_200").Cache(gdb.CacheOption{ - Duration: -1, - Name: "test2", - Force: false, - }).WherePri(2).Update() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 1) - - one, err = db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test2", - Force: false, - }).WherePri(2).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_200") - }) - // transaction. - gtest.C(t, func(t *gtest.T) { - // make cache for id 3 - one, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test3", - Force: false, - }).WherePri(3).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_3") - - r, err := db.Model(table).Data("passport", "user_300").Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test3", - Force: false, - }).WherePri(3).Update() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 1) - - err = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error { - one, err := tx.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test3", - Force: false, - }).WherePri(3).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_300") - return nil - }) - t.AssertNil(err) - - one, err = db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test3", - Force: false, - }).WherePri(3).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_3") - }) - gtest.C(t, func(t *gtest.T) { - // make cache for id 4 - one, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test4", - Force: false, - }).WherePri(4).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_4") - - r, err := db.Model(table).Data("passport", "user_400").Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test3", - Force: false, - }).WherePri(4).Update() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 1) - - err = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error { - // Cache feature disabled. - one, err := tx.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test4", - Force: false, - }).WherePri(4).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_400") - // Update the cache. - r, err := tx.Model(table).Data("passport", "user_4000"). - Cache(gdb.CacheOption{ - Duration: -1, - Name: "test4", - Force: false, - }).WherePri(4).Update() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 1) - return nil - }) - t.AssertNil(err) - // Read from db. - one, err = db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test4", - Force: false, - }).WherePri(4).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_4000") - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test1", + Force: false, + }).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_1") + + r, err := db.Model(table).Data("passport", "user_100").WherePri(1).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + + one, err = db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test1", + Force: false, + }).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_1") + + time.Sleep(time.Second * 2) + + one, err = db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test1", + Force: false, + }).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_100") + }) + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test2", + Force: false, + }).WherePri(2).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_2") + + r, err := db.Model(table).Data("passport", "user_200").Cache(gdb.CacheOption{ + Duration: -1, + Name: "test2", + Force: false, + }).WherePri(2).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + + one, err = db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test2", + Force: false, + }).WherePri(2).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_200") + }) + // transaction. + gtest.C(t, func(t *gtest.T) { + // make cache for id 3 + one, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test3", + Force: false, + }).WherePri(3).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_3") + + r, err := db.Model(table).Data("passport", "user_300").Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test3", + Force: false, + }).WherePri(3).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + + err = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error { + one, err := tx.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test3", + Force: false, + }).WherePri(3).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_300") + return nil + }) + t.AssertNil(err) + + one, err = db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test3", + Force: false, + }).WherePri(3).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_3") + }) + gtest.C(t, func(t *gtest.T) { + // make cache for id 4 + one, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test4", + Force: false, + }).WherePri(4).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_4") + + r, err := db.Model(table).Data("passport", "user_400").Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test3", + Force: false, + }).WherePri(4).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + + err = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error { + // Cache feature disabled. + one, err := tx.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test4", + Force: false, + }).WherePri(4).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_400") + // Update the cache. + r, err := tx.Model(table).Data("passport", "user_4000"). + Cache(gdb.CacheOption{ + Duration: -1, + Name: "test4", + Force: false, + }).WherePri(4).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + return nil + }) + t.AssertNil(err) + // Read from db. + one, err = db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test4", + Force: false, + }).WherePri(4).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_4000") + }) } func Test_Model_Having(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id > 1").Having("id > 8").All() - t.AssertNil(err) - t.Assert(len(all), 2) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id > 1").Having("id > ?", 8).All() - t.AssertNil(err) - t.Assert(len(all), 2) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id > ?", 1).Having("id > ?", 8).All() - t.AssertNil(err) - t.Assert(len(all), 2) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id > ?", 1).Having("id", 8).All() - t.AssertNil(err) - t.Assert(len(all), 1) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id > 1").Having("id > 8").All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id > 1").Having("id > ?", 8).All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id > ?", 1).Having("id > ?", 8).All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id > ?", 1).Having("id", 8).All() + t.AssertNil(err) + t.Assert(len(all), 1) + }) } func Test_Model_Distinct(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table, "t").Fields("distinct t.id").Where("id > 1").Having("id > 8").All() - t.AssertNil(err) - t.Assert(len(all), 2) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id > 1").Distinct().Count() - t.AssertNil(err) - t.Assert(count, int64(9)) - }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table, "t").Fields("distinct t.id").Where("id > 1").Having("id > 8").All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id > 1").Distinct().Count() + t.AssertNil(err) + t.Assert(count, int64(9)) + }) } func Test_Model_Min_Max(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table, "t").Fields("min(t.id)").Where("id > 1").Value() - t.AssertNil(err) - t.Assert(value.Int(), 2) - }) - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table, "t").Fields("max(t.id)").Where("id > 1").Value() - t.AssertNil(err) - t.Assert(value.Int(), 10) - }) + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table, "t").Fields("min(t.id)").Where("id > 1").Value() + t.AssertNil(err) + t.Assert(value.Int(), 2) + }) + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table, "t").Fields("max(t.id)").Where("id > 1").Value() + t.AssertNil(err) + t.Assert(value.Int(), 10) + }) } func Test_Model_Fields_AutoMapping(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).Fields("ID").Where("id", 2).Value() - t.AssertNil(err) - t.Assert(value.Int(), 2) - }) - - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).Fields("NICK_NAME").Where("id", 2).Value() - t.AssertNil(err) - t.Assert(value.String(), "name_2") - }) - // Map - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Fields(g.Map{ - "ID": 1, - "NICK_NAME": 1, - }).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 2) - t.Assert(one["id"], 2) - t.Assert(one["nickname"], "name_2") - }) - // Struct - gtest.C(t, func(t *gtest.T) { - type T struct { - ID int - NICKNAME int - } - one, err := db.Model(table).Fields(&T{ - ID: 0, - NICKNAME: 0, - }).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 2) - t.Assert(one["id"], 2) - t.Assert(one["nickname"], "name_2") - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Fields("ID").Where("id", 2).Value() + t.AssertNil(err) + t.Assert(value.Int(), 2) + }) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Fields("NICK_NAME").Where("id", 2).Value() + t.AssertNil(err) + t.Assert(value.String(), "name_2") + }) + // Map + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Fields(g.Map{ + "ID": 1, + "NICK_NAME": 1, + }).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["id"], 2) + t.Assert(one["nickname"], "name_2") + }) + // Struct + gtest.C(t, func(t *gtest.T) { + type T struct { + ID int + NICKNAME int + } + one, err := db.Model(table).Fields(&T{ + ID: 0, + NICKNAME: 0, + }).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["id"], 2) + t.Assert(one["nickname"], "name_2") + }) } func Test_Model_FieldsEx_AutoMapping(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - // "id": i, - // "passport": fmt.Sprintf(`user_%d`, i), - // "password": fmt.Sprintf(`pass_%d`, i), - // "nickname": fmt.Sprintf(`name_%d`, i), - // "create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(), - - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).FieldsEx("create_date, Passport, Password, NickName, CreateTime").Where("id", 2).Value() - t.AssertNil(err) - t.Assert(value.Int(), 2) - }) - - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).FieldsEx("create_date, ID, Passport, Password, CreateTime").Where("id", 2).Value() - t.AssertNil(err) - t.Assert(value.String(), "name_2") - }) - // Map - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).FieldsEx(g.Map{ - "Passport": 1, - "Password": 1, - "CreateTime": 1, - }).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 3) - t.Assert(one["id"], 2) - t.Assert(one["nickname"], "name_2") - }) - // Struct - gtest.C(t, func(t *gtest.T) { - type T struct { - Passport int - Password int - CreateTime int - } - one, err := db.Model(table).FieldsEx(&T{ - Passport: 0, - Password: 0, - CreateTime: 0, - }).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 3) - t.Assert(one["id"], 2) - t.Assert(one["nickname"], "name_2") - }) + table := createInitTable() + defer dropTable(table) + + // "id": i, + // "passport": fmt.Sprintf(`user_%d`, i), + // "password": fmt.Sprintf(`pass_%d`, i), + // "nickname": fmt.Sprintf(`name_%d`, i), + // "create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(), + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).FieldsEx("create_date, Passport, Password, NickName, CreateTime").Where("id", 2).Value() + t.AssertNil(err) + t.Assert(value.Int(), 2) + }) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).FieldsEx("create_date, ID, Passport, Password, CreateTime").Where("id", 2).Value() + t.AssertNil(err) + t.Assert(value.String(), "name_2") + }) + // Map + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).FieldsEx(g.Map{ + "Passport": 1, + "Password": 1, + "CreateTime": 1, + }).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 3) + t.Assert(one["id"], 2) + t.Assert(one["nickname"], "name_2") + }) + // Struct + gtest.C(t, func(t *gtest.T) { + type T struct { + Passport int + Password int + CreateTime int + } + one, err := db.Model(table).FieldsEx(&T{ + Passport: 0, + Password: 0, + CreateTime: 0, + }).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 3) + t.Assert(one["id"], 2) + t.Assert(one["nickname"], "name_2") + }) } func Test_Model_Fields_Struct(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - type A struct { - Passport string - Password string - } - type B struct { - A - NickName string - } - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Fields(A{}).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 2) - t.Assert(one["passport"], "user_2") - t.Assert(one["password"], "pass_2") - }) - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Fields(&A{}).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 2) - t.Assert(one["passport"], "user_2") - t.Assert(one["password"], "pass_2") - }) - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Fields(B{}).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 3) - t.Assert(one["passport"], "user_2") - t.Assert(one["password"], "pass_2") - t.Assert(one["nickname"], "name_2") - }) - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Fields(&B{}).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 3) - t.Assert(one["passport"], "user_2") - t.Assert(one["password"], "pass_2") - t.Assert(one["nickname"], "name_2") - }) + table := createInitTable() + defer dropTable(table) + + type A struct { + Passport string + Password string + } + type B struct { + A + NickName string + } + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Fields(A{}).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["passport"], "user_2") + t.Assert(one["password"], "pass_2") + }) + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Fields(&A{}).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["passport"], "user_2") + t.Assert(one["password"], "pass_2") + }) + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Fields(B{}).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 3) + t.Assert(one["passport"], "user_2") + t.Assert(one["password"], "pass_2") + t.Assert(one["nickname"], "name_2") + }) + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Fields(&B{}).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 3) + t.Assert(one["passport"], "user_2") + t.Assert(one["password"], "pass_2") + t.Assert(one["nickname"], "name_2") + }) } func Test_Model_NullField(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport *string - } - data := g.Map{ - "id": 1, - "passport": nil, - } - result, err := db.Model(table).Data(data).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - - var user *User - err = one.Struct(&user) - t.AssertNil(err) - t.Assert(user.Id, data["id"]) - t.Assert(user.Passport, data["passport"]) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport *string + } + data := g.Map{ + "id": 1, + "passport": nil, + } + result, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + + var user *User + err = one.Struct(&user) + t.AssertNil(err) + t.Assert(user.Id, data["id"]) + t.Assert(user.Passport, data["passport"]) + }) } func Test_Model_Empty_Slice_Argument(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Where(`id`, g.Slice{}).All() - t.AssertNil(err) - t.Assert(len(result), 0) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Where(`id in(?)`, g.Slice{}).All() - t.AssertNil(err) - t.Assert(len(result), 0) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(`id`, g.Slice{}).All() + t.AssertNil(err) + t.Assert(len(result), 0) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(`id in(?)`, g.Slice{}).All() + t.AssertNil(err) + t.Assert(len(result), 0) + }) } func Test_Model_HasTable(t *testing.T) { - table := createTable() - defer dropTable(table) + table := createTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - t.AssertNil(db.GetCore().ClearCacheAll(ctx)) - result, err := db.GetCore().HasTable(table) - t.Assert(result, true) - t.AssertNil(err) - }) + gtest.C(t, func(t *gtest.T) { + t.AssertNil(db.GetCore().ClearCacheAll(ctx)) + result, err := db.GetCore().HasTable(table) + t.Assert(result, true) + t.AssertNil(err) + }) - gtest.C(t, func(t *gtest.T) { - t.AssertNil(db.GetCore().ClearCacheAll(ctx)) - result, err := db.GetCore().HasTable("table12321") - t.Assert(result, false) - t.AssertNil(err) - }) + gtest.C(t, func(t *gtest.T) { + t.AssertNil(db.GetCore().ClearCacheAll(ctx)) + result, err := db.GetCore().HasTable("table12321") + t.Assert(result, false) + t.AssertNil(err) + }) } func Test_Model_HasField(t *testing.T) { - table := createTable() - defer dropTable(table) + table := createTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).HasField("id") - t.Assert(result, true) - t.AssertNil(err) - }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).HasField("id") + t.Assert(result, true) + t.AssertNil(err) + }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).HasField("id123") - t.Assert(result, false) - t.AssertNil(err) - }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).HasField("id123") + t.Assert(result, false) + t.AssertNil(err) + }) } func createTableForTimeZoneTest() string { - tableName := "user_" + gtime.Now().TimestampNanoStr() - if _, err := db.Exec(ctx, fmt.Sprintf(` + tableName := "user_" + gtime.Now().TimestampNanoStr() + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE %s ( id int(10) unsigned NOT NULL AUTO_INCREMENT, passport varchar(45) NULL, @@ -2519,698 +2521,698 @@ func createTableForTimeZoneTest() string { PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; `, tableName, - )); err != nil { - gtest.Fatal(err) - } - return tableName + )); err != nil { + gtest.Fatal(err) + } + return tableName } // https://github.com/gogf/gf/issues/1012 func Test_TimeZoneInsert(t *testing.T) { - tableName := createTableForTimeZoneTest() - defer dropTable(tableName) - - tokyoLoc, err := time.LoadLocation("Asia/Tokyo") - gtest.AssertNil(err) - - CreateTime := "2020-11-22 12:23:45" - UpdateTime := "2020-11-22 13:23:46" - DeleteTime := "2020-11-22 14:23:47" - type User struct { - Id int `json:"id"` - CreatedAt *gtime.Time `json:"created_at"` - UpdatedAt gtime.Time `json:"updated_at"` - DeletedAt time.Time `json:"deleted_at"` - } - t1, _ := time.ParseInLocation("2006-01-02 15:04:05", CreateTime, tokyoLoc) - t2, _ := time.ParseInLocation("2006-01-02 15:04:05", UpdateTime, tokyoLoc) - t3, _ := time.ParseInLocation("2006-01-02 15:04:05", DeleteTime, tokyoLoc) - u := &User{ - Id: 1, - CreatedAt: gtime.New(t1.UTC()), - UpdatedAt: *gtime.New(t2.UTC()), - DeletedAt: t3.UTC(), - } - - gtest.C(t, func(t *gtest.T) { - _, err = db.Model(tableName).Unscoped().Insert(u) - t.AssertNil(err) - userEntity := &User{} - err = db.Model(tableName).Where("id", 1).Unscoped().Scan(&userEntity) - t.AssertNil(err) - t.Assert(userEntity.CreatedAt.String(), "2020-11-22 11:23:45") - t.Assert(userEntity.UpdatedAt.String(), "2020-11-22 12:23:46") - t.Assert(gtime.NewFromTime(userEntity.DeletedAt).String(), "2020-11-22 13:23:47") - }) + tableName := createTableForTimeZoneTest() + defer dropTable(tableName) + + tokyoLoc, err := time.LoadLocation("Asia/Tokyo") + gtest.AssertNil(err) + + CreateTime := "2020-11-22 12:23:45" + UpdateTime := "2020-11-22 13:23:46" + DeleteTime := "2020-11-22 14:23:47" + type User struct { + Id int `json:"id"` + CreatedAt *gtime.Time `json:"created_at"` + UpdatedAt gtime.Time `json:"updated_at"` + DeletedAt time.Time `json:"deleted_at"` + } + t1, _ := time.ParseInLocation("2006-01-02 15:04:05", CreateTime, tokyoLoc) + t2, _ := time.ParseInLocation("2006-01-02 15:04:05", UpdateTime, tokyoLoc) + t3, _ := time.ParseInLocation("2006-01-02 15:04:05", DeleteTime, tokyoLoc) + u := &User{ + Id: 1, + CreatedAt: gtime.New(t1.UTC()), + UpdatedAt: *gtime.New(t2.UTC()), + DeletedAt: t3.UTC(), + } + + gtest.C(t, func(t *gtest.T) { + _, err = db.Model(tableName).Unscoped().Insert(u) + t.AssertNil(err) + userEntity := &User{} + err = db.Model(tableName).Where("id", 1).Unscoped().Scan(&userEntity) + t.AssertNil(err) + t.Assert(userEntity.CreatedAt.String(), "2020-11-22 11:23:45") + t.Assert(userEntity.UpdatedAt.String(), "2020-11-22 12:23:46") + t.Assert(gtime.NewFromTime(userEntity.DeletedAt).String(), "2020-11-22 13:23:47") + }) } func Test_Model_Fields_Map_Struct(t *testing.T) { - table := createInitTable() - defer dropTable(table) - // map - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Fields(g.Map{ - "ID": 1, - "PASSPORT": 1, - "NONE_EXIST": 1, - }).Where("id", 1).One() - t.AssertNil(err) - t.Assert(len(result), 2) - t.Assert(result["id"], 1) - t.Assert(result["passport"], "user_1") - }) - // struct - gtest.C(t, func(t *gtest.T) { - type A struct { - ID int - PASSPORT string - XXX_TYPE int - } - a := A{} - err := db.Model(table).Fields(a).Where("id", 1).Scan(&a) - t.AssertNil(err) - t.Assert(a.ID, 1) - t.Assert(a.PASSPORT, "user_1") - t.Assert(a.XXX_TYPE, 0) - }) - // *struct - gtest.C(t, func(t *gtest.T) { - type A struct { - ID int - PASSPORT string - XXX_TYPE int - } - var a *A - err := db.Model(table).Fields(a).Where("id", 1).Scan(&a) - t.AssertNil(err) - t.Assert(a.ID, 1) - t.Assert(a.PASSPORT, "user_1") - t.Assert(a.XXX_TYPE, 0) - }) - // **struct - gtest.C(t, func(t *gtest.T) { - type A struct { - ID int - PASSPORT string - XXX_TYPE int - } - var a *A - err := db.Model(table).Fields(&a).Where("id", 1).Scan(&a) - t.AssertNil(err) - t.Assert(a.ID, 1) - t.Assert(a.PASSPORT, "user_1") - t.Assert(a.XXX_TYPE, 0) - }) + table := createInitTable() + defer dropTable(table) + // map + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Fields(g.Map{ + "ID": 1, + "PASSPORT": 1, + "NONE_EXIST": 1, + }).Where("id", 1).One() + t.AssertNil(err) + t.Assert(len(result), 2) + t.Assert(result["id"], 1) + t.Assert(result["passport"], "user_1") + }) + // struct + gtest.C(t, func(t *gtest.T) { + type A struct { + ID int + PASSPORT string + XXX_TYPE int + } + a := A{} + err := db.Model(table).Fields(a).Where("id", 1).Scan(&a) + t.AssertNil(err) + t.Assert(a.ID, 1) + t.Assert(a.PASSPORT, "user_1") + t.Assert(a.XXX_TYPE, 0) + }) + // *struct + gtest.C(t, func(t *gtest.T) { + type A struct { + ID int + PASSPORT string + XXX_TYPE int + } + var a *A + err := db.Model(table).Fields(a).Where("id", 1).Scan(&a) + t.AssertNil(err) + t.Assert(a.ID, 1) + t.Assert(a.PASSPORT, "user_1") + t.Assert(a.XXX_TYPE, 0) + }) + // **struct + gtest.C(t, func(t *gtest.T) { + type A struct { + ID int + PASSPORT string + XXX_TYPE int + } + var a *A + err := db.Model(table).Fields(&a).Where("id", 1).Scan(&a) + t.AssertNil(err) + t.Assert(a.ID, 1) + t.Assert(a.PASSPORT, "user_1") + t.Assert(a.XXX_TYPE, 0) + }) } func Test_Model_Min_Max_Avg_Sum(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Min("id") - t.AssertNil(err) - t.Assert(result, 1) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Max("id") - t.AssertNil(err) - t.Assert(result, TableSize) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Avg("id") - t.AssertNil(err) - t.Assert(result, 5.5) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Sum("id") - t.AssertNil(err) - t.Assert(result, 55) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Min("id") + t.AssertNil(err) + t.Assert(result, 1) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Max("id") + t.AssertNil(err) + t.Assert(result, TableSize) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Avg("id") + t.AssertNil(err) + t.Assert(result, 5.5) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Sum("id") + t.AssertNil(err) + t.Assert(result, 55) + }) } func Test_Model_CountColumn(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).CountColumn("id") - t.AssertNil(err) - t.Assert(result, TableSize) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).WhereIn("id", g.Slice{1, 2, 3}).CountColumn("id") - t.AssertNil(err) - t.Assert(result, 3) - }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).CountColumn("id") + t.AssertNil(err) + t.Assert(result, TableSize) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).WhereIn("id", g.Slice{1, 2, 3}).CountColumn("id") + t.AssertNil(err) + t.Assert(result, 3) + }) } func Test_Model_InsertAndGetId(t *testing.T) { - table := createTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - id, err := db.Model(table).Data(g.Map{ - "id": 1, - "passport": "user_1", - "password": "pass_1", - "nickname": "name_1", - }).InsertAndGetId() - t.AssertNil(err) - t.Assert(id, 1) - }) - gtest.C(t, func(t *gtest.T) { - id, err := db.Model(table).Data(g.Map{ - "passport": "user_2", - "password": "pass_2", - "nickname": "name_2", - }).InsertAndGetId() - t.AssertNil(err) - t.Assert(id, 2) - }) + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + id, err := db.Model(table).Data(g.Map{ + "id": 1, + "passport": "user_1", + "password": "pass_1", + "nickname": "name_1", + }).InsertAndGetId() + t.AssertNil(err) + t.Assert(id, 1) + }) + gtest.C(t, func(t *gtest.T) { + id, err := db.Model(table).Data(g.Map{ + "passport": "user_2", + "password": "pass_2", + "nickname": "name_2", + }).InsertAndGetId() + t.AssertNil(err) + t.Assert(id, 2) + }) } func Test_Model_Increment_Decrement(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Where("id", 1).Increment("id", 100) - t.AssertNil(err) - rows, _ := result.RowsAffected() - t.Assert(rows, 1) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Where("id", 101).Decrement("id", 10) - t.AssertNil(err) - rows, _ := result.RowsAffected() - t.Assert(rows, 1) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 91).Count() - t.AssertNil(err) - t.Assert(count, int64(1)) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("id", 1).Increment("id", 100) + t.AssertNil(err) + rows, _ := result.RowsAffected() + t.Assert(rows, 1) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("id", 101).Decrement("id", 10) + t.AssertNil(err) + rows, _ := result.RowsAffected() + t.Assert(rows, 1) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 91).Count() + t.AssertNil(err) + t.Assert(count, int64(1)) + }) } func Test_Model_OnDuplicate(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - // string type 1. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicate("passport,password").Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["password"], data["password"]) - t.Assert(one["nickname"], "name_1") - }) - - // string type 2. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicate("passport", "password").Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["password"], data["password"]) - t.Assert(one["nickname"], "name_1") - }) - - // slice. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicate(g.Slice{"passport", "password"}).Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["password"], data["password"]) - t.Assert(one["nickname"], "name_1") - }) - - // map. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicate(g.Map{ - "passport": "nickname", - "password": "nickname", - }).Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["nickname"]) - t.Assert(one["password"], data["nickname"]) - t.Assert(one["nickname"], "name_1") - }) - - // map+raw. - gtest.C(t, func(t *gtest.T) { - data := g.MapStrStr{ - "id": "1", - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicate(g.Map{ - "passport": gdb.Raw("CONCAT(VALUES(`passport`), '1')"), - "password": gdb.Raw("CONCAT(VALUES(`password`), '2')"), - }).Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]+"1") - t.Assert(one["password"], data["password"]+"2") - t.Assert(one["nickname"], "name_1") - }) + table := createInitTable() + defer dropTable(table) + + // string type 1. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicate("passport,password").Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["password"], data["password"]) + t.Assert(one["nickname"], "name_1") + }) + + // string type 2. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicate("passport", "password").Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["password"], data["password"]) + t.Assert(one["nickname"], "name_1") + }) + + // slice. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicate(g.Slice{"passport", "password"}).Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["password"], data["password"]) + t.Assert(one["nickname"], "name_1") + }) + + // map. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicate(g.Map{ + "passport": "nickname", + "password": "nickname", + }).Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["nickname"]) + t.Assert(one["password"], data["nickname"]) + t.Assert(one["nickname"], "name_1") + }) + + // map+raw. + gtest.C(t, func(t *gtest.T) { + data := g.MapStrStr{ + "id": "1", + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicate(g.Map{ + "passport": gdb.Raw("CONCAT(VALUES(`passport`), '1')"), + "password": gdb.Raw("CONCAT(VALUES(`password`), '2')"), + }).Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]+"1") + t.Assert(one["password"], data["password"]+"2") + t.Assert(one["nickname"], "name_1") + }) } func Test_Model_OnDuplicateEx(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - // string type 1. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicateEx("nickname,create_time").Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["password"], data["password"]) - t.Assert(one["nickname"], "name_1") - }) - - // string type 2. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicateEx("nickname", "create_time").Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["password"], data["password"]) - t.Assert(one["nickname"], "name_1") - }) - - // slice. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicateEx(g.Slice{"nickname", "create_time"}).Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["password"], data["password"]) - t.Assert(one["nickname"], "name_1") - }) - - // map. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicateEx(g.Map{ - "nickname": "nickname", - "create_time": "nickname", - }).Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["password"], data["password"]) - t.Assert(one["nickname"], "name_1") - }) + table := createInitTable() + defer dropTable(table) + + // string type 1. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicateEx("nickname,create_time").Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["password"], data["password"]) + t.Assert(one["nickname"], "name_1") + }) + + // string type 2. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicateEx("nickname", "create_time").Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["password"], data["password"]) + t.Assert(one["nickname"], "name_1") + }) + + // slice. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicateEx(g.Slice{"nickname", "create_time"}).Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["password"], data["password"]) + t.Assert(one["nickname"], "name_1") + }) + + // map. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicateEx(g.Map{ + "nickname": "nickname", + "create_time": "nickname", + }).Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["password"], data["password"]) + t.Assert(one["nickname"], "name_1") + }) } func Test_Model_Raw(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - all, err := db. - Raw(fmt.Sprintf("select * from %s where id in (?)", table), g.Slice{1, 5, 7, 8, 9, 10}). - WhereLT("id", 8). - WhereIn("id", g.Slice{1, 2, 3, 4, 5, 6, 7}). - OrderDesc("id"). - Limit(2). - All() - t.AssertNil(err) - t.Assert(len(all), 2) - t.Assert(all[0]["id"], 7) - t.Assert(all[1]["id"], 5) - }) - - gtest.C(t, func(t *gtest.T) { - count, err := db. - Raw(fmt.Sprintf("select * from %s where id in (?)", table), g.Slice{1, 5, 7, 8, 9, 10}). - WhereLT("id", 8). - WhereIn("id", g.Slice{1, 2, 3, 4, 5, 6, 7}). - OrderDesc("id"). - Limit(2). - Count() - t.AssertNil(err) - t.Assert(count, int64(6)) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + all, err := db. + Raw(fmt.Sprintf("select * from %s where id in (?)", table), g.Slice{1, 5, 7, 8, 9, 10}). + WhereLT("id", 8). + WhereIn("id", g.Slice{1, 2, 3, 4, 5, 6, 7}). + OrderDesc("id"). + Limit(2). + All() + t.AssertNil(err) + t.Assert(len(all), 2) + t.Assert(all[0]["id"], 7) + t.Assert(all[1]["id"], 5) + }) + + gtest.C(t, func(t *gtest.T) { + count, err := db. + Raw(fmt.Sprintf("select * from %s where id in (?)", table), g.Slice{1, 5, 7, 8, 9, 10}). + WhereLT("id", 8). + WhereIn("id", g.Slice{1, 2, 3, 4, 5, 6, 7}). + OrderDesc("id"). + Limit(2). + Count() + t.AssertNil(err) + t.Assert(count, int64(6)) + }) } func Test_Model_Handler(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - m := db.Model(table).Safe().Handler( - func(m *gdb.Model) *gdb.Model { - return m.Page(0, 3) - }, - func(m *gdb.Model) *gdb.Model { - return m.Where("id", g.Slice{1, 2, 3, 4, 5, 6}) - }, - func(m *gdb.Model) *gdb.Model { - return m.OrderDesc("id") - }, - ) - all, err := m.All() - t.AssertNil(err) - t.Assert(len(all), 3) - t.Assert(all[0]["id"], 6) - t.Assert(all[2]["id"], 4) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + m := db.Model(table).Safe().Handler( + func(m *gdb.Model) *gdb.Model { + return m.Page(0, 3) + }, + func(m *gdb.Model) *gdb.Model { + return m.Where("id", g.Slice{1, 2, 3, 4, 5, 6}) + }, + func(m *gdb.Model) *gdb.Model { + return m.OrderDesc("id") + }, + ) + all, err := m.All() + t.AssertNil(err) + t.Assert(len(all), 3) + t.Assert(all[0]["id"], 6) + t.Assert(all[2]["id"], 4) + }) } func Test_Model_FieldCount(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Fields("id").FieldCount("id", "total").Group("id").OrderAsc("id").All() - t.AssertNil(err) - t.Assert(len(all), TableSize) - t.Assert(all[0]["id"], 1) - t.Assert(all[0]["total"].Int(), 1) - }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Fields("id").FieldCount("id", "total").Group("id").OrderAsc("id").All() + t.AssertNil(err) + t.Assert(len(all), TableSize) + t.Assert(all[0]["id"], 1) + t.Assert(all[0]["total"].Int(), 1) + }) } func Test_Model_FieldMax(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Fields("id").FieldMax("id", "total").Group("id").OrderAsc("id").All() - t.AssertNil(err) - t.Assert(len(all), TableSize) - t.Assert(all[0]["id"], 1) - t.Assert(all[0]["total"].Int(), 1) - }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Fields("id").FieldMax("id", "total").Group("id").OrderAsc("id").All() + t.AssertNil(err) + t.Assert(len(all), TableSize) + t.Assert(all[0]["id"], 1) + t.Assert(all[0]["total"].Int(), 1) + }) } func Test_Model_FieldMin(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Fields("id").FieldMin("id", "total").Group("id").OrderAsc("id").All() - t.AssertNil(err) - t.Assert(len(all), TableSize) - t.Assert(all[0]["id"], 1) - t.Assert(all[0]["total"].Int(), 1) - }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Fields("id").FieldMin("id", "total").Group("id").OrderAsc("id").All() + t.AssertNil(err) + t.Assert(len(all), TableSize) + t.Assert(all[0]["id"], 1) + t.Assert(all[0]["total"].Int(), 1) + }) } func Test_Model_FieldAvg(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Fields("id").FieldAvg("id", "total").Group("id").OrderAsc("id").All() - t.AssertNil(err) - t.Assert(len(all), TableSize) - t.Assert(all[0]["id"], 1) - t.Assert(all[0]["total"].Int(), 1) - }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Fields("id").FieldAvg("id", "total").Group("id").OrderAsc("id").All() + t.AssertNil(err) + t.Assert(len(all), TableSize) + t.Assert(all[0]["id"], 1) + t.Assert(all[0]["total"].Int(), 1) + }) } func Test_Model_OmitEmptyWhere(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - // Basic type where. - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 0).Count() - t.AssertNil(err) - t.Assert(count, int64(0)) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).OmitEmptyWhere().Where("id", 0).Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).OmitEmptyWhere().Where("id", 0).Where("nickname", "").Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) - // Slice where. - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", g.Slice{1, 2, 3}).Count() - t.AssertNil(err) - t.Assert(count, int64(3)) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", g.Slice{}).Count() - t.AssertNil(err) - t.Assert(count, int64(0)) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).OmitEmptyWhere().Where("id", g.Slice{}).Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", g.Slice{}).OmitEmptyWhere().Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) - // Struct Where. - gtest.C(t, func(t *gtest.T) { - type Input struct { - Id []int - Name []string - } - count, err := db.Model(table).Where(Input{}).Count() - t.AssertNil(err) - t.Assert(count, int64(0)) - }) - gtest.C(t, func(t *gtest.T) { - type Input struct { - Id []int - Name []string - } - count, err := db.Model(table).Where(Input{}).OmitEmptyWhere().Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) - // Map Where. - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where(g.Map{ - "id": []int{}, - "nickname": []string{}, - }).Count() - t.AssertNil(err) - t.Assert(count, int64(0)) - }) - gtest.C(t, func(t *gtest.T) { - type Input struct { - Id []int - } - count, err := db.Model(table).Where(g.Map{ - "id": []int{}, - }).OmitEmptyWhere().Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) + table := createInitTable() + defer dropTable(table) + + // Basic type where. + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 0).Count() + t.AssertNil(err) + t.Assert(count, int64(0)) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).OmitEmptyWhere().Where("id", 0).Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).OmitEmptyWhere().Where("id", 0).Where("nickname", "").Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) + // Slice where. + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", g.Slice{1, 2, 3}).Count() + t.AssertNil(err) + t.Assert(count, int64(3)) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", g.Slice{}).Count() + t.AssertNil(err) + t.Assert(count, int64(0)) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).OmitEmptyWhere().Where("id", g.Slice{}).Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", g.Slice{}).OmitEmptyWhere().Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) + // Struct Where. + gtest.C(t, func(t *gtest.T) { + type Input struct { + Id []int + Name []string + } + count, err := db.Model(table).Where(Input{}).Count() + t.AssertNil(err) + t.Assert(count, int64(0)) + }) + gtest.C(t, func(t *gtest.T) { + type Input struct { + Id []int + Name []string + } + count, err := db.Model(table).Where(Input{}).OmitEmptyWhere().Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) + // Map Where. + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where(g.Map{ + "id": []int{}, + "nickname": []string{}, + }).Count() + t.AssertNil(err) + t.Assert(count, int64(0)) + }) + gtest.C(t, func(t *gtest.T) { + type Input struct { + Id []int + } + count, err := db.Model(table).Where(g.Map{ + "id": []int{}, + }).OmitEmptyWhere().Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) } // https://github.com/gogf/gf/issues/1387 func Test_Model_GTime_DefaultValue(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - Nickname string - CreateTime *gtime.Time - } - data := User{ - Id: 1, - Passport: "user_1", - Password: "pass_1", - Nickname: "name_1", - } - // Insert - _, err := db.Model(table).Data(data).Insert() - t.AssertNil(err) - - // Select - var ( - user *User - ) - err = db.Model(table).Scan(&user) - t.AssertNil(err) - t.Assert(user.Passport, data.Passport) - t.Assert(user.Password, data.Password) - t.Assert(user.CreateTime, data.CreateTime) - t.Assert(user.Nickname, data.Nickname) - - // Insert - user.Id = 2 - _, err = db.Model(table).Data(user).Insert() - t.AssertNil(err) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + Nickname string + CreateTime *gtime.Time + } + data := User{ + Id: 1, + Passport: "user_1", + Password: "pass_1", + Nickname: "name_1", + } + // Insert + _, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + + // Select + var ( + user *User + ) + err = db.Model(table).Scan(&user) + t.AssertNil(err) + t.Assert(user.Passport, data.Passport) + t.Assert(user.Password, data.Password) + t.Assert(user.CreateTime, data.CreateTime) + t.Assert(user.Nickname, data.Nickname) + + // Insert + user.Id = 2 + _, err = db.Model(table).Data(user).Insert() + t.AssertNil(err) + }) } // Using filter does 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.Model(table).Data(data).Insert() - t.AssertNil(err) - 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.Model(table).Data(data).Insert() - t.AssertNil(err) - n, _ := result.LastInsertId() - t.Assert(n, 2) - - t.Assert(data[0]["uid"], 1) - t.Assert(data[1]["uid"], 2) - }) + // 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.Model(table).Data(data).Insert() + t.AssertNil(err) + 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.Model(table).Data(data).Insert() + t.AssertNil(err) + n, _ := result.LastInsertId() + t.Assert(n, 2) + + t.Assert(data[0]["uid"], 1) + t.Assert(data[1]["uid"], 2) + }) } func Test_Model_Embedded_Filter(t *testing.T) { - table := createTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - type Base struct { - Id int - Uid int - CreateTime string - NoneExist string - } - type User struct { - Base - Passport string - Password string - Nickname string - } - result, err := db.Model(table).Data(User{ - Passport: "john-test", - Password: "123456", - Nickname: "John", - Base: Base{ - Id: 100, - Uid: 100, - CreateTime: gtime.Now().String(), - }, - }).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - - var user *User - err = db.Model(table).Fields(user).Where("id=100").Scan(&user) - t.AssertNil(err) - t.Assert(user.Passport, "john-test") - t.Assert(user.Id, 100) - }) + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type Base struct { + Id int + Uid int + CreateTime string + NoneExist string + } + type User struct { + Base + Passport string + Password string + Nickname string + } + result, err := db.Model(table).Data(User{ + Passport: "john-test", + Password: "123456", + Nickname: "John", + Base: Base{ + Id: 100, + Uid: 100, + CreateTime: gtime.Now().String(), + }, + }).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + + var user *User + err = db.Model(table).Fields(user).Where("id=100").Scan(&user) + t.AssertNil(err) + t.Assert(user.Passport, "john-test") + t.Assert(user.Id, 100) + }) } // This is no longer used as the filter feature is automatically enabled from GoFrame v1.16.0. @@ -3240,29 +3242,29 @@ func Test_Model_Embedded_Filter(t *testing.T) { // } func Test_Model_Fields_AutoFilterInJoinStatement(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - var err error - table1 := "user" - table2 := "score" - table3 := "info" - if _, err := db.Exec(ctx, fmt.Sprintf(` + gtest.C(t, func(t *gtest.T) { + var err error + table1 := "user" + table2 := "score" + table3 := "info" + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE IF NOT EXISTS %s ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(500) NOT NULL DEFAULT '', PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1; `, table1, - )); err != nil { - t.AssertNil(err) - } - defer dropTable(table1) - _, err = db.Model(table1).Insert(g.Map{ - "id": 1, - "name": "john", - }) - t.AssertNil(err) - - if _, err := db.Exec(ctx, fmt.Sprintf(` + )); err != nil { + t.AssertNil(err) + } + defer dropTable(table1) + _, err = db.Model(table1).Insert(g.Map{ + "id": 1, + "name": "john", + }) + t.AssertNil(err) + + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE IF NOT EXISTS %s ( id int(11) NOT NULL AUTO_INCREMENT, user_id int(11) NOT NULL DEFAULT 0, @@ -3270,18 +3272,18 @@ func Test_Model_Fields_AutoFilterInJoinStatement(t *testing.T) { PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1; `, table2, - )); err != nil { - t.AssertNil(err) - } - defer dropTable(table2) - _, err = db.Model(table2).Insert(g.Map{ - "id": 1, - "user_id": 1, - "number": "n", - }) - t.AssertNil(err) - - if _, err := db.Exec(ctx, fmt.Sprintf(` + )); err != nil { + t.AssertNil(err) + } + defer dropTable(table2) + _, err = db.Model(table2).Insert(g.Map{ + "id": 1, + "user_id": 1, + "number": "n", + }) + t.AssertNil(err) + + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE IF NOT EXISTS %s ( id int(11) NOT NULL AUTO_INCREMENT, user_id int(11) NOT NULL DEFAULT 0, @@ -3289,558 +3291,558 @@ func Test_Model_Fields_AutoFilterInJoinStatement(t *testing.T) { PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1; `, table3, - )); err != nil { - t.AssertNil(err) - } - defer dropTable(table3) - _, err = db.Model(table3).Insert(g.Map{ - "id": 1, - "user_id": 1, - "description": "brief", - }) - t.AssertNil(err) - - one, err := db.Model("user"). - Where("user.id", 1). - Fields("score.number,user.name"). - LeftJoin("score", "user.id=score.user_id"). - LeftJoin("info", "info.id=info.user_id"). - Order("user.id asc"). - One() - t.AssertNil(err) - t.Assert(len(one), 2) - t.Assert(one["name"].String(), "john") - t.Assert(one["number"].String(), "n") - - one, err = db.Model("user"). - LeftJoin("score", "user.id=score.user_id"). - LeftJoin("info", "info.id=info.user_id"). - Fields("score.number,user.name"). - One() - t.AssertNil(err) - t.Assert(len(one), 2) - t.Assert(one["name"].String(), "john") - t.Assert(one["number"].String(), "n") - }) + )); err != nil { + t.AssertNil(err) + } + defer dropTable(table3) + _, err = db.Model(table3).Insert(g.Map{ + "id": 1, + "user_id": 1, + "description": "brief", + }) + t.AssertNil(err) + + one, err := db.Model("user"). + Where("user.id", 1). + Fields("score.number,user.name"). + LeftJoin("score", "user.id=score.user_id"). + LeftJoin("info", "info.id=info.user_id"). + Order("user.id asc"). + One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["name"].String(), "john") + t.Assert(one["number"].String(), "n") + + one, err = db.Model("user"). + LeftJoin("score", "user.id=score.user_id"). + LeftJoin("info", "info.id=info.user_id"). + Fields("score.number,user.name"). + One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["name"].String(), "john") + t.Assert(one["number"].String(), "n") + }) } // https://github.com/gogf/gf/issues/1159 func Test_ScanList_NoRecreate_PtrAttribute(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - type S1 struct { - Id int - Name string - Age int - Score int - } - type S3 struct { - One *S1 - } - var ( - s []*S3 - err error - ) - r1 := gdb.Result{ - gdb.Record{ - "id": gvar.New(1), - "name": gvar.New("john"), - "age": gvar.New(16), - }, - gdb.Record{ - "id": gvar.New(2), - "name": gvar.New("smith"), - "age": gvar.New(18), - }, - } - err = r1.ScanList(&s, "One") - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - - r2 := gdb.Result{ - gdb.Record{ - "id": gvar.New(1), - "age": gvar.New(20), - }, - gdb.Record{ - "id": gvar.New(2), - "age": gvar.New(21), - }, - } - err = r2.ScanList(&s, "One", "One", "id:Id") - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 20) - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 21) - }) + gtest.C(t, func(t *gtest.T) { + type S1 struct { + Id int + Name string + Age int + Score int + } + type S3 struct { + One *S1 + } + var ( + s []*S3 + err error + ) + r1 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), + }, + gdb.Record{ + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), + }, + } + err = r1.ScanList(&s, "One") + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + + r2 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(1), + "age": gdb.NewValue(20), + }, + gdb.Record{ + "id": gdb.NewValue(2), + "age": gdb.NewValue(21), + }, + } + err = r2.ScanList(&s, "One", "One", "id:Id") + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 20) + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 21) + }) } // https://github.com/gogf/gf/issues/1159 func Test_ScanList_NoRecreate_StructAttribute(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - type S1 struct { - Id int - Name string - Age int - Score int - } - type S3 struct { - One S1 - } - var ( - s []*S3 - err error - ) - r1 := gdb.Result{ - gdb.Record{ - "id": gvar.New(1), - "name": gvar.New("john"), - "age": gvar.New(16), - }, - gdb.Record{ - "id": gvar.New(2), - "name": gvar.New("smith"), - "age": gvar.New(18), - }, - } - err = r1.ScanList(&s, "One") - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - - r2 := gdb.Result{ - gdb.Record{ - "id": gvar.New(1), - "age": gvar.New(20), - }, - gdb.Record{ - "id": gvar.New(2), - "age": gvar.New(21), - }, - } - err = r2.ScanList(&s, "One", "One", "id:Id") - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 20) - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 21) - }) + gtest.C(t, func(t *gtest.T) { + type S1 struct { + Id int + Name string + Age int + Score int + } + type S3 struct { + One S1 + } + var ( + s []*S3 + err error + ) + r1 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), + }, + gdb.Record{ + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), + }, + } + err = r1.ScanList(&s, "One") + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + + r2 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(1), + "age": gdb.NewValue(20), + }, + gdb.Record{ + "id": gdb.NewValue(2), + "age": gdb.NewValue(21), + }, + } + err = r2.ScanList(&s, "One", "One", "id:Id") + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 20) + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 21) + }) } // https://github.com/gogf/gf/issues/1159 func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - type S1 struct { - Id int - Name string - Age int - Score int - } - type S2 struct { - Id int - Pid int - Name string - Age int - Score int - } - type S3 struct { - One *S1 - Many []*S2 - } - var ( - s []*S3 - err error - ) - r1 := gdb.Result{ - gdb.Record{ - "id": gvar.New(1), - "name": gvar.New("john"), - "age": gvar.New(16), - }, - gdb.Record{ - "id": gvar.New(2), - "name": gvar.New("smith"), - "age": gvar.New(18), - }, - } - err = r1.ScanList(&s, "One") - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - - r2 := gdb.Result{ - gdb.Record{ - "id": gvar.New(100), - "pid": gvar.New(1), - "age": gvar.New(30), - "name": gvar.New("john"), - }, - gdb.Record{ - "id": gvar.New(200), - "pid": gvar.New(1), - "age": gvar.New(31), - "name": gvar.New("smith"), - }, - } - err = r2.ScanList(&s, "Many", "One", "pid:Id") - // fmt.Printf("%+v", err) - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(len(s[0].Many), 2) - t.Assert(s[0].Many[0].Name, "john") - t.Assert(s[0].Many[0].Age, 30) - t.Assert(s[0].Many[1].Name, "smith") - t.Assert(s[0].Many[1].Age, 31) - - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - t.Assert(len(s[1].Many), 0) - - r3 := gdb.Result{ - gdb.Record{ - "id": gvar.New(100), - "pid": gvar.New(1), - "age": gvar.New(40), - }, - gdb.Record{ - "id": gvar.New(200), - "pid": gvar.New(1), - "age": gvar.New(41), - }, - } - err = r3.ScanList(&s, "Many", "One", "pid:Id") - // fmt.Printf("%+v", err) - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(len(s[0].Many), 2) - t.Assert(s[0].Many[0].Name, "john") - t.Assert(s[0].Many[0].Age, 40) - t.Assert(s[0].Many[1].Name, "smith") - t.Assert(s[0].Many[1].Age, 41) - - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - t.Assert(len(s[1].Many), 0) - }) + gtest.C(t, func(t *gtest.T) { + type S1 struct { + Id int + Name string + Age int + Score int + } + type S2 struct { + Id int + Pid int + Name string + Age int + Score int + } + type S3 struct { + One *S1 + Many []*S2 + } + var ( + s []*S3 + err error + ) + r1 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), + }, + gdb.Record{ + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), + }, + } + err = r1.ScanList(&s, "One") + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + + r2 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(30), + "name": gdb.NewValue("john"), + }, + gdb.Record{ + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(31), + "name": gdb.NewValue("smith"), + }, + } + err = r2.ScanList(&s, "Many", "One", "pid:Id") + // fmt.Printf("%+v", err) + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(len(s[0].Many), 2) + t.Assert(s[0].Many[0].Name, "john") + t.Assert(s[0].Many[0].Age, 30) + t.Assert(s[0].Many[1].Name, "smith") + t.Assert(s[0].Many[1].Age, 31) + + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + t.Assert(len(s[1].Many), 0) + + r3 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(40), + }, + gdb.Record{ + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(41), + }, + } + err = r3.ScanList(&s, "Many", "One", "pid:Id") + // fmt.Printf("%+v", err) + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(len(s[0].Many), 2) + t.Assert(s[0].Many[0].Name, "john") + t.Assert(s[0].Many[0].Age, 40) + t.Assert(s[0].Many[1].Name, "smith") + t.Assert(s[0].Many[1].Age, 41) + + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + t.Assert(len(s[1].Many), 0) + }) } // https://github.com/gogf/gf/issues/1159 func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - type S1 struct { - Id int - Name string - Age int - Score int - } - type S2 struct { - Id int - Pid int - Name string - Age int - Score int - } - type S3 struct { - One S1 - Many []S2 - } - var ( - s []S3 - err error - ) - r1 := gdb.Result{ - gdb.Record{ - "id": gvar.New(1), - "name": gvar.New("john"), - "age": gvar.New(16), - }, - gdb.Record{ - "id": gvar.New(2), - "name": gvar.New("smith"), - "age": gvar.New(18), - }, - } - err = r1.ScanList(&s, "One") - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - - r2 := gdb.Result{ - gdb.Record{ - "id": gvar.New(100), - "pid": gvar.New(1), - "age": gvar.New(30), - "name": gvar.New("john"), - }, - gdb.Record{ - "id": gvar.New(200), - "pid": gvar.New(1), - "age": gvar.New(31), - "name": gvar.New("smith"), - }, - } - err = r2.ScanList(&s, "Many", "One", "pid:Id") - // fmt.Printf("%+v", err) - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(len(s[0].Many), 2) - t.Assert(s[0].Many[0].Name, "john") - t.Assert(s[0].Many[0].Age, 30) - t.Assert(s[0].Many[1].Name, "smith") - t.Assert(s[0].Many[1].Age, 31) - - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - t.Assert(len(s[1].Many), 0) - - r3 := gdb.Result{ - gdb.Record{ - "id": gvar.New(100), - "pid": gvar.New(1), - "age": gvar.New(40), - }, - gdb.Record{ - "id": gvar.New(200), - "pid": gvar.New(1), - "age": gvar.New(41), - }, - } - err = r3.ScanList(&s, "Many", "One", "pid:Id") - // fmt.Printf("%+v", err) - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(len(s[0].Many), 2) - t.Assert(s[0].Many[0].Name, "john") - t.Assert(s[0].Many[0].Age, 40) - t.Assert(s[0].Many[1].Name, "smith") - t.Assert(s[0].Many[1].Age, 41) - - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - t.Assert(len(s[1].Many), 0) - }) + gtest.C(t, func(t *gtest.T) { + type S1 struct { + Id int + Name string + Age int + Score int + } + type S2 struct { + Id int + Pid int + Name string + Age int + Score int + } + type S3 struct { + One S1 + Many []S2 + } + var ( + s []S3 + err error + ) + r1 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), + }, + gdb.Record{ + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), + }, + } + err = r1.ScanList(&s, "One") + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + + r2 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(30), + "name": gdb.NewValue("john"), + }, + gdb.Record{ + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(31), + "name": gdb.NewValue("smith"), + }, + } + err = r2.ScanList(&s, "Many", "One", "pid:Id") + // fmt.Printf("%+v", err) + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(len(s[0].Many), 2) + t.Assert(s[0].Many[0].Name, "john") + t.Assert(s[0].Many[0].Age, 30) + t.Assert(s[0].Many[1].Name, "smith") + t.Assert(s[0].Many[1].Age, 31) + + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + t.Assert(len(s[1].Many), 0) + + r3 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(40), + }, + gdb.Record{ + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(41), + }, + } + err = r3.ScanList(&s, "Many", "One", "pid:Id") + // fmt.Printf("%+v", err) + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(len(s[0].Many), 2) + t.Assert(s[0].Many[0].Name, "john") + t.Assert(s[0].Many[0].Age, 40) + t.Assert(s[0].Many[1].Name, "smith") + t.Assert(s[0].Many[1].Age, 41) + + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + t.Assert(len(s[1].Many), 0) + }) } func TestResult_Structs1(t *testing.T) { - type A struct { - Id int `orm:"id"` - } - type B struct { - *A - Name string - } - gtest.C(t, func(t *gtest.T) { - r := gdb.Result{ - gdb.Record{"id": gvar.New(nil), "name": gvar.New("john")}, - gdb.Record{"id": gvar.New(1), "name": gvar.New("smith")}, - } - array := make([]*B, 2) - err := r.Structs(&array) - t.AssertNil(err) - t.Assert(array[0].Id, 0) - t.Assert(array[1].Id, 1) - t.Assert(array[0].Name, "john") - t.Assert(array[1].Name, "smith") - }) + type A struct { + Id int `orm:"id"` + } + type B struct { + *A + Name string + } + gtest.C(t, func(t *gtest.T) { + r := gdb.Result{ + gdb.Record{"id": gdb.NewValue(nil), "name": gdb.NewValue("john")}, + gdb.Record{"id": gdb.NewValue(1), "name": gdb.NewValue("smith")}, + } + array := make([]*B, 2) + err := r.Structs(&array) + t.AssertNil(err) + t.Assert(array[0].Id, 0) + t.Assert(array[1].Id, 1) + t.Assert(array[0].Name, "john") + t.Assert(array[1].Name, "smith") + }) } func Test_Builder_OmitEmptyWhere(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 1).Count() - t.AssertNil(err) - t.Assert(count, int64(1)) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 0).OmitEmptyWhere().Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) - gtest.C(t, func(t *gtest.T) { - builder := db.Model(table).OmitEmptyWhere().Builder() - count, err := db.Model(table).Where( - builder.Where("id", 0), - ).Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 1).Count() + t.AssertNil(err) + t.Assert(count, int64(1)) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 0).OmitEmptyWhere().Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) + gtest.C(t, func(t *gtest.T) { + builder := db.Model(table).OmitEmptyWhere().Builder() + count, err := db.Model(table).Where( + builder.Where("id", 0), + ).Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) } func Test_Scan_Nil_Result_Error(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - type S struct { - Id int - Name string - Age int - Score int - } - gtest.C(t, func(t *gtest.T) { - var s *S - err := db.Model(table).Where("id", 1).Scan(&s) - t.AssertNil(err) - t.Assert(s.Id, 1) - }) - gtest.C(t, func(t *gtest.T) { - var s *S - err := db.Model(table).Where("id", 100).Scan(&s) - t.AssertNil(err) - t.Assert(s, nil) - }) - gtest.C(t, func(t *gtest.T) { - var s S - err := db.Model(table).Where("id", 100).Scan(&s) - t.Assert(err, sql.ErrNoRows) - }) - gtest.C(t, func(t *gtest.T) { - var ss []*S - err := db.Model(table).Scan(&ss) - t.AssertNil(err) - t.Assert(len(ss), TableSize) - }) - // If the result is empty, it returns error. - gtest.C(t, func(t *gtest.T) { - var ss = make([]*S, 10) - err := db.Model(table).WhereGT("id", 100).Scan(&ss) - t.Assert(err, sql.ErrNoRows) - }) + table := createInitTable() + defer dropTable(table) + + type S struct { + Id int + Name string + Age int + Score int + } + gtest.C(t, func(t *gtest.T) { + var s *S + err := db.Model(table).Where("id", 1).Scan(&s) + t.AssertNil(err) + t.Assert(s.Id, 1) + }) + gtest.C(t, func(t *gtest.T) { + var s *S + err := db.Model(table).Where("id", 100).Scan(&s) + t.AssertNil(err) + t.Assert(s, nil) + }) + gtest.C(t, func(t *gtest.T) { + var s S + err := db.Model(table).Where("id", 100).Scan(&s) + t.Assert(err, sql.ErrNoRows) + }) + gtest.C(t, func(t *gtest.T) { + var ss []*S + err := db.Model(table).Scan(&ss) + t.AssertNil(err) + t.Assert(len(ss), TableSize) + }) + // If the result is empty, it returns error. + gtest.C(t, func(t *gtest.T) { + var ss = make([]*S, 10) + err := db.Model(table).WhereGT("id", 100).Scan(&ss) + t.Assert(err, sql.ErrNoRows) + }) } func Test_Model_FixGdbJoin(t *testing.T) { - array := gstr.SplitAndTrim(gtest.DataContent(`fix_gdb_join.sql`), ";") - for _, v := range array { - if _, err := db.Exec(ctx, v); err != nil { - gtest.Error(err) - } - } - defer dropTable(`common_resource`) - defer dropTable(`managed_resource`) - defer dropTable(`rules_template`) - defer dropTable(`resource_mark`) - gtest.C(t, func(t *gtest.T) { - t.AssertNil(db.GetCore().ClearCacheAll(ctx)) - sqlSlice, err := gdb.CatchSQL(ctx, func(ctx context.Context) error { - orm := db.Model(`managed_resource`).Ctx(ctx). - LeftJoinOnField(`common_resource`, `resource_id`). - LeftJoinOnFields(`resource_mark`, `resource_mark_id`, `=`, `id`). - LeftJoinOnFields(`rules_template`, `rule_template_id`, `=`, `template_id`). - FieldsPrefix( - `managed_resource`, - "resource_id", "user", "status", "status_message", "safe_publication", "rule_template_id", - "created_at", "comments", "expired_at", "resource_mark_id", "instance_id", "resource_name", - "pay_mode"). - FieldsPrefix(`resource_mark`, "mark_name", "color"). - FieldsPrefix(`rules_template`, "name"). - FieldsPrefix(`common_resource`, `src_instance_id`, "database_kind", "source_type", "ip", "port") - all, err := orm.OrderAsc("src_instance_id").All() - t.Assert(len(all), 4) - t.Assert(all[0]["pay_mode"], 1) - t.Assert(all[0]["src_instance_id"], 2) - t.Assert(all[3]["instance_id"], "dmcins-jxy0x75m") - t.Assert(all[3]["src_instance_id"], "vdb-6b6m3u1u") - t.Assert(all[3]["resource_mark_id"], "11") - return err - }) - t.AssertNil(err) - - t.Assert(gtest.DataContent(`fix_gdb_join_expect.sql`), sqlSlice[len(sqlSlice)-1]) - }) + array := gstr.SplitAndTrim(gtest.DataContent(`fix_gdb_join.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable(`common_resource`) + defer dropTable(`managed_resource`) + defer dropTable(`rules_template`) + defer dropTable(`resource_mark`) + gtest.C(t, func(t *gtest.T) { + t.AssertNil(db.GetCore().ClearCacheAll(ctx)) + sqlSlice, err := gdb.CatchSQL(ctx, func(ctx context.Context) error { + orm := db.Model(`managed_resource`).Ctx(ctx). + LeftJoinOnField(`common_resource`, `resource_id`). + LeftJoinOnFields(`resource_mark`, `resource_mark_id`, `=`, `id`). + LeftJoinOnFields(`rules_template`, `rule_template_id`, `=`, `template_id`). + FieldsPrefix( + `managed_resource`, + "resource_id", "user", "status", "status_message", "safe_publication", "rule_template_id", + "created_at", "comments", "expired_at", "resource_mark_id", "instance_id", "resource_name", + "pay_mode"). + FieldsPrefix(`resource_mark`, "mark_name", "color"). + FieldsPrefix(`rules_template`, "name"). + FieldsPrefix(`common_resource`, `src_instance_id`, "database_kind", "source_type", "ip", "port") + all, err := orm.OrderAsc("src_instance_id").All() + t.Assert(len(all), 4) + t.Assert(all[0]["pay_mode"], 1) + t.Assert(all[0]["src_instance_id"], 2) + t.Assert(all[3]["instance_id"], "dmcins-jxy0x75m") + t.Assert(all[3]["src_instance_id"], "vdb-6b6m3u1u") + t.Assert(all[3]["resource_mark_id"], "11") + return err + }) + t.AssertNil(err) + + t.Assert(gtest.DataContent(`fix_gdb_join_expect.sql`), sqlSlice[len(sqlSlice)-1]) + }) } func Test_Model_Year_Date_Time_DateTime_Timestamp(t *testing.T) { - table := "date_time_example" - array := gstr.SplitAndTrim(gtest.DataContent(`date_time_example.sql`), ";") - for _, v := range array { - if _, err := db.Exec(ctx, v); err != nil { - gtest.Error(err) - } - } - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - // insert. - var now = gtime.Now() - _, err := db.Model("date_time_example").Insert(g.Map{ - "year": now, - "date": now, - "time": now, - "datetime": now, - "timestamp": now, - }) - t.AssertNil(err) - // select. - one, err := db.Model("date_time_example").One() - t.AssertNil(err) - t.Assert(one["year"].String(), now.Format("Y")) - t.Assert(one["date"].String(), now.Format("Y-m-d")) - t.Assert(one["time"].String(), now.Format("H:i:s")) - t.AssertLT(one["datetime"].GTime().Sub(now).Seconds(), 5) - t.AssertLT(one["timestamp"].GTime().Sub(now).Seconds(), 5) - }) + table := "date_time_example" + array := gstr.SplitAndTrim(gtest.DataContent(`date_time_example.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + // insert. + var now = gtime.Now() + _, err := db.Model("date_time_example").Insert(g.Map{ + "year": now, + "date": now, + "time": now, + "datetime": now, + "timestamp": now, + }) + t.AssertNil(err) + // select. + one, err := db.Model("date_time_example").One() + t.AssertNil(err) + t.Assert(one["year"].String(), now.Format("Y")) + t.Assert(one["date"].String(), now.Format("Y-m-d")) + t.Assert(one["time"].String(), now.Format("H:i:s")) + t.AssertLT(one["datetime"].GTime().Sub(now).Seconds(), 5) + t.AssertLT(one["timestamp"].GTime().Sub(now).Seconds(), 5) + }) } func Test_OrderBy_Statement_Generated(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - array := gstr.SplitAndTrim(gtest.DataContent(`fix_gdb_order_by.sql`), ";") - for _, v := range array { - if _, err := db.Exec(ctx, v); err != nil { - gtest.Error(err) - } - } - defer dropTable(`employee`) - sqlArray, _ := gdb.CatchSQL(ctx, func(ctx context.Context) error { - g.DB("default").Ctx(ctx).Model("employee").Order("name asc", "age desc").All() - return nil - }) - rawSql := strings.ReplaceAll(sqlArray[len(sqlArray)-1], " ", "") - expectSql := strings.ReplaceAll("SELECT * FROM `employee` ORDER BY `name` asc, `age` desc", " ", "") - t.Assert(rawSql, expectSql) - }) + gtest.C(t, func(t *gtest.T) { + array := gstr.SplitAndTrim(gtest.DataContent(`fix_gdb_order_by.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable(`employee`) + sqlArray, _ := gdb.CatchSQL(ctx, func(ctx context.Context) error { + g.DB("default").Ctx(ctx).Model("employee").Order("name asc", "age desc").All() + return nil + }) + rawSql := strings.ReplaceAll(sqlArray[len(sqlArray)-1], " ", "") + expectSql := strings.ReplaceAll("SELECT * FROM `employee` ORDER BY `name` asc, `age` desc", " ", "") + t.Assert(rawSql, expectSql) + }) } func Test_Fields_Raw(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - table := createInitTable() - defer dropTable(table) - one, err := db.Model(table).Fields(gdb.Raw("1")).One() - t.AssertNil(err) - t.Assert(one["1"], 1) - - one, err = db.Model(table).Fields(gdb.Raw("2")).One() - t.AssertNil(err) - t.Assert(one["2"], 2) - - one, err = db.Model(table).Fields(gdb.Raw("2")).Where("id", 2).One() - t.AssertNil(err) - t.Assert(one["2"], 2) - - one, err = db.Model(table).Fields(gdb.Raw("2")).Where("id", 10000000000).One() - t.AssertNil(err) - t.Assert(len(one), 0) - }) + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + one, err := db.Model(table).Fields(gdb.Raw("1")).One() + t.AssertNil(err) + t.Assert(one["1"], 1) + + one, err = db.Model(table).Fields(gdb.Raw("2")).One() + t.AssertNil(err) + t.Assert(one["2"], 2) + + one, err = db.Model(table).Fields(gdb.Raw("2")).Where("id", 2).One() + t.AssertNil(err) + t.Assert(one["2"], 2) + + one, err = db.Model(table).Fields(gdb.Raw("2")).Where("id", 10000000000).One() + t.AssertNil(err) + t.Assert(len(one), 0) + }) } diff --git a/contrib/drivers/mysql/testdata/issue1380.sql b/contrib/drivers/mysql/testdata/issues/1380.sql similarity index 100% rename from contrib/drivers/mysql/testdata/issue1380.sql rename to contrib/drivers/mysql/testdata/issues/1380.sql diff --git a/contrib/drivers/mysql/testdata/issue1401.sql b/contrib/drivers/mysql/testdata/issues/1401.sql similarity index 100% rename from contrib/drivers/mysql/testdata/issue1401.sql rename to contrib/drivers/mysql/testdata/issues/1401.sql diff --git a/contrib/drivers/mysql/testdata/issue1412.sql b/contrib/drivers/mysql/testdata/issues/1412.sql similarity index 100% rename from contrib/drivers/mysql/testdata/issue1412.sql rename to contrib/drivers/mysql/testdata/issues/1412.sql diff --git a/contrib/drivers/mysql/testdata/issue2105.sql b/contrib/drivers/mysql/testdata/issues/2105.sql similarity index 100% rename from contrib/drivers/mysql/testdata/issue2105.sql rename to contrib/drivers/mysql/testdata/issues/2105.sql diff --git a/contrib/drivers/mysql/testdata/issue2119.sql b/contrib/drivers/mysql/testdata/issues/2119.sql similarity index 100% rename from contrib/drivers/mysql/testdata/issue2119.sql rename to contrib/drivers/mysql/testdata/issues/2119.sql diff --git a/contrib/drivers/mysql/testdata/issue2439.sql b/contrib/drivers/mysql/testdata/issues/2439.sql similarity index 100% rename from contrib/drivers/mysql/testdata/issue2439.sql rename to contrib/drivers/mysql/testdata/issues/2439.sql diff --git a/contrib/drivers/mysql/testdata/issue2643.sql b/contrib/drivers/mysql/testdata/issues/2643.sql similarity index 100% rename from contrib/drivers/mysql/testdata/issue2643.sql rename to contrib/drivers/mysql/testdata/issues/2643.sql diff --git a/contrib/drivers/mysql/testdata/issue3086.sql b/contrib/drivers/mysql/testdata/issues/3086.sql similarity index 100% rename from contrib/drivers/mysql/testdata/issue3086.sql rename to contrib/drivers/mysql/testdata/issues/3086.sql diff --git a/contrib/drivers/mysql/testdata/issue3218.sql b/contrib/drivers/mysql/testdata/issues/3218.sql similarity index 100% rename from contrib/drivers/mysql/testdata/issue3218.sql rename to contrib/drivers/mysql/testdata/issues/3218.sql diff --git a/contrib/drivers/mysql/testdata/issue3626.sql b/contrib/drivers/mysql/testdata/issues/3626.sql similarity index 100% rename from contrib/drivers/mysql/testdata/issue3626.sql rename to contrib/drivers/mysql/testdata/issues/3626.sql diff --git a/contrib/drivers/mysql/testdata/issue3754.sql b/contrib/drivers/mysql/testdata/issues/3754.sql similarity index 100% rename from contrib/drivers/mysql/testdata/issue3754.sql rename to contrib/drivers/mysql/testdata/issues/3754.sql diff --git a/contrib/drivers/mysql/testdata/issue3915.sql b/contrib/drivers/mysql/testdata/issues/3915.sql similarity index 100% rename from contrib/drivers/mysql/testdata/issue3915.sql rename to contrib/drivers/mysql/testdata/issues/3915.sql diff --git a/contrib/drivers/mysql/testdata/issue4034.sql b/contrib/drivers/mysql/testdata/issues/4034.sql similarity index 100% rename from contrib/drivers/mysql/testdata/issue4034.sql rename to contrib/drivers/mysql/testdata/issues/4034.sql diff --git a/contrib/drivers/mysql/testdata/issues/4086.sql b/contrib/drivers/mysql/testdata/issues/4086.sql new file mode 100644 index 00000000000..53a3646ecc8 --- /dev/null +++ b/contrib/drivers/mysql/testdata/issues/4086.sql @@ -0,0 +1,10 @@ +DROP TABLE IF EXISTS `issue4086`; +CREATE TABLE `issue4086` ( + `proxy_id` bigint NOT NULL, + `recommend_ids` json DEFAULT NULL, + `photos` json DEFAULT NULL, + PRIMARY KEY (`proxy_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +INSERT INTO `issue4086` (`proxy_id`, `recommend_ids`, `photos`) VALUES (1, '[584, 585]', 'null'); +INSERT INTO `issue4086` (`proxy_id`, `recommend_ids`, `photos`) VALUES (2, '[]', NULL); \ No newline at end of file diff --git a/contrib/drivers/oracle/go.mod b/contrib/drivers/oracle/go.mod index 5b782dc93b6..39bb2f25971 100644 --- a/contrib/drivers/oracle/go.mod +++ b/contrib/drivers/oracle/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/drivers/oracle/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/gogf/gf/v2 v2.8.3 @@ -15,18 +17,20 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/contrib/drivers/oracle/go.sum b/contrib/drivers/oracle/go.sum index 20159b13709..7444a9a7ee7 100644 --- a/contrib/drivers/oracle/go.sum +++ b/contrib/drivers/oracle/go.sum @@ -2,7 +2,9 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -15,10 +17,17 @@ github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -32,20 +41,24 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/sijms/go-ora/v2 v2.7.10 h1:GSLdj0PYYgSndhsnm7b6p32OqgnwnUZSkFb3j+htfhI= github.com/sijms/go-ora/v2 v2.7.10/go.mod h1:EHxlY6x7y9HAsdfumurRfTd+v8NrEOTR3Xl4FWlH6xk= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -54,7 +67,8 @@ golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/contrib/drivers/pgsql/go.mod b/contrib/drivers/pgsql/go.mod index 09ed53aba15..edbfa4ea18c 100644 --- a/contrib/drivers/pgsql/go.mod +++ b/contrib/drivers/pgsql/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/drivers/pgsql/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/gogf/gf/v2 v2.8.3 @@ -15,18 +17,20 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/contrib/drivers/pgsql/go.sum b/contrib/drivers/pgsql/go.sum index f1b56657cb8..7f021fc7d60 100644 --- a/contrib/drivers/pgsql/go.sum +++ b/contrib/drivers/pgsql/go.sum @@ -2,7 +2,9 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -15,10 +17,17 @@ github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= @@ -34,18 +43,22 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -54,7 +67,8 @@ golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/contrib/drivers/pgsql/pgsql_convert.go b/contrib/drivers/pgsql/pgsql_convert.go index d2652d307c8..9734c2321ea 100644 --- a/contrib/drivers/pgsql/pgsql_convert.go +++ b/contrib/drivers/pgsql/pgsql_convert.go @@ -7,130 +7,130 @@ package pgsql import ( - "context" - "reflect" - "strings" + "context" + "reflect" + "strings" - "github.com/lib/pq" + "github.com/lib/pq" - "github.com/gogf/gf/v2/database/gdb" - "github.com/gogf/gf/v2/frame/g" - "github.com/gogf/gf/v2/text/gregex" - "github.com/gogf/gf/v2/text/gstr" - "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" ) // ConvertValueForField converts value to database acceptable value. func (d *Driver) ConvertValueForField(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) { - if g.IsNil(fieldValue) { - return d.Core.ConvertValueForField(ctx, fieldType, fieldValue) - } - - var fieldValueKind = reflect.TypeOf(fieldValue).Kind() - - if fieldValueKind == reflect.Slice { - // For pgsql, json or jsonb require '[]' - if !gstr.Contains(fieldType, "json") { - fieldValue = gstr.ReplaceByMap(gconv.String(fieldValue), - map[string]string{ - "[": "{", - "]": "}", - }, - ) - } - } - return d.Core.ConvertValueForField(ctx, fieldType, fieldValue) + if g.IsNil(fieldValue) { + return d.Core.ConvertValueForField(ctx, fieldType, fieldValue) + } + + var fieldValueKind = reflect.TypeOf(fieldValue).Kind() + + if fieldValueKind == reflect.Slice { + // For pgsql, json or jsonb require '[]' + if !gstr.Contains(fieldType, "json") { + fieldValue = gstr.ReplaceByMap(gconv.String(fieldValue), + map[string]string{ + "[": "{", + "]": "}", + }, + ) + } + } + return d.Core.ConvertValueForField(ctx, fieldType, fieldValue) } // CheckLocalTypeForField checks and returns corresponding local golang type for given db type. func (d *Driver) CheckLocalTypeForField(ctx context.Context, fieldType string, fieldValue interface{}) (gdb.LocalType, error) { - var typeName string - match, _ := gregex.MatchString(`(.+?)\((.+)\)`, fieldType) - if len(match) == 3 { - typeName = gstr.Trim(match[1]) - } else { - typeName = fieldType - } - typeName = strings.ToLower(typeName) - switch typeName { - case - // For pgsql, int2 = smallint. - "int2", - // For pgsql, int4 = integer - "int4": - return gdb.LocalTypeInt, nil - - case - // For pgsql, int8 = bigint - "int8": - return gdb.LocalTypeInt64, nil - - case - "_int2", - "_int4": - return gdb.LocalTypeIntSlice, nil - - case - "_int8": - return gdb.LocalTypeInt64Slice, nil - - case - "_varchar", "_text": - return gdb.LocalTypeStringSlice, nil - - default: - return d.Core.CheckLocalTypeForField(ctx, fieldType, fieldValue) - } + var typeName string + match, _ := gregex.MatchString(`(.+?)\((.+)\)`, fieldType) + if len(match) == 3 { + typeName = gstr.Trim(match[1]) + } else { + typeName = fieldType + } + typeName = strings.ToLower(typeName) + switch typeName { + case + // For pgsql, int2 = smallint. + "int2", + // For pgsql, int4 = integer + "int4": + return gdb.LocalTypeInt, nil + + case + // For pgsql, int8 = bigint + "int8": + return gdb.LocalTypeInt64, nil + + case + "_int2", + "_int4": + return gdb.LocalTypeIntSlice, nil + + case + "_int8": + return gdb.LocalTypeInt64Slice, nil + + case + "_varchar", "_text": + return gdb.LocalTypeStringSlice, nil + + default: + return d.Core.CheckLocalTypeForField(ctx, fieldType, fieldValue) + } } // ConvertValueForLocal converts value to local Golang type of value according field type name from database. // The parameter `fieldType` is in lower case, like: // `float(5,2)`, `unsigned double(5,2)`, `decimal(10,2)`, `char(45)`, `varchar(100)`, etc. func (d *Driver) ConvertValueForLocal(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) { - typeName, _ := gregex.ReplaceString(`\(.+\)`, "", fieldType) - typeName = strings.ToLower(typeName) - switch typeName { - // For pgsql, int2 = smallint and int4 = integer. - case "int2", "int4": - return gconv.Int(gconv.String(fieldValue)), nil - - // For pgsql, int8 = bigint. - case "int8": - return gconv.Int64(gconv.String(fieldValue)), nil - - // Int32 slice. - case - "_int2", "_int4": - return gconv.Ints( - gstr.ReplaceByMap(gconv.String(fieldValue), - map[string]string{ - "{": "[", - "}": "]", - }, - ), - ), nil - - // Int64 slice. - case - "_int8": - return gconv.Int64s( - gstr.ReplaceByMap(gconv.String(fieldValue), - map[string]string{ - "{": "[", - "}": "]", - }, - ), - ), nil - - // String slice. - case "_varchar", "_text": - var result pq.StringArray - if err := result.Scan(fieldValue); err != nil { - return nil, err - } - return []string(result), nil - - default: - return d.Core.ConvertValueForLocal(ctx, fieldType, fieldValue) - } + typeName, _ := gregex.ReplaceString(`\(.+\)`, "", fieldType) + typeName = strings.ToLower(typeName) + switch typeName { + // For pgsql, int2 = smallint and int4 = integer. + case "int2", "int4": + return gconv.Int(gconv.String(fieldValue)), nil + + // For pgsql, int8 = bigint. + case "int8": + return gconv.Int64(gconv.String(fieldValue)), nil + + // Int32 slice. + case + "_int2", "_int4": + return gconv.Ints( + gstr.ReplaceByMap(gconv.String(fieldValue), + map[string]string{ + "{": "[", + "}": "]", + }, + ), + ), nil + + // Int64 slice. + case + "_int8": + return gconv.Int64s( + gstr.ReplaceByMap(gconv.String(fieldValue), + map[string]string{ + "{": "[", + "}": "]", + }, + ), + ), nil + + // String slice. + case "_varchar", "_text": + var result = make(pq.StringArray, 0) + if err := result.Scan(fieldValue); err != nil { + return nil, err + } + return []string(result), nil + + default: + return d.Core.ConvertValueForLocal(ctx, fieldType, fieldValue) + } } diff --git a/contrib/drivers/sqlite/go.mod b/contrib/drivers/sqlite/go.mod index eed458eada6..60f434a7242 100644 --- a/contrib/drivers/sqlite/go.mod +++ b/contrib/drivers/sqlite/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/drivers/sqlite/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/glebarez/go-sqlite v1.21.2 @@ -16,9 +18,10 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -26,10 +29,10 @@ require ( github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/contrib/drivers/sqlite/go.sum b/contrib/drivers/sqlite/go.sum index a6ac1e9edc6..d49fc7a19b9 100644 --- a/contrib/drivers/sqlite/go.sum +++ b/contrib/drivers/sqlite/go.sum @@ -2,7 +2,9 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= @@ -19,13 +21,19 @@ github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -39,21 +47,25 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -62,8 +74,9 @@ golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= diff --git a/contrib/drivers/sqlitecgo/go.mod b/contrib/drivers/sqlitecgo/go.mod index 1ced67e3432..b806153942a 100644 --- a/contrib/drivers/sqlitecgo/go.mod +++ b/contrib/drivers/sqlitecgo/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/drivers/sqlitecgo/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/gogf/gf/v2 v2.8.3 @@ -15,18 +17,20 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/contrib/drivers/sqlitecgo/go.sum b/contrib/drivers/sqlitecgo/go.sum index e463112f27c..10aa8ae7166 100644 --- a/contrib/drivers/sqlitecgo/go.sum +++ b/contrib/drivers/sqlitecgo/go.sum @@ -2,7 +2,9 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -15,10 +17,17 @@ github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -34,18 +43,22 @@ github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -54,7 +67,8 @@ golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/contrib/nosql/redis/go.mod b/contrib/nosql/redis/go.mod index 29dc703d832..2ea9adba03b 100644 --- a/contrib/nosql/redis/go.mod +++ b/contrib/nosql/redis/go.mod @@ -1,12 +1,14 @@ module github.com/gogf/gf/contrib/nosql/redis/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/gogf/gf/v2 v2.8.3 github.com/redis/go-redis/v9 v9.7.0 - go.opentelemetry.io/otel v1.24.0 - go.opentelemetry.io/otel/trace v1.24.0 + go.opentelemetry.io/otel v1.32.0 + go.opentelemetry.io/otel/trace v1.32.0 ) require ( @@ -19,16 +21,18 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/contrib/nosql/redis/go.sum b/contrib/nosql/redis/go.sum index 0c3db9d7c1d..6b2f2b542b9 100644 --- a/contrib/nosql/redis/go.sum +++ b/contrib/nosql/redis/go.sum @@ -1,12 +1,16 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= @@ -21,10 +25,17 @@ github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -38,20 +49,24 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -60,7 +75,8 @@ golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/contrib/registry/consul/go.mod b/contrib/registry/consul/go.mod index b110ccf8241..2c44f517087 100644 --- a/contrib/registry/consul/go.mod +++ b/contrib/registry/consul/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/registry/consul/v2 -go 1.18 +go 1.22 + +toolchain go1.22.0 require ( github.com/gogf/gf/v2 v2.8.3 @@ -16,6 +18,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect @@ -29,10 +32,10 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/contrib/registry/consul/go.sum b/contrib/registry/consul/go.sum index caf44ad1f98..0f8cc3f51ed 100644 --- a/contrib/registry/consul/go.sum +++ b/contrib/registry/consul/go.sum @@ -23,6 +23,7 @@ github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -48,15 +49,22 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= +github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= github.com/hashicorp/consul/api v1.26.1 h1:5oSXOO5fboPZeW5SN+TdGFP/BILDgBm19OrPZ/pICIM= github.com/hashicorp/consul/api v1.26.1/go.mod h1:B4sQTeaSO16NtynqrAdwOlahJ7IUDZM9cj2420xYL8A= github.com/hashicorp/consul/sdk v0.15.0 h1:2qK9nDrr4tiJKRoxPGhm6B7xJjLVIQqkjiab2M4aKjU= +github.com/hashicorp/consul/sdk v0.15.0/go.mod h1:r/OmRRPbHOe0yxNahLw7G9x5WG17E1BIECMtCjcPSNo= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -70,6 +78,7 @@ github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJ github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= @@ -79,11 +88,14 @@ github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5O github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= @@ -98,11 +110,13 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -121,6 +135,7 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= @@ -137,14 +152,17 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -159,6 +177,9 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -167,20 +188,22 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= @@ -194,6 +217,7 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= +golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -235,8 +259,9 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/contrib/registry/etcd/go.mod b/contrib/registry/etcd/go.mod index 50db4fee6dd..17cb9486bb2 100644 --- a/contrib/registry/etcd/go.mod +++ b/contrib/registry/etcd/go.mod @@ -20,8 +20,10 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -30,10 +32,10 @@ require ( github.com/rivo/uniseg v0.4.7 // indirect go.etcd.io/etcd/api/v3 v3.5.17 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.17 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.17.0 // indirect diff --git a/contrib/registry/etcd/go.sum b/contrib/registry/etcd/go.sum index 2bf6733f784..1ae5b2355bb 100644 --- a/contrib/registry/etcd/go.sum +++ b/contrib/registry/etcd/go.sum @@ -6,6 +6,7 @@ github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmf github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -27,12 +28,18 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -52,11 +59,13 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/etcd/api/v3 v3.5.17 h1:cQB8eb8bxwuxOilBpMJAEo8fAONyrdXTHUNcMd8yT1w= @@ -65,14 +74,14 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.17 h1:XxnDXAWq2pnxqx76ljWwiQ9jylbpC4rvkAeRVOU go.etcd.io/etcd/client/pkg/v3 v3.5.17/go.mod h1:4DqK1TKacp/86nJk4FLQqo6Mn2vvQFBmruW3pP14H/w= go.etcd.io/etcd/client/v3 v3.5.17 h1:o48sINNeWz5+pjy/Z0+HKpj/xSnBkuVhVvXkjEXbqZY= go.etcd.io/etcd/client/v3 v3.5.17/go.mod h1:j2d4eXTHWkT2ClBgnnEPm/Wuu7jsqku41v9DZ3OtjQo= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= @@ -122,8 +131,9 @@ google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/contrib/registry/file/go.mod b/contrib/registry/file/go.mod index f26c0572097..d2533732fa6 100644 --- a/contrib/registry/file/go.mod +++ b/contrib/registry/file/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/registry/file/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require github.com/gogf/gf/v2 v2.8.3 @@ -12,18 +14,20 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/contrib/registry/file/go.sum b/contrib/registry/file/go.sum index 3f5df0ec368..4a2bcdc09a5 100644 --- a/contrib/registry/file/go.sum +++ b/contrib/registry/file/go.sum @@ -2,7 +2,9 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -15,10 +17,17 @@ github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -32,18 +41,22 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -52,7 +65,8 @@ golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/contrib/registry/nacos/go.mod b/contrib/registry/nacos/go.mod index ee1b6f4c3b2..a2c621ceae1 100644 --- a/contrib/registry/nacos/go.mod +++ b/contrib/registry/nacos/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/registry/nacos/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/gogf/gf/v2 v2.8.3 @@ -26,6 +28,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect @@ -44,10 +47,10 @@ require ( github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.21.0 // indirect diff --git a/contrib/registry/nacos/go.sum b/contrib/registry/nacos/go.sum index 8f1eddd6fdc..6b13b063c8b 100644 --- a/contrib/registry/nacos/go.sum +++ b/contrib/registry/nacos/go.sum @@ -146,6 +146,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -157,6 +158,8 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= @@ -183,8 +186,9 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -245,6 +249,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -255,7 +261,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -265,14 +272,14 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= @@ -557,8 +564,9 @@ google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHh gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/contrib/registry/polaris/go.mod b/contrib/registry/polaris/go.mod index dbbc7ba7213..f8423fbb21f 100644 --- a/contrib/registry/polaris/go.mod +++ b/contrib/registry/polaris/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/registry/polaris/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/gogf/gf/v2 v2.8.3 @@ -41,10 +43,10 @@ require ( github.com/prometheus/procfs v0.15.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.21.0 // indirect diff --git a/contrib/registry/polaris/go.sum b/contrib/registry/polaris/go.sum index e784f1e8dbe..db8c38d840f 100644 --- a/contrib/registry/polaris/go.sum +++ b/contrib/registry/polaris/go.sum @@ -303,6 +303,7 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -372,6 +373,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -444,7 +446,8 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -468,7 +471,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -482,14 +486,14 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= diff --git a/contrib/registry/zookeeper/go.mod b/contrib/registry/zookeeper/go.mod index 6c2a5c0f5e6..7f1f3466c22 100644 --- a/contrib/registry/zookeeper/go.mod +++ b/contrib/registry/zookeeper/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/registry/zookeeper/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/go-zookeeper/zk v1.0.3 @@ -16,18 +18,20 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/contrib/registry/zookeeper/go.sum b/contrib/registry/zookeeper/go.sum index f0cf8086b81..e24c5df2400 100644 --- a/contrib/registry/zookeeper/go.sum +++ b/contrib/registry/zookeeper/go.sum @@ -2,7 +2,9 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -17,10 +19,17 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -34,18 +43,22 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= @@ -56,7 +69,8 @@ golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/contrib/rpc/grpcx/go.mod b/contrib/rpc/grpcx/go.mod index 465676b0a56..9d9705297c2 100644 --- a/contrib/rpc/grpcx/go.mod +++ b/contrib/rpc/grpcx/go.mod @@ -1,12 +1,14 @@ module github.com/gogf/gf/contrib/rpc/grpcx/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/gogf/gf/contrib/registry/file/v2 v2.8.3 github.com/gogf/gf/v2 v2.8.3 - go.opentelemetry.io/otel v1.24.0 - go.opentelemetry.io/otel/trace v1.24.0 + go.opentelemetry.io/otel v1.32.0 + go.opentelemetry.io/otel/trace v1.32.0 google.golang.org/grpc v1.64.1 google.golang.org/protobuf v1.34.2 ) @@ -19,6 +21,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect github.com/magiconair/properties v1.8.9 // indirect @@ -27,8 +30,8 @@ require ( github.com/mattn/go-runewidth v0.0.16 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/contrib/rpc/grpcx/go.sum b/contrib/rpc/grpcx/go.sum index ce2771206f8..ed1149c8ba3 100644 --- a/contrib/rpc/grpcx/go.sum +++ b/contrib/rpc/grpcx/go.sum @@ -3,6 +3,7 @@ github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2 github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -15,10 +16,17 @@ github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -32,18 +40,22 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -58,7 +70,8 @@ google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/contrib/sdk/httpclient/go.mod b/contrib/sdk/httpclient/go.mod index be05225fbea..e2abac29eb4 100644 --- a/contrib/sdk/httpclient/go.mod +++ b/contrib/sdk/httpclient/go.mod @@ -1,6 +1,8 @@ module github.com/gogf/gf/contrib/sdk/httpclient/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require github.com/gogf/gf/v2 v2.8.3 @@ -12,18 +14,20 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/contrib/sdk/httpclient/go.sum b/contrib/sdk/httpclient/go.sum index 3f5df0ec368..4a2bcdc09a5 100644 --- a/contrib/sdk/httpclient/go.sum +++ b/contrib/sdk/httpclient/go.sum @@ -2,7 +2,9 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -15,10 +17,17 @@ github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -32,18 +41,22 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -52,7 +65,8 @@ golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/contrib/trace/otlpgrpc/go.mod b/contrib/trace/otlpgrpc/go.mod index b32e636b26b..6f9aeee21e4 100644 --- a/contrib/trace/otlpgrpc/go.mod +++ b/contrib/trace/otlpgrpc/go.mod @@ -1,13 +1,15 @@ module github.com/gogf/gf/contrib/trace/otlpgrpc/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/gogf/gf/v2 v2.8.3 - go.opentelemetry.io/otel v1.24.0 + go.opentelemetry.io/otel v1.32.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 - go.opentelemetry.io/otel/sdk v1.24.0 + go.opentelemetry.io/otel/sdk v1.32.0 google.golang.org/grpc v1.64.1 ) @@ -20,6 +22,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect @@ -29,8 +32,8 @@ require ( github.com/mattn/go-runewidth v0.0.16 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect go.opentelemetry.io/proto/otlp v1.1.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect diff --git a/contrib/trace/otlpgrpc/go.sum b/contrib/trace/otlpgrpc/go.sum index 92a50b717aa..c5557eb6c89 100644 --- a/contrib/trace/otlpgrpc/go.sum +++ b/contrib/trace/otlpgrpc/go.sum @@ -5,6 +5,7 @@ github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -17,6 +18,9 @@ github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= @@ -24,7 +28,9 @@ github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWI github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -38,26 +44,30 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -76,5 +86,6 @@ google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6h google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/contrib/trace/otlphttp/go.mod b/contrib/trace/otlphttp/go.mod index 25afc8d744a..d7d6125b997 100644 --- a/contrib/trace/otlphttp/go.mod +++ b/contrib/trace/otlphttp/go.mod @@ -1,13 +1,15 @@ module github.com/gogf/gf/contrib/trace/otlphttp/v2 -go 1.20 +go 1.22 + +toolchain go1.22.0 require ( github.com/gogf/gf/v2 v2.8.3 - go.opentelemetry.io/otel v1.24.0 + go.opentelemetry.io/otel v1.32.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 - go.opentelemetry.io/otel/sdk v1.24.0 + go.opentelemetry.io/otel/sdk v1.32.0 ) require ( @@ -19,6 +21,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grokify/html-strip-tags-go v0.1.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect @@ -28,8 +31,8 @@ require ( github.com/mattn/go-runewidth v0.0.16 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rivo/uniseg v0.4.7 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect go.opentelemetry.io/proto/otlp v1.1.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/sys v0.28.0 // indirect diff --git a/contrib/trace/otlphttp/go.sum b/contrib/trace/otlphttp/go.sum index 8178bfd1719..a5ac0d2a22f 100644 --- a/contrib/trace/otlphttp/go.sum +++ b/contrib/trace/otlphttp/go.sum @@ -5,6 +5,7 @@ github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -17,6 +18,9 @@ github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= @@ -24,7 +28,9 @@ github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWI github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -38,23 +44,26 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= @@ -75,5 +84,6 @@ google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6h google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/database/gdb/gdb.go b/database/gdb/gdb.go index 558ca92c957..efa41d521b9 100644 --- a/database/gdb/gdb.go +++ b/database/gdb/gdb.go @@ -10,900 +10,901 @@ package gdb import ( - "context" - "database/sql" - "time" - - "github.com/gogf/gf/v2/container/garray" - "github.com/gogf/gf/v2/container/gmap" - "github.com/gogf/gf/v2/container/gtype" - "github.com/gogf/gf/v2/container/gvar" - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/os/gcache" - "github.com/gogf/gf/v2/os/gcmd" - "github.com/gogf/gf/v2/os/gctx" - "github.com/gogf/gf/v2/os/glog" - "github.com/gogf/gf/v2/util/grand" - "github.com/gogf/gf/v2/util/gutil" + "context" + "database/sql" + "time" + + "github.com/gogf/gf/v2/container/garray" + "github.com/gogf/gf/v2/container/gmap" + "github.com/gogf/gf/v2/container/gtype" + "github.com/gogf/gf/v2/database/gdb/internal/defines" + "github.com/gogf/gf/v2/database/gdb/internal/fieldvar" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/os/gcache" + "github.com/gogf/gf/v2/os/gcmd" + "github.com/gogf/gf/v2/os/gctx" + "github.com/gogf/gf/v2/os/glog" + "github.com/gogf/gf/v2/util/grand" + "github.com/gogf/gf/v2/util/gutil" ) // DB defines the interfaces for ORM operations. type DB interface { - // =========================================================================== - // Model creation. - // =========================================================================== - - // Model creates and returns a new ORM model from given schema. - // The parameter `table` can be more than one table names, and also alias name, like: - // 1. Model names: - // Model("user") - // Model("user u") - // Model("user, user_detail") - // Model("user u, user_detail ud") - // 2. Model name with alias: Model("user", "u") - // Also see Core.Model. - Model(tableNameOrStruct ...interface{}) *Model - - // Raw creates and returns a model based on a raw sql not a table. - Raw(rawSql string, args ...interface{}) *Model - - // Schema switches to a specified schema. - // Also see Core.Schema. - Schema(schema string) *Schema - - // With creates and returns an ORM model based on metadata of given object. - // Also see Core.With. - With(objects ...interface{}) *Model - - // Open creates a raw connection object for database with given node configuration. - // Note that it is not recommended using the function manually. - Open(config *ConfigNode) (*sql.DB, error) - - // Ctx is a chaining function, which creates and returns a new DB that is a shallow copy - // of current DB object and with given context in it. - // Also see Core.Ctx. - Ctx(ctx context.Context) DB - - // Close closes the database and prevents new queries from starting. - // Close then waits for all queries that have started processing on the server - // to finish. - // - // It is rare to Close a DB, as the DB handle is meant to be - // long-lived and shared between many goroutines. - Close(ctx context.Context) error - - // =========================================================================== - // Query APIs. - // =========================================================================== - - // Query executes a SQL query that returns rows using given SQL and arguments. - // The args are for any placeholder parameters in the query. - Query(ctx context.Context, sql string, args ...interface{}) (Result, error) - - // Exec executes a SQL query that doesn't return rows (e.g., INSERT, UPDATE, DELETE). - // It returns sql.Result for accessing LastInsertId or RowsAffected. - Exec(ctx context.Context, sql string, args ...interface{}) (sql.Result, error) - - // Prepare creates a prepared statement for later queries or executions. - // The execOnMaster parameter determines whether the statement executes on master node. - Prepare(ctx context.Context, sql string, execOnMaster ...bool) (*Stmt, error) - - // =========================================================================== - // Common APIs for CRUD. - // =========================================================================== - - // Insert inserts one or multiple records into table. - // The data can be a map, struct, or slice of maps/structs. - // The optional batch parameter specifies the batch size for bulk inserts. - Insert(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) - - // InsertIgnore inserts records but ignores duplicate key errors. - // It works like Insert but adds IGNORE keyword to the SQL statement. - InsertIgnore(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) - - // InsertAndGetId inserts a record and returns the auto-generated ID. - // It's a convenience method combining Insert with LastInsertId. - InsertAndGetId(ctx context.Context, table string, data interface{}, batch ...int) (int64, error) - - // Replace inserts or replaces records using REPLACE INTO syntax. - // Existing records with same unique key will be deleted and re-inserted. - Replace(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) - - // Save inserts or updates records using INSERT ... ON DUPLICATE KEY UPDATE syntax. - // It updates existing records instead of replacing them entirely. - Save(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) - - // Update updates records in table that match the condition. - // The data can be a map or struct containing the new values. - // The condition specifies the WHERE clause with optional placeholder args. - Update(ctx context.Context, table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) - - // Delete deletes records from table that match the condition. - // The condition specifies the WHERE clause with optional placeholder args. - Delete(ctx context.Context, table string, condition interface{}, args ...interface{}) (sql.Result, error) - - // =========================================================================== - // Internal APIs for CRUD, which can be overwritten by custom CRUD implements. - // =========================================================================== - - // DoSelect executes a SELECT query using the given link and returns the result. - // This is an internal method that can be overridden by custom implementations. - DoSelect(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) - - // DoInsert performs the actual INSERT operation with given options. - // This is an internal method that can be overridden by custom implementations. - DoInsert(ctx context.Context, link Link, table string, data List, option DoInsertOption) (result sql.Result, err error) - - // DoUpdate performs the actual UPDATE operation. - // This is an internal method that can be overridden by custom implementations. - DoUpdate(ctx context.Context, link Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) - - // DoDelete performs the actual DELETE operation. - // This is an internal method that can be overridden by custom implementations. - DoDelete(ctx context.Context, link Link, table string, condition string, args ...interface{}) (result sql.Result, err error) - - // DoQuery executes a query that returns rows. - // This is an internal method that can be overridden by custom implementations. - DoQuery(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) - - // DoExec executes a query that doesn't return rows. - // This is an internal method that can be overridden by custom implementations. - DoExec(ctx context.Context, link Link, sql string, args ...interface{}) (result sql.Result, err error) - - // DoFilter processes and filters SQL and args before execution. - // This is an internal method that can be overridden to implement custom SQL filtering. - DoFilter(ctx context.Context, link Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) - - // DoCommit handles the actual commit operation for transactions. - // This is an internal method that can be overridden by custom implementations. - DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutput, err error) - - // DoPrepare creates a prepared statement on the given link. - // This is an internal method that can be overridden by custom implementations. - DoPrepare(ctx context.Context, link Link, sql string) (*Stmt, error) - - // =========================================================================== - // Query APIs for convenience purpose. - // =========================================================================== - - // GetAll executes a query and returns all rows as Result. - // It's a convenience wrapper around Query. - GetAll(ctx context.Context, sql string, args ...interface{}) (Result, error) + // =========================================================================== + // Model creation. + // =========================================================================== + + // Model creates and returns a new ORM model from given schema. + // The parameter `table` can be more than one table names, and also alias name, like: + // 1. Model names: + // Model("user") + // Model("user u") + // Model("user, user_detail") + // Model("user u, user_detail ud") + // 2. Model name with alias: Model("user", "u") + // Also see Core.Model. + Model(tableNameOrStruct ...interface{}) *Model + + // Raw creates and returns a model based on a raw sql not a table. + Raw(rawSql string, args ...interface{}) *Model + + // Schema switches to a specified schema. + // Also see Core.Schema. + Schema(schema string) *Schema + + // With creates and returns an ORM model based on metadata of given object. + // Also see Core.With. + With(objects ...interface{}) *Model + + // Open creates a raw connection object for database with given node configuration. + // Note that it is not recommended using the function manually. + Open(config *ConfigNode) (*sql.DB, error) + + // Ctx is a chaining function, which creates and returns a new DB that is a shallow copy + // of current DB object and with given context in it. + // Also see Core.Ctx. + Ctx(ctx context.Context) DB + + // Close closes the database and prevents new queries from starting. + // Close then waits for all queries that have started processing on the server + // to finish. + // + // It is rare to Close a DB, as the DB handle is meant to be + // long-lived and shared between many goroutines. + Close(ctx context.Context) error + + // =========================================================================== + // Query APIs. + // =========================================================================== + + // Query executes a SQL query that returns rows using given SQL and arguments. + // The args are for any placeholder parameters in the query. + Query(ctx context.Context, sql string, args ...interface{}) (Result, error) + + // Exec executes a SQL query that doesn't return rows (e.g., INSERT, UPDATE, DELETE). + // It returns sql.Result for accessing LastInsertId or RowsAffected. + Exec(ctx context.Context, sql string, args ...interface{}) (sql.Result, error) + + // Prepare creates a prepared statement for later queries or executions. + // The execOnMaster parameter determines whether the statement executes on master node. + Prepare(ctx context.Context, sql string, execOnMaster ...bool) (*Stmt, error) + + // =========================================================================== + // Common APIs for CRUD. + // =========================================================================== + + // Insert inserts one or multiple records into table. + // The data can be a map, struct, or slice of maps/structs. + // The optional batch parameter specifies the batch size for bulk inserts. + Insert(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) + + // InsertIgnore inserts records but ignores duplicate key errors. + // It works like Insert but adds IGNORE keyword to the SQL statement. + InsertIgnore(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) + + // InsertAndGetId inserts a record and returns the auto-generated ID. + // It's a convenience method combining Insert with LastInsertId. + InsertAndGetId(ctx context.Context, table string, data interface{}, batch ...int) (int64, error) + + // Replace inserts or replaces records using REPLACE INTO syntax. + // Existing records with same unique key will be deleted and re-inserted. + Replace(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) + + // Save inserts or updates records using INSERT ... ON DUPLICATE KEY UPDATE syntax. + // It updates existing records instead of replacing them entirely. + Save(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) + + // Update updates records in table that match the condition. + // The data can be a map or struct containing the new values. + // The condition specifies the WHERE clause with optional placeholder args. + Update(ctx context.Context, table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) + + // Delete deletes records from table that match the condition. + // The condition specifies the WHERE clause with optional placeholder args. + Delete(ctx context.Context, table string, condition interface{}, args ...interface{}) (sql.Result, error) + + // =========================================================================== + // Internal APIs for CRUD, which can be overwritten by custom CRUD implements. + // =========================================================================== + + // DoSelect executes a SELECT query using the given link and returns the result. + // This is an internal method that can be overridden by custom implementations. + DoSelect(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) + + // DoInsert performs the actual INSERT operation with given options. + // This is an internal method that can be overridden by custom implementations. + DoInsert(ctx context.Context, link Link, table string, data List, option DoInsertOption) (result sql.Result, err error) + + // DoUpdate performs the actual UPDATE operation. + // This is an internal method that can be overridden by custom implementations. + DoUpdate(ctx context.Context, link Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) + + // DoDelete performs the actual DELETE operation. + // This is an internal method that can be overridden by custom implementations. + DoDelete(ctx context.Context, link Link, table string, condition string, args ...interface{}) (result sql.Result, err error) + + // DoQuery executes a query that returns rows. + // This is an internal method that can be overridden by custom implementations. + DoQuery(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) + + // DoExec executes a query that doesn't return rows. + // This is an internal method that can be overridden by custom implementations. + DoExec(ctx context.Context, link Link, sql string, args ...interface{}) (result sql.Result, err error) + + // DoFilter processes and filters SQL and args before execution. + // This is an internal method that can be overridden to implement custom SQL filtering. + DoFilter(ctx context.Context, link Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) + + // DoCommit handles the actual commit operation for transactions. + // This is an internal method that can be overridden by custom implementations. + DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutput, err error) + + // DoPrepare creates a prepared statement on the given link. + // This is an internal method that can be overridden by custom implementations. + DoPrepare(ctx context.Context, link Link, sql string) (*Stmt, error) + + // =========================================================================== + // Query APIs for convenience purpose. + // =========================================================================== + + // GetAll executes a query and returns all rows as Result. + // It's a convenience wrapper around Query. + GetAll(ctx context.Context, sql string, args ...interface{}) (Result, error) - // GetOne executes a query and returns the first row as Record. - // It's useful when you expect only one row to be returned. - GetOne(ctx context.Context, sql string, args ...interface{}) (Record, error) + // GetOne executes a query and returns the first row as Record. + // It's useful when you expect only one row to be returned. + GetOne(ctx context.Context, sql string, args ...interface{}) (Record, error) - // GetValue executes a query and returns the first column of the first row. - // It's useful for queries like SELECT COUNT(*) or getting a single value. - GetValue(ctx context.Context, sql string, args ...interface{}) (Value, error) + // GetValue executes a query and returns the first column of the first row. + // It's useful for queries like SELECT COUNT(*) or getting a single value. + GetValue(ctx context.Context, sql string, args ...interface{}) (Value, error) - // GetArray executes a query and returns the first column of all rows. - // It's useful for queries like SELECT id FROM table. - GetArray(ctx context.Context, sql string, args ...interface{}) ([]Value, error) + // GetArray executes a query and returns the first column of all rows. + // It's useful for queries like SELECT id FROM table. + GetArray(ctx context.Context, sql string, args ...interface{}) ([]Value, error) - // GetCount executes a COUNT query and returns the result as an integer. - // It's a convenience method for counting rows. - GetCount(ctx context.Context, sql string, args ...interface{}) (int, error) + // GetCount executes a COUNT query and returns the result as an integer. + // It's a convenience method for counting rows. + GetCount(ctx context.Context, sql string, args ...interface{}) (int, error) - // GetScan executes a query and scans the result into the given object pointer. - // It automatically maps database columns to struct fields or slice elements. - GetScan(ctx context.Context, objPointer interface{}, sql string, args ...interface{}) error + // GetScan executes a query and scans the result into the given object pointer. + // It automatically maps database columns to struct fields or slice elements. + GetScan(ctx context.Context, objPointer interface{}, sql string, args ...interface{}) error - // Union combines multiple SELECT queries using UNION operator. - // It returns a new Model that represents the combined query. - Union(unions ...*Model) *Model + // Union combines multiple SELECT queries using UNION operator. + // It returns a new Model that represents the combined query. + Union(unions ...*Model) *Model - // UnionAll combines multiple SELECT queries using UNION ALL operator. - // Unlike Union, it keeps duplicate rows in the result. - UnionAll(unions ...*Model) *Model + // UnionAll combines multiple SELECT queries using UNION ALL operator. + // Unlike Union, it keeps duplicate rows in the result. + UnionAll(unions ...*Model) *Model - // =========================================================================== - // Master/Slave specification support. - // =========================================================================== + // =========================================================================== + // Master/Slave specification support. + // =========================================================================== - // Master returns a connection to the master database node. - // The optional schema parameter specifies which database schema to use. - Master(schema ...string) (*sql.DB, error) + // Master returns a connection to the master database node. + // The optional schema parameter specifies which database schema to use. + Master(schema ...string) (*sql.DB, error) - // Slave returns a connection to a slave database node. - // The optional schema parameter specifies which database schema to use. - Slave(schema ...string) (*sql.DB, error) + // Slave returns a connection to a slave database node. + // The optional schema parameter specifies which database schema to use. + Slave(schema ...string) (*sql.DB, error) - // =========================================================================== - // Ping-Pong. - // =========================================================================== + // =========================================================================== + // Ping-Pong. + // =========================================================================== - // PingMaster checks if the master database node is accessible. - // It returns an error if the connection fails. - PingMaster() error + // PingMaster checks if the master database node is accessible. + // It returns an error if the connection fails. + PingMaster() error - // PingSlave checks if any slave database node is accessible. - // It returns an error if no slave connections are available. - PingSlave() error + // PingSlave checks if any slave database node is accessible. + // It returns an error if no slave connections are available. + PingSlave() error - // =========================================================================== - // Transaction. - // =========================================================================== + // =========================================================================== + // Transaction. + // =========================================================================== - // Begin starts a new transaction and returns a TX interface. - // The returned TX must be committed or rolled back to release resources. - Begin(ctx context.Context) (TX, error) + // Begin starts a new transaction and returns a TX interface. + // The returned TX must be committed or rolled back to release resources. + Begin(ctx context.Context) (TX, error) - // BeginWithOptions starts a new transaction with the given options and returns a TX interface. - // The options allow specifying isolation level and read-only mode. - // The returned TX must be committed or rolled back to release resources. - BeginWithOptions(ctx context.Context, opts TxOptions) (TX, error) + // BeginWithOptions starts a new transaction with the given options and returns a TX interface. + // The options allow specifying isolation level and read-only mode. + // The returned TX must be committed or rolled back to release resources. + BeginWithOptions(ctx context.Context, opts TxOptions) (TX, error) - // Transaction executes a function within a transaction. - // It automatically handles commit/rollback based on whether f returns an error. - Transaction(ctx context.Context, f func(ctx context.Context, tx TX) error) error + // Transaction executes a function within a transaction. + // It automatically handles commit/rollback based on whether f returns an error. + Transaction(ctx context.Context, f func(ctx context.Context, tx TX) error) error - // TransactionWithOptions executes a function within a transaction with specific options. - // It allows customizing transaction behavior like isolation level and timeout. - TransactionWithOptions(ctx context.Context, opts TxOptions, f func(ctx context.Context, tx TX) error) error + // TransactionWithOptions executes a function within a transaction with specific options. + // It allows customizing transaction behavior like isolation level and timeout. + TransactionWithOptions(ctx context.Context, opts TxOptions, f func(ctx context.Context, tx TX) error) error - // =========================================================================== - // Configuration methods. - // =========================================================================== + // =========================================================================== + // Configuration methods. + // =========================================================================== - // GetCache returns the cache instance used by this database. - // The cache is used for query results caching. - GetCache() *gcache.Cache + // GetCache returns the cache instance used by this database. + // The cache is used for query results caching. + GetCache() *gcache.Cache - // SetDebug enables or disables debug mode for SQL logging. - // When enabled, all SQL statements and their execution time are logged. - SetDebug(debug bool) + // SetDebug enables or disables debug mode for SQL logging. + // When enabled, all SQL statements and their execution time are logged. + SetDebug(debug bool) - // GetDebug returns whether debug mode is enabled. - GetDebug() bool + // GetDebug returns whether debug mode is enabled. + GetDebug() bool - // GetSchema returns the current database schema name. - GetSchema() string + // GetSchema returns the current database schema name. + GetSchema() string - // GetPrefix returns the table name prefix used by this database. - GetPrefix() string + // GetPrefix returns the table name prefix used by this database. + GetPrefix() string - // GetGroup returns the configuration group name of this database. - GetGroup() string + // GetGroup returns the configuration group name of this database. + GetGroup() string - // SetDryRun enables or disables dry-run mode. - // In dry-run mode, SQL statements are generated but not executed. - SetDryRun(enabled bool) + // SetDryRun enables or disables dry-run mode. + // In dry-run mode, SQL statements are generated but not executed. + SetDryRun(enabled bool) - // GetDryRun returns whether dry-run mode is enabled. - GetDryRun() bool + // GetDryRun returns whether dry-run mode is enabled. + GetDryRun() bool - // SetLogger sets a custom logger for database operations. - // The logger must implement glog.ILogger interface. - SetLogger(logger glog.ILogger) + // SetLogger sets a custom logger for database operations. + // The logger must implement glog.ILogger interface. + SetLogger(logger glog.ILogger) - // GetLogger returns the current logger used by this database. - GetLogger() glog.ILogger + // GetLogger returns the current logger used by this database. + GetLogger() glog.ILogger - // GetConfig returns the configuration node used by this database. - GetConfig() *ConfigNode + // GetConfig returns the configuration node used by this database. + GetConfig() *ConfigNode - // SetMaxIdleConnCount sets the maximum number of idle connections in the pool. - SetMaxIdleConnCount(n int) + // SetMaxIdleConnCount sets the maximum number of idle connections in the pool. + SetMaxIdleConnCount(n int) - // SetMaxOpenConnCount sets the maximum number of open connections to the database. - SetMaxOpenConnCount(n int) + // SetMaxOpenConnCount sets the maximum number of open connections to the database. + SetMaxOpenConnCount(n int) - // SetMaxConnLifeTime sets the maximum amount of time a connection may be reused. - SetMaxConnLifeTime(d time.Duration) + // SetMaxConnLifeTime sets the maximum amount of time a connection may be reused. + SetMaxConnLifeTime(d time.Duration) - // =========================================================================== - // Utility methods. - // =========================================================================== + // =========================================================================== + // Utility methods. + // =========================================================================== - // Stats returns statistics about the database connection pool. - // It includes information like the number of active and idle connections. - Stats(ctx context.Context) []StatsItem + // Stats returns statistics about the database connection pool. + // It includes information like the number of active and idle connections. + Stats(ctx context.Context) []StatsItem - // GetCtx returns the context associated with this database instance. - GetCtx() context.Context + // GetCtx returns the context associated with this database instance. + GetCtx() context.Context - // GetCore returns the underlying Core instance of this database. - GetCore() *Core + // GetCore returns the underlying Core instance of this database. + GetCore() *Core - // GetChars returns the left and right quote characters used for escaping identifiers. - // For example, in MySQL these are backticks: ` and `. - GetChars() (charLeft string, charRight string) + // GetChars returns the left and right quote characters used for escaping identifiers. + // For example, in MySQL these are backticks: ` and `. + GetChars() (charLeft string, charRight string) - // Tables returns a list of all table names in the specified schema. - // If no schema is specified, it uses the default schema. - Tables(ctx context.Context, schema ...string) (tables []string, err error) + // Tables returns a list of all table names in the specified schema. + // If no schema is specified, it uses the default schema. + Tables(ctx context.Context, schema ...string) (tables []string, err error) - // TableFields returns detailed information about all fields in the specified table. - // The returned map keys are field names and values contain field metadata. - TableFields(ctx context.Context, table string, schema ...string) (map[string]*TableField, error) + // TableFields returns detailed information about all fields in the specified table. + // The returned map keys are field names and values contain field metadata. + TableFields(ctx context.Context, table string, schema ...string) (map[string]*TableField, error) - // ConvertValueForField converts a value to the appropriate type for a database field. - // It handles type conversion from Go types to database-specific types. - ConvertValueForField(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) + // ConvertValueForField converts a value to the appropriate type for a database field. + // It handles type conversion from Go types to database-specific types. + ConvertValueForField(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) - // ConvertValueForLocal converts a database value to the appropriate Go type. - // It handles type conversion from database-specific types to Go types. - ConvertValueForLocal(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) + // ConvertValueForLocal converts a database value to the appropriate Go type. + // It handles type conversion from database-specific types to Go types. + ConvertValueForLocal(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) - // CheckLocalTypeForField checks if a Go value is compatible with a database field type. - // It returns the appropriate LocalType and any conversion errors. - CheckLocalTypeForField(ctx context.Context, fieldType string, fieldValue interface{}) (LocalType, error) + // CheckLocalTypeForField checks if a Go value is compatible with a database field type. + // It returns the appropriate LocalType and any conversion errors. + CheckLocalTypeForField(ctx context.Context, fieldType string, fieldValue interface{}) (LocalType, error) - // FormatUpsert formats an upsert (INSERT ... ON DUPLICATE KEY UPDATE) statement. - // It generates the appropriate SQL based on the columns, values, and options provided. - FormatUpsert(columns []string, list List, option DoInsertOption) (string, error) + // FormatUpsert formats an upsert (INSERT ... ON DUPLICATE KEY UPDATE) statement. + // It generates the appropriate SQL based on the columns, values, and options provided. + FormatUpsert(columns []string, list List, option DoInsertOption) (string, error) - // OrderRandomFunction returns the SQL function for random ordering. - // The implementation is database-specific (e.g., RAND() for MySQL). - OrderRandomFunction() string + // OrderRandomFunction returns the SQL function for random ordering. + // The implementation is database-specific (e.g., RAND() for MySQL). + OrderRandomFunction() string } // TX defines the interfaces for ORM transaction operations. type TX interface { - Link + Link - // Ctx binds a context to current transaction. - // The context is used for operations like timeout control. - Ctx(ctx context.Context) TX + // Ctx binds a context to current transaction. + // The context is used for operations like timeout control. + Ctx(ctx context.Context) TX - // Raw creates and returns a model based on a raw SQL. - // The rawSql can contain placeholders ? and corresponding args. - Raw(rawSql string, args ...interface{}) *Model + // Raw creates and returns a model based on a raw SQL. + // The rawSql can contain placeholders ? and corresponding args. + Raw(rawSql string, args ...interface{}) *Model - // Model creates and returns a Model from given table name/struct. - // The parameter can be table name as string, or struct/*struct type. - Model(tableNameQueryOrStruct ...interface{}) *Model + // Model creates and returns a Model from given table name/struct. + // The parameter can be table name as string, or struct/*struct type. + Model(tableNameQueryOrStruct ...interface{}) *Model - // With creates and returns a Model from given object. - // It automatically analyzes the object and generates corresponding SQL. - With(object interface{}) *Model + // With creates and returns a Model from given object. + // It automatically analyzes the object and generates corresponding SQL. + With(object interface{}) *Model - // =========================================================================== - // Nested transaction if necessary. - // =========================================================================== + // =========================================================================== + // Nested transaction if necessary. + // =========================================================================== - // Begin starts a nested transaction. - // It creates a new savepoint for current transaction. - Begin() error + // Begin starts a nested transaction. + // It creates a new savepoint for current transaction. + Begin() error - // Commit commits current transaction/savepoint. - // For nested transactions, it releases the current savepoint. - Commit() error + // Commit commits current transaction/savepoint. + // For nested transactions, it releases the current savepoint. + Commit() error - // Rollback rolls back current transaction/savepoint. - // For nested transactions, it rolls back to the current savepoint. - Rollback() error + // Rollback rolls back current transaction/savepoint. + // For nested transactions, it rolls back to the current savepoint. + Rollback() error - // Transaction executes given function in a nested transaction. - // It automatically handles commit/rollback based on function's error return. - Transaction(ctx context.Context, f func(ctx context.Context, tx TX) error) (err error) + // Transaction executes given function in a nested transaction. + // It automatically handles commit/rollback based on function's error return. + Transaction(ctx context.Context, f func(ctx context.Context, tx TX) error) (err error) - // TransactionWithOptions executes given function in a nested transaction with options. - // It allows customizing transaction behavior like isolation level. - TransactionWithOptions(ctx context.Context, opts TxOptions, f func(ctx context.Context, tx TX) error) error + // TransactionWithOptions executes given function in a nested transaction with options. + // It allows customizing transaction behavior like isolation level. + TransactionWithOptions(ctx context.Context, opts TxOptions, f func(ctx context.Context, tx TX) error) error - // =========================================================================== - // Core method. - // =========================================================================== + // =========================================================================== + // Core method. + // =========================================================================== - // Query executes a query that returns rows using given SQL and arguments. - // The args are for any placeholder parameters in the query. - Query(sql string, args ...interface{}) (result Result, err error) + // Query executes a query that returns rows using given SQL and arguments. + // The args are for any placeholder parameters in the query. + Query(sql string, args ...interface{}) (result Result, err error) - // Exec executes a query that doesn't return rows. - // For example: INSERT, UPDATE, DELETE. - Exec(sql string, args ...interface{}) (sql.Result, error) + // Exec executes a query that doesn't return rows. + // For example: INSERT, UPDATE, DELETE. + Exec(sql string, args ...interface{}) (sql.Result, error) - // Prepare creates a prepared statement for later queries or executions. - // Multiple queries or executions may be run concurrently from the statement. - Prepare(sql string) (*Stmt, error) + // Prepare creates a prepared statement for later queries or executions. + // Multiple queries or executions may be run concurrently from the statement. + Prepare(sql string) (*Stmt, error) - // =========================================================================== - // Query. - // =========================================================================== + // =========================================================================== + // Query. + // =========================================================================== - // GetAll executes a query and returns all rows as Result. - // It's a convenient wrapper for Query. - GetAll(sql string, args ...interface{}) (Result, error) + // GetAll executes a query and returns all rows as Result. + // It's a convenient wrapper for Query. + GetAll(sql string, args ...interface{}) (Result, error) - // GetOne executes a query and returns the first row as Record. - // It's useful when you expect only one row to be returned. - GetOne(sql string, args ...interface{}) (Record, error) + // GetOne executes a query and returns the first row as Record. + // It's useful when you expect only one row to be returned. + GetOne(sql string, args ...interface{}) (Record, error) - // GetStruct executes a query and scans the result into given struct. - // The obj should be a pointer to struct. - GetStruct(obj interface{}, sql string, args ...interface{}) error + // GetStruct executes a query and scans the result into given struct. + // The obj should be a pointer to struct. + GetStruct(obj interface{}, sql string, args ...interface{}) error - // GetStructs executes a query and scans all results into given struct slice. - // The objPointerSlice should be a pointer to slice of struct. - GetStructs(objPointerSlice interface{}, sql string, args ...interface{}) error + // GetStructs executes a query and scans all results into given struct slice. + // The objPointerSlice should be a pointer to slice of struct. + GetStructs(objPointerSlice interface{}, sql string, args ...interface{}) error - // GetScan executes a query and scans the result into given variables. - // The pointer can be type of struct/*struct/[]struct/[]*struct. - GetScan(pointer interface{}, sql string, args ...interface{}) error + // GetScan executes a query and scans the result into given variables. + // The pointer can be type of struct/*struct/[]struct/[]*struct. + GetScan(pointer interface{}, sql string, args ...interface{}) error - // GetValue executes a query and returns the first column of first row. - // It's useful for queries like SELECT COUNT(*). - GetValue(sql string, args ...interface{}) (Value, error) + // GetValue executes a query and returns the first column of first row. + // It's useful for queries like SELECT COUNT(*). + GetValue(sql string, args ...interface{}) (Value, error) - // GetCount executes a query that should return a count value. - // It's a convenient wrapper for count queries. - GetCount(sql string, args ...interface{}) (int64, error) + // GetCount executes a query that should return a count value. + // It's a convenient wrapper for count queries. + GetCount(sql string, args ...interface{}) (int64, error) - // =========================================================================== - // CRUD. - // =========================================================================== + // =========================================================================== + // CRUD. + // =========================================================================== - // Insert inserts one or multiple records into table. - // The data can be map/struct/*struct/[]map/[]struct/[]*struct. - Insert(table string, data interface{}, batch ...int) (sql.Result, error) + // Insert inserts one or multiple records into table. + // The data can be map/struct/*struct/[]map/[]struct/[]*struct. + Insert(table string, data interface{}, batch ...int) (sql.Result, error) - // InsertIgnore inserts one or multiple records with IGNORE option. - // It ignores records that would cause duplicate key conflicts. - InsertIgnore(table string, data interface{}, batch ...int) (sql.Result, error) + // InsertIgnore inserts one or multiple records with IGNORE option. + // It ignores records that would cause duplicate key conflicts. + InsertIgnore(table string, data interface{}, batch ...int) (sql.Result, error) - // InsertAndGetId inserts one record and returns its id value. - // It's commonly used with auto-increment primary key. - InsertAndGetId(table string, data interface{}, batch ...int) (int64, error) + // InsertAndGetId inserts one record and returns its id value. + // It's commonly used with auto-increment primary key. + InsertAndGetId(table string, data interface{}, batch ...int) (int64, error) - // Replace inserts or replaces records using REPLACE INTO syntax. - // Existing records with same unique key will be deleted and re-inserted. - Replace(table string, data interface{}, batch ...int) (sql.Result, error) + // Replace inserts or replaces records using REPLACE INTO syntax. + // Existing records with same unique key will be deleted and re-inserted. + Replace(table string, data interface{}, batch ...int) (sql.Result, error) - // Save inserts or updates records using INSERT ... ON DUPLICATE KEY UPDATE syntax. - // It updates existing records instead of replacing them entirely. - Save(table string, data interface{}, batch ...int) (sql.Result, error) + // Save inserts or updates records using INSERT ... ON DUPLICATE KEY UPDATE syntax. + // It updates existing records instead of replacing them entirely. + Save(table string, data interface{}, batch ...int) (sql.Result, error) - // Update updates records in table that match given condition. - // The data can be map/struct, and condition supports various formats. - Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) + // Update updates records in table that match given condition. + // The data can be map/struct, and condition supports various formats. + Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) - // Delete deletes records from table that match given condition. - // The condition supports various formats with optional arguments. - Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error) + // Delete deletes records from table that match given condition. + // The condition supports various formats with optional arguments. + Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error) - // =========================================================================== - // Utility methods. - // =========================================================================== + // =========================================================================== + // Utility methods. + // =========================================================================== - // GetCtx returns the context that is bound to current transaction. - GetCtx() context.Context + // GetCtx returns the context that is bound to current transaction. + GetCtx() context.Context - // GetDB returns the underlying DB interface object. - GetDB() DB + // GetDB returns the underlying DB interface object. + GetDB() DB - // GetSqlTX returns the underlying *sql.Tx object. - // Note: be very careful when using this method. - GetSqlTX() *sql.Tx + // GetSqlTX returns the underlying *sql.Tx object. + // Note: be very careful when using this method. + GetSqlTX() *sql.Tx - // IsClosed checks if current transaction is closed. - // A transaction is closed after Commit or Rollback. - IsClosed() bool + // IsClosed checks if current transaction is closed. + // A transaction is closed after Commit or Rollback. + IsClosed() bool - // =========================================================================== - // Save point feature. - // =========================================================================== + // =========================================================================== + // Save point feature. + // =========================================================================== - // SavePoint creates a save point with given name. - // It's used in nested transactions to create rollback points. - SavePoint(point string) error + // SavePoint creates a save point with given name. + // It's used in nested transactions to create rollback points. + SavePoint(point string) error - // RollbackTo rolls back transaction to previously created save point. - // If the save point doesn't exist, it returns an error. - RollbackTo(point string) error + // RollbackTo rolls back transaction to previously created save point. + // If the save point doesn't exist, it returns an error. + RollbackTo(point string) error } // StatsItem defines the stats information for a configuration node. type StatsItem interface { - // Node returns the configuration node info. - Node() ConfigNode + // Node returns the configuration node info. + Node() ConfigNode - // Stats returns the connection stat for current node. - Stats() sql.DBStats + // Stats returns the connection stat for current node. + Stats() sql.DBStats } // Core is the base struct for database management. type Core struct { - db DB // DB interface object. - ctx context.Context // Context for chaining operation only. Do not set a default value in Core initialization. - group string // Configuration group name. - schema string // Custom schema for this object. - debug *gtype.Bool // Enable debug mode for the database, which can be changed in runtime. - cache *gcache.Cache // Cache manager, SQL result cache only. - links *gmap.Map // links caches all created links by node. - logger glog.ILogger // Logger for logging functionality. - config *ConfigNode // Current config node. - dynamicConfig dynamicConfig // Dynamic configurations, which can be changed in runtime. - innerMemCache *gcache.Cache + db DB // DB interface object. + ctx context.Context // Context for chaining operation only. Do not set a default value in Core initialization. + group string // Configuration group name. + schema string // Custom schema for this object. + debug *gtype.Bool // Enable debug mode for the database, which can be changed in runtime. + cache *gcache.Cache // Cache manager, SQL result cache only. + links *gmap.Map // links caches all created links by node. + logger glog.ILogger // Logger for logging functionality. + config *ConfigNode // Current config node. + dynamicConfig dynamicConfig // Dynamic configurations, which can be changed in runtime. + innerMemCache *gcache.Cache // Internal memory cache for storing temporary data. } type dynamicConfig struct { - MaxIdleConnCount int - MaxOpenConnCount int - MaxConnLifeTime time.Duration + MaxIdleConnCount int + MaxOpenConnCount int + MaxConnLifeTime time.Duration } // DoCommitInput is the input parameters for function DoCommit. type DoCommitInput struct { - // Db is the underlying database connection object. - Db *sql.DB + // Db is the underlying database connection object. + Db *sql.DB - // Tx is the underlying transaction object. - Tx *sql.Tx + // Tx is the underlying transaction object. + Tx *sql.Tx - // Stmt is the prepared statement object. - Stmt *sql.Stmt + // Stmt is the prepared statement object. + Stmt *sql.Stmt - // Link is the common database function wrapper interface. - Link Link + // Link is the common database function wrapper interface. + Link Link - // Sql is the SQL string to be executed. - Sql string + // Sql is the SQL string to be executed. + Sql string - // Args is the arguments for SQL placeholders. - Args []interface{} + // Args is the arguments for SQL placeholders. + Args []interface{} - // Type indicates the type of SQL operation. - Type SqlType + // Type indicates the type of SQL operation. + Type SqlType - // TxOptions specifies the transaction options. - TxOptions sql.TxOptions + // TxOptions specifies the transaction options. + TxOptions sql.TxOptions - // TxCancelFunc is the context cancel function for transaction. - TxCancelFunc context.CancelFunc + // TxCancelFunc is the context cancel function for transaction. + TxCancelFunc context.CancelFunc - // IsTransaction indicates whether current operation is in transaction. - IsTransaction bool + // IsTransaction indicates whether current operation is in transaction. + IsTransaction bool } // DoCommitOutput is the output parameters for function DoCommit. type DoCommitOutput struct { - // Result is the result of exec statement. - Result sql.Result + // Result is the result of exec statement. + Result sql.Result - // Records is the result of query statement. - Records []Record + // Records is the result of query statement. + Records []Record - // Stmt is the Statement object result for Prepare. - Stmt *Stmt + // Stmt is the Statement object result for Prepare. + Stmt *Stmt - // Tx is the transaction object result for Begin. - Tx TX + // Tx is the transaction object result for Begin. + Tx TX - // RawResult is the underlying result, which might be sql.Result/*sql.Rows/*sql.Row. - RawResult interface{} + // RawResult is the underlying result, which might be sql.Result/*sql.Rows/*sql.Row. + RawResult interface{} } // Driver is the interface for integrating sql drivers into package gdb. type Driver interface { - // New creates and returns a database object for specified database server. - New(core *Core, node *ConfigNode) (DB, error) + // New creates and returns a database object for specified database server. + New(core *Core, node *ConfigNode) (DB, error) } // Link is a common database function wrapper interface. // Note that, any operation using `Link` will have no SQL logging. type Link interface { - QueryContext(ctx context.Context, sql string, args ...interface{}) (*sql.Rows, error) - ExecContext(ctx context.Context, sql string, args ...interface{}) (sql.Result, error) - PrepareContext(ctx context.Context, sql string) (*sql.Stmt, error) - IsOnMaster() bool - IsTransaction() bool + QueryContext(ctx context.Context, sql string, args ...interface{}) (*sql.Rows, error) + ExecContext(ctx context.Context, sql string, args ...interface{}) (sql.Result, error) + PrepareContext(ctx context.Context, sql string) (*sql.Stmt, error) + IsOnMaster() bool + IsTransaction() bool } // Sql is the sql recording struct. type Sql struct { - Sql string // SQL string(may contain reserved char '?'). - Type SqlType // SQL operation type. - Args []interface{} // Arguments for this sql. - Format string // Formatted sql which contains arguments in the sql. - Error error // Execution result. - Start int64 // Start execution timestamp in milliseconds. - End int64 // End execution timestamp in milliseconds. - Group string // Group is the group name of the configuration that the sql is executed from. - Schema string // Schema is the schema name of the configuration that the sql is executed from. - IsTransaction bool // IsTransaction marks whether this sql is executed in transaction. - RowsAffected int64 // RowsAffected marks retrieved or affected number with current sql statement. + Sql string // SQL string(may contain reserved char '?'). + Type SqlType // SQL operation type. + Args []interface{} // Arguments for this sql. + Format string // Formatted sql which contains arguments in the sql. + Error error // Execution result. + Start int64 // Start execution timestamp in milliseconds. + End int64 // End execution timestamp in milliseconds. + Group string // Group is the group name of the configuration that the sql is executed from. + Schema string // Schema is the schema name of the configuration that the sql is executed from. + IsTransaction bool // IsTransaction marks whether this sql is executed in transaction. + RowsAffected int64 // RowsAffected marks retrieved or affected number with current sql statement. } // DoInsertOption is the input struct for function DoInsert. type DoInsertOption struct { - // OnDuplicateStr is the custom string for `on duplicated` statement. - OnDuplicateStr string + // OnDuplicateStr is the custom string for `on duplicated` statement. + OnDuplicateStr string - // OnDuplicateMap is the custom key-value map from `OnDuplicateEx` function for `on duplicated` statement. - OnDuplicateMap map[string]interface{} + // OnDuplicateMap is the custom key-value map from `OnDuplicateEx` function for `on duplicated` statement. + OnDuplicateMap map[string]interface{} - // OnConflict is the custom conflict key of upsert clause, if the database needs it. - OnConflict []string + // OnConflict is the custom conflict key of upsert clause, if the database needs it. + OnConflict []string - // InsertOption is the insert operation in constant value. - InsertOption InsertOption + // InsertOption is the insert operation in constant value. + InsertOption InsertOption - // BatchCount is the batch count for batch inserting. - BatchCount int + // BatchCount is the batch count for batch inserting. + BatchCount int } // TableField is the struct for table field. type TableField struct { - // Index is for ordering purpose as map is unordered. - Index int + // Index is for ordering purpose as map is unordered. + Index int - // Name is the field name. - Name string + // Name is the field name. + Name string - // Type is the field type. Eg: 'int(10) unsigned', 'varchar(64)'. - Type string + // Type is the field type. Eg: 'int(10) unsigned', 'varchar(64)'. + Type string - // Null is whether the field can be null or not. - Null bool + // Null is whether the field can be null or not. + Null bool - // Key is the index information(empty if it's not an index). Eg: PRI, MUL. - Key string + // Key is the index information(empty if it's not an index). Eg: PRI, MUL. + Key string - // Default is the default value for the field. - Default interface{} + // Default is the default value for the field. + Default interface{} - // Extra is the extra information. Eg: auto_increment. - Extra string + // Extra is the extra information. Eg: auto_increment. + Extra string - // Comment is the field comment. - Comment string + // Comment is the field comment. + Comment string } // Counter is the type for update count. type Counter struct { - // Field is the field name. - Field string + // Field is the field name. + Field string - // Value is the value. - Value float64 + // Value is the value. + Value float64 } type ( - // Raw is a raw sql that will not be treated as argument but as a direct sql part. - Raw string + // Raw is a raw sql that will not be treated as argument but as a direct sql part. + Raw string - // Value is the field value type. - Value = *gvar.Var + // Value is the field value type. + Value = *fieldvar.Var - // Record is the row record of the table. - Record map[string]Value + // Record is the row record of the table. + Record map[string]Value - // Result is the row record array. - Result []Record + // Result is the row record array. + Result []Record - // Map is alias of map[string]interface{}, which is the most common usage map type. - Map = map[string]interface{} + // Map is alias of map[string]interface{}, which is the most common usage map type. + Map = map[string]interface{} - // List is type of map array. - List = []Map + // List is type of map array. + List = []Map ) type CatchSQLManager struct { - // SQLArray is the array of sql. - SQLArray *garray.StrArray + // SQLArray is the array of sql. + SQLArray *garray.StrArray - // DoCommit marks it will be committed to underlying driver or not. - DoCommit bool + // DoCommit marks it will be committed to underlying driver or not. + DoCommit bool } const ( - defaultModelSafe = false - defaultCharset = `utf8` - defaultProtocol = `tcp` - unionTypeNormal = 0 - unionTypeAll = 1 - defaultMaxIdleConnCount = 10 // Max idle connection count in pool. - defaultMaxOpenConnCount = 0 // Max open connection count in pool. Default is no limit. - defaultMaxConnLifeTime = 30 * time.Second // Max lifetime for per connection in pool in seconds. - cachePrefixTableFields = `TableFields:` - cachePrefixSelectCache = `SelectCache:` - commandEnvKeyForDryRun = "gf.gdb.dryrun" - modelForDaoSuffix = `ForDao` - dbRoleSlave = `slave` - ctxKeyForDB gctx.StrKey = `CtxKeyForDB` - ctxKeyCatchSQL gctx.StrKey = `CtxKeyCatchSQL` - ctxKeyInternalProducedSQL gctx.StrKey = `CtxKeyInternalProducedSQL` - - linkPattern = `^(\w+):(.*?):(.*?)@(\w+?)\((.+?)\)/{0,1}([^\?]*)\?{0,1}(.*?)$` - linkPatternDescription = `type:username:password@protocol(host:port)/dbname?param1=value1&...¶mN=valueN` + defaultModelSafe = false + defaultCharset = `utf8` + defaultProtocol = `tcp` + unionTypeNormal = 0 + unionTypeAll = 1 + defaultMaxIdleConnCount = 10 // Max idle connection count in pool. + defaultMaxOpenConnCount = 0 // Max open connection count in pool. Default is no limit. + defaultMaxConnLifeTime = 30 * time.Second // Max lifetime for per connection in pool in seconds. + cachePrefixTableFields = `TableFields:` + cachePrefixSelectCache = `SelectCache:` + commandEnvKeyForDryRun = "gf.gdb.dryrun" + modelForDaoSuffix = `ForDao` + dbRoleSlave = `slave` + ctxKeyForDB gctx.StrKey = `CtxKeyForDB` + ctxKeyCatchSQL gctx.StrKey = `CtxKeyCatchSQL` + ctxKeyInternalProducedSQL gctx.StrKey = `CtxKeyInternalProducedSQL` + + linkPattern = `^(\w+):(.*?):(.*?)@(\w+?)\((.+?)\)/{0,1}([^\?]*)\?{0,1}(.*?)$` + linkPatternDescription = `type:username:password@protocol(host:port)/dbname?param1=value1&...¶mN=valueN` ) type ctxTimeoutType int const ( - ctxTimeoutTypeExec ctxTimeoutType = iota - ctxTimeoutTypeQuery - ctxTimeoutTypePrepare - ctxTimeoutTypeTrans + ctxTimeoutTypeExec ctxTimeoutType = iota + ctxTimeoutTypeQuery + ctxTimeoutTypePrepare + ctxTimeoutTypeTrans ) type SelectType int const ( - SelectTypeDefault SelectType = iota - SelectTypeCount - SelectTypeValue - SelectTypeArray + SelectTypeDefault SelectType = iota + SelectTypeCount + SelectTypeValue + SelectTypeArray ) type joinOperator string const ( - joinOperatorLeft joinOperator = "LEFT" - joinOperatorRight joinOperator = "RIGHT" - joinOperatorInner joinOperator = "INNER" + joinOperatorLeft joinOperator = "LEFT" + joinOperatorRight joinOperator = "RIGHT" + joinOperatorInner joinOperator = "INNER" ) type InsertOption int const ( - InsertOptionDefault InsertOption = iota - InsertOptionReplace - InsertOptionSave - InsertOptionIgnore + InsertOptionDefault InsertOption = iota + InsertOptionReplace + InsertOptionSave + InsertOptionIgnore ) const ( - InsertOperationInsert = "INSERT" - InsertOperationReplace = "REPLACE" - InsertOperationIgnore = "INSERT IGNORE" - InsertOnDuplicateKeyUpdate = "ON DUPLICATE KEY UPDATE" + InsertOperationInsert = "INSERT" + InsertOperationReplace = "REPLACE" + InsertOperationIgnore = "INSERT IGNORE" + InsertOnDuplicateKeyUpdate = "ON DUPLICATE KEY UPDATE" ) type SqlType string const ( - SqlTypeBegin SqlType = "DB.Begin" - SqlTypeTXCommit SqlType = "TX.Commit" - SqlTypeTXRollback SqlType = "TX.Rollback" - SqlTypeExecContext SqlType = "DB.ExecContext" - SqlTypeQueryContext SqlType = "DB.QueryContext" - SqlTypePrepareContext SqlType = "DB.PrepareContext" - SqlTypeStmtExecContext SqlType = "DB.Statement.ExecContext" - SqlTypeStmtQueryContext SqlType = "DB.Statement.QueryContext" - SqlTypeStmtQueryRowContext SqlType = "DB.Statement.QueryRowContext" + SqlTypeBegin SqlType = "DB.Begin" + SqlTypeTXCommit SqlType = "TX.Commit" + SqlTypeTXRollback SqlType = "TX.Rollback" + SqlTypeExecContext SqlType = "DB.ExecContext" + SqlTypeQueryContext SqlType = "DB.QueryContext" + SqlTypePrepareContext SqlType = "DB.PrepareContext" + SqlTypeStmtExecContext SqlType = "DB.Statement.ExecContext" + SqlTypeStmtQueryContext SqlType = "DB.Statement.QueryContext" + SqlTypeStmtQueryRowContext SqlType = "DB.Statement.QueryRowContext" ) -type LocalType string +type LocalType = defines.LocalType const ( - LocalTypeUndefined LocalType = "" - LocalTypeString LocalType = "string" - LocalTypeTime LocalType = "time" - LocalTypeDate LocalType = "date" - LocalTypeDatetime LocalType = "datetime" - LocalTypeInt LocalType = "int" - LocalTypeUint LocalType = "uint" - LocalTypeInt64 LocalType = "int64" - LocalTypeUint64 LocalType = "uint64" - LocalTypeIntSlice LocalType = "[]int" - LocalTypeInt64Slice LocalType = "[]int64" - LocalTypeUint64Slice LocalType = "[]uint64" - LocalTypeStringSlice LocalType = "[]string" - LocalTypeInt64Bytes LocalType = "int64-bytes" - LocalTypeUint64Bytes LocalType = "uint64-bytes" - LocalTypeFloat32 LocalType = "float32" - LocalTypeFloat64 LocalType = "float64" - LocalTypeBytes LocalType = "[]byte" - LocalTypeBool LocalType = "bool" - LocalTypeJson LocalType = "json" - LocalTypeJsonb LocalType = "jsonb" + LocalTypeUndefined = defines.LocalTypeUndefined + LocalTypeString = defines.LocalTypeString + LocalTypeTime = defines.LocalTypeTime + LocalTypeDate = defines.LocalTypeDate + LocalTypeDatetime = defines.LocalTypeDatetime + LocalTypeInt = defines.LocalTypeInt + LocalTypeUint = defines.LocalTypeUint + LocalTypeInt64 = defines.LocalTypeInt64 + LocalTypeUint64 = defines.LocalTypeUint64 + LocalTypeIntSlice = defines.LocalTypeIntSlice + LocalTypeInt64Slice = defines.LocalTypeInt64Slice + LocalTypeUint64Slice = defines.LocalTypeUint64Slice + LocalTypeStringSlice = defines.LocalTypeStringSlice + LocalTypeInt64Bytes = defines.LocalTypeInt64Bytes + LocalTypeUint64Bytes = defines.LocalTypeUint64Bytes + LocalTypeFloat32 = defines.LocalTypeFloat32 + LocalTypeFloat64 = defines.LocalTypeFloat64 + LocalTypeBytes = defines.LocalTypeBytes + LocalTypeBool = defines.LocalTypeBool + LocalTypeJson = defines.LocalTypeJson + LocalTypeJsonb = defines.LocalTypeJsonb ) const ( - fieldTypeBinary = "binary" - fieldTypeVarbinary = "varbinary" - fieldTypeBlob = "blob" - fieldTypeTinyblob = "tinyblob" - fieldTypeMediumblob = "mediumblob" - fieldTypeLongblob = "longblob" - fieldTypeInt = "int" - fieldTypeTinyint = "tinyint" - fieldTypeSmallInt = "small_int" - fieldTypeSmallint = "smallint" - fieldTypeMediumInt = "medium_int" - fieldTypeMediumint = "mediumint" - fieldTypeSerial = "serial" - fieldTypeBigInt = "big_int" - fieldTypeBigint = "bigint" - fieldTypeBigserial = "bigserial" - fieldTypeReal = "real" - fieldTypeFloat = "float" - fieldTypeDouble = "double" - fieldTypeDecimal = "decimal" - fieldTypeMoney = "money" - fieldTypeNumeric = "numeric" - fieldTypeSmallmoney = "smallmoney" - fieldTypeBool = "bool" - fieldTypeBit = "bit" - fieldTypeYear = "year" // YYYY - fieldTypeDate = "date" // YYYY-MM-DD - fieldTypeTime = "time" // HH:MM:SS - fieldTypeDatetime = "datetime" // YYYY-MM-DD HH:MM:SS - fieldTypeTimestamp = "timestamp" // YYYYMMDD HHMMSS - fieldTypeTimestampz = "timestamptz" - fieldTypeJson = "json" - fieldTypeJsonb = "jsonb" + fieldTypeBinary = "binary" + fieldTypeVarbinary = "varbinary" + fieldTypeBlob = "blob" + fieldTypeTinyblob = "tinyblob" + fieldTypeMediumblob = "mediumblob" + fieldTypeLongblob = "longblob" + fieldTypeInt = "int" + fieldTypeTinyint = "tinyint" + fieldTypeSmallInt = "small_int" + fieldTypeSmallint = "smallint" + fieldTypeMediumInt = "medium_int" + fieldTypeMediumint = "mediumint" + fieldTypeSerial = "serial" + fieldTypeBigInt = "big_int" + fieldTypeBigint = "bigint" + fieldTypeBigserial = "bigserial" + fieldTypeReal = "real" + fieldTypeFloat = "float" + fieldTypeDouble = "double" + fieldTypeDecimal = "decimal" + fieldTypeMoney = "money" + fieldTypeNumeric = "numeric" + fieldTypeSmallmoney = "smallmoney" + fieldTypeBool = "bool" + fieldTypeBit = "bit" + fieldTypeYear = "year" // YYYY + fieldTypeDate = "date" // YYYY-MM-DD + fieldTypeTime = "time" // HH:MM:SS + fieldTypeDatetime = "datetime" // YYYY-MM-DD HH:MM:SS + fieldTypeTimestamp = "timestamp" // YYYYMMDD HHMMSS + fieldTypeTimestampz = "timestamptz" + fieldTypeJson = "json" + fieldTypeJsonb = "jsonb" ) var ( - // instances is the management map for instances. - instances = gmap.NewStrAnyMap(true) + // instances is the management map for instances. + instances = gmap.NewStrAnyMap(true) - // driverMap manages all custom registered driver. - driverMap = map[string]Driver{} + // driverMap manages all custom registered driver. + driverMap = map[string]Driver{} - // lastOperatorRegPattern is the regular expression pattern for a string - // which has operator at its tail. - lastOperatorRegPattern = `[<>=]+\s*$` + // lastOperatorRegPattern is the regular expression pattern for a string + // which has operator at its tail. + lastOperatorRegPattern = `[<>=]+\s*$` - // regularFieldNameRegPattern is the regular expression pattern for a string - // which is a regular field name of table. - regularFieldNameRegPattern = `^[\w\.\-]+$` + // regularFieldNameRegPattern is the regular expression pattern for a string + // which is a regular field name of table. + regularFieldNameRegPattern = `^[\w\.\-]+$` - // regularFieldNameWithCommaRegPattern is the regular expression pattern for one or more strings - // which are regular field names of table, multiple field names joined with char ','. - regularFieldNameWithCommaRegPattern = `^[\w\.\-,\s]+$` + // regularFieldNameWithCommaRegPattern is the regular expression pattern for one or more strings + // which are regular field names of table, multiple field names joined with char ','. + regularFieldNameWithCommaRegPattern = `^[\w\.\-,\s]+$` - // regularFieldNameWithoutDotRegPattern is similar to regularFieldNameRegPattern but not allows '.'. - // Note that, although some databases allow char '.' in the field name, but it here does not allow '.' - // in the field name as it conflicts with "db.table.field" pattern in SOME situations. - regularFieldNameWithoutDotRegPattern = `^[\w\-]+$` + // regularFieldNameWithoutDotRegPattern is similar to regularFieldNameRegPattern but not allows '.'. + // Note that, although some databases allow char '.' in the field name, but it here does not allow '.' + // in the field name as it conflicts with "db.table.field" pattern in SOME situations. + regularFieldNameWithoutDotRegPattern = `^[\w\-]+$` - // allDryRun sets dry-run feature for all database connections. - // It is commonly used for command options for convenience. - allDryRun = false + // allDryRun sets dry-run feature for all database connections. + // It is commonly used for command options for convenience. + allDryRun = false ) func init() { - // allDryRun is initialized from environment or command options. - allDryRun = gcmd.GetOptWithEnv(commandEnvKeyForDryRun, false).Bool() + // allDryRun is initialized from environment or command options. + allDryRun = gcmd.GetOptWithEnv(commandEnvKeyForDryRun, false).Bool() } // Register registers custom database driver to gdb. func Register(name string, driver Driver) error { - driverMap[name] = newDriverWrapper(driver) - return nil + driverMap[name] = newDriverWrapper(driver) + return nil } // New creates and returns an ORM object with given configuration node. func New(node ConfigNode) (db DB, err error) { - return newDBByConfigNode(&node, "") + return newDBByConfigNode(&node, "") } // NewByGroup creates and returns an ORM object with global configurations. // The parameter `name` specifies the configuration group name, // which is DefaultGroupName in default. func NewByGroup(group ...string) (db DB, err error) { - groupName := configs.group - if len(group) > 0 && group[0] != "" { - groupName = group[0] - } - configs.RLock() - defer configs.RUnlock() - - if len(configs.config) < 1 { - return nil, gerror.NewCode( - gcode.CodeInvalidConfiguration, - "database configuration is empty, please set the database configuration before using", - ) - } - if _, ok := configs.config[groupName]; ok { - var node *ConfigNode - if node, err = getConfigNodeByGroup(groupName, true); err == nil { - return newDBByConfigNode(node, groupName) - } - return nil, err - } - return nil, gerror.NewCodef( - gcode.CodeInvalidConfiguration, - `database configuration node "%s" is not found, did you misspell group name "%s" or miss the database configuration?`, - groupName, groupName, - ) + groupName := configs.group + if len(group) > 0 && group[0] != "" { + groupName = group[0] + } + configs.RLock() + defer configs.RUnlock() + + if len(configs.config) < 1 { + return nil, gerror.NewCode( + gcode.CodeInvalidConfiguration, + "database configuration is empty, please set the database configuration before using", + ) + } + if _, ok := configs.config[groupName]; ok { + var node *ConfigNode + if node, err = getConfigNodeByGroup(groupName, true); err == nil { + return newDBByConfigNode(node, groupName) + } + return nil, err + } + return nil, gerror.NewCodef( + gcode.CodeInvalidConfiguration, + `database configuration node "%s" is not found, did you misspell group name "%s" or miss the database configuration?`, + groupName, groupName, + ) } // newDBByConfigNode creates and returns an ORM object with given configuration node and group name. @@ -912,54 +913,54 @@ func NewByGroup(group ...string) (db DB, err error) { // The parameter `node` is used for DB creation, not for underlying connection creation. // So all db type configurations in the same group should be the same. func newDBByConfigNode(node *ConfigNode, group string) (db DB, err error) { - if node.Link != "" { - node, err = parseConfigNodeLink(node) - if err != nil { - return - } - } - c := &Core{ - group: group, - debug: gtype.NewBool(), - cache: gcache.New(), - links: gmap.New(true), - logger: glog.New(), - config: node, - innerMemCache: gcache.New(), - dynamicConfig: dynamicConfig{ - MaxIdleConnCount: node.MaxIdleConnCount, - MaxOpenConnCount: node.MaxOpenConnCount, - MaxConnLifeTime: node.MaxConnLifeTime, - }, - } - if v, ok := driverMap[node.Type]; ok { - if c.db, err = v.New(c, node); err != nil { - return nil, err - } - return c.db, nil - } - errorMsg := `cannot find database driver for specified database type "%s"` - errorMsg += `, did you misspell type name "%s" or forget importing the database driver? ` - errorMsg += `possible reference: https://github.com/gogf/gf/tree/master/contrib/drivers` - return nil, gerror.NewCodef(gcode.CodeInvalidConfiguration, errorMsg, node.Type, node.Type) + if node.Link != "" { + node, err = parseConfigNodeLink(node) + if err != nil { + return + } + } + c := &Core{ + group: group, + debug: gtype.NewBool(), + cache: gcache.New(), + links: gmap.New(true), + logger: glog.New(), + config: node, + innerMemCache: gcache.New(), + dynamicConfig: dynamicConfig{ + MaxIdleConnCount: node.MaxIdleConnCount, + MaxOpenConnCount: node.MaxOpenConnCount, + MaxConnLifeTime: node.MaxConnLifeTime, + }, + } + if v, ok := driverMap[node.Type]; ok { + if c.db, err = v.New(c, node); err != nil { + return nil, err + } + return c.db, nil + } + errorMsg := `cannot find database driver for specified database type "%s"` + errorMsg += `, did you misspell type name "%s" or forget importing the database driver? ` + errorMsg += `possible reference: https://github.com/gogf/gf/tree/master/contrib/drivers` + return nil, gerror.NewCodef(gcode.CodeInvalidConfiguration, errorMsg, node.Type, node.Type) } // Instance returns an instance for DB operations. // The parameter `name` specifies the configuration group name, // which is DefaultGroupName in default. func Instance(name ...string) (db DB, err error) { - group := configs.group - if len(name) > 0 && name[0] != "" { - group = name[0] - } - v := instances.GetOrSetFuncLock(group, func() interface{} { - db, err = NewByGroup(group) - return db - }) - if v != nil { - return v.(DB), nil - } - return + group := configs.group + if len(name) > 0 && name[0] != "" { + group = name[0] + } + v := instances.GetOrSetFuncLock(group, func() interface{} { + db, err = NewByGroup(group) + return db + }) + if v != nil { + return v.(DB), nil + } + return } // getConfigNodeByGroup calculates and returns a configuration node of given group. It @@ -970,39 +971,39 @@ func Instance(name ...string) (db DB, err error) { // The parameter `master` specifies whether retrieving a master node, or else a slave node // if master-slave nodes are configured. func getConfigNodeByGroup(group string, master bool) (*ConfigNode, error) { - if list, ok := configs.config[group]; ok { - // Separates master and slave configuration nodes array. - var ( - masterList = make(ConfigGroup, 0) - slaveList = make(ConfigGroup, 0) - ) - for i := 0; i < len(list); i++ { - if list[i].Role == dbRoleSlave { - slaveList = append(slaveList, list[i]) - } else { - masterList = append(masterList, list[i]) - } - } - if len(masterList) < 1 { - return nil, gerror.NewCode( - gcode.CodeInvalidConfiguration, - "at least one master node configuration's need to make sense", - ) - } - if len(slaveList) < 1 { - slaveList = masterList - } - if master { - return getConfigNodeByWeight(masterList), nil - } else { - return getConfigNodeByWeight(slaveList), nil - } - } - return nil, gerror.NewCodef( - gcode.CodeInvalidConfiguration, - "empty database configuration for item name '%s'", - group, - ) + if list, ok := configs.config[group]; ok { + // Separates master and slave configuration nodes array. + var ( + masterList = make(ConfigGroup, 0) + slaveList = make(ConfigGroup, 0) + ) + for i := 0; i < len(list); i++ { + if list[i].Role == dbRoleSlave { + slaveList = append(slaveList, list[i]) + } else { + masterList = append(masterList, list[i]) + } + } + if len(masterList) < 1 { + return nil, gerror.NewCode( + gcode.CodeInvalidConfiguration, + "at least one master node configuration's need to make sense", + ) + } + if len(slaveList) < 1 { + slaveList = masterList + } + if master { + return getConfigNodeByWeight(masterList), nil + } else { + return getConfigNodeByWeight(slaveList), nil + } + } + return nil, gerror.NewCodef( + gcode.CodeInvalidConfiguration, + "empty database configuration for item name '%s'", + group, + ) } // getConfigNodeByWeight calculates the configuration weights and randomly returns a node. @@ -1013,116 +1014,116 @@ func getConfigNodeByGroup(group string, master bool) (*ConfigNode, error) { // 2. Node1 weight range is [0, 99], and node2 weight range is [100, 199], ratio is 1:1; // 3. If the random number is 99, it then chooses and returns node1;. func getConfigNodeByWeight(cg ConfigGroup) *ConfigNode { - if len(cg) < 2 { - return &cg[0] - } - var total int - for i := 0; i < len(cg); i++ { - total += cg[i].Weight * 100 - } - // If total is 0 means all the nodes have no weight attribute configured. - // It then defaults each node's weight attribute to 1. - if total == 0 { - for i := 0; i < len(cg); i++ { - cg[i].Weight = 1 - total += cg[i].Weight * 100 - } - } - // Exclude the right border value. - var ( - minWeight = 0 - maxWeight = 0 - random = grand.N(0, total-1) - ) - for i := 0; i < len(cg); i++ { - maxWeight = minWeight + cg[i].Weight*100 - if random >= minWeight && random < maxWeight { - // ==================================================== - // Return a COPY of the ConfigNode. - // ==================================================== - node := ConfigNode{} - node = cg[i] - return &node - } - minWeight = maxWeight - } - return nil + if len(cg) < 2 { + return &cg[0] + } + var total int + for i := 0; i < len(cg); i++ { + total += cg[i].Weight * 100 + } + // If total is 0 means all the nodes have no weight attribute configured. + // It then defaults each node's weight attribute to 1. + if total == 0 { + for i := 0; i < len(cg); i++ { + cg[i].Weight = 1 + total += cg[i].Weight * 100 + } + } + // Exclude the right border value. + var ( + minWeight = 0 + maxWeight = 0 + random = grand.N(0, total-1) + ) + for i := 0; i < len(cg); i++ { + maxWeight = minWeight + cg[i].Weight*100 + if random >= minWeight && random < maxWeight { + // ==================================================== + // Return a COPY of the ConfigNode. + // ==================================================== + node := ConfigNode{} + node = cg[i] + return &node + } + minWeight = maxWeight + } + return nil } // getSqlDb retrieves and returns an underlying database connection object. // The parameter `master` specifies whether retrieves master node connection if // master-slave nodes are configured. func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error) { - var ( - node *ConfigNode - ctx = c.db.GetCtx() - ) - if c.group != "" { - // Load balance. - configs.RLock() - defer configs.RUnlock() - // Value COPY for node. - // The returned node is a clone of configuration node, which is safe for later modification. - node, err = getConfigNodeByGroup(c.group, master) - if err != nil { - return nil, err - } - } else { - // Value COPY for node. - n := *c.db.GetConfig() - node = &n - } - if node.Charset == "" { - node.Charset = defaultCharset - } - // Changes the schema. - nodeSchema := gutil.GetOrDefaultStr(c.schema, schema...) - if nodeSchema != "" { - node.Name = nodeSchema - } - // Update the configuration object in internal data. - if err = c.setConfigNodeToCtx(ctx, node); err != nil { - return - } - - // Cache the underlying connection pool object by node. - var ( - instanceCacheFunc = func() interface{} { - if sqlDb, err = c.db.Open(node); err != nil { - return nil - } - if sqlDb == nil { - return nil - } - if c.dynamicConfig.MaxIdleConnCount > 0 { - sqlDb.SetMaxIdleConns(c.dynamicConfig.MaxIdleConnCount) - } else { - sqlDb.SetMaxIdleConns(defaultMaxIdleConnCount) - } - if c.dynamicConfig.MaxOpenConnCount > 0 { - sqlDb.SetMaxOpenConns(c.dynamicConfig.MaxOpenConnCount) - } else { - sqlDb.SetMaxOpenConns(defaultMaxOpenConnCount) - } - if c.dynamicConfig.MaxConnLifeTime > 0 { - sqlDb.SetConnMaxLifetime(c.dynamicConfig.MaxConnLifeTime) - } else { - sqlDb.SetConnMaxLifetime(defaultMaxConnLifeTime) - } - return sqlDb - } - // it here uses NODE VALUE not pointer as the cache key, in case of oracle ORA-12516 error. - instanceValue = c.links.GetOrSetFuncLock(*node, instanceCacheFunc) - ) - if instanceValue != nil && sqlDb == nil { - // It reads from instance map. - sqlDb = instanceValue.(*sql.DB) - } - if node.Debug { - c.db.SetDebug(node.Debug) - } - if node.DryRun { - c.db.SetDryRun(node.DryRun) - } - return + var ( + node *ConfigNode + ctx = c.db.GetCtx() + ) + if c.group != "" { + // Load balance. + configs.RLock() + defer configs.RUnlock() + // Value COPY for node. + // The returned node is a clone of configuration node, which is safe for later modification. + node, err = getConfigNodeByGroup(c.group, master) + if err != nil { + return nil, err + } + } else { + // Value COPY for node. + n := *c.db.GetConfig() + node = &n + } + if node.Charset == "" { + node.Charset = defaultCharset + } + // Changes the schema. + nodeSchema := gutil.GetOrDefaultStr(c.schema, schema...) + if nodeSchema != "" { + node.Name = nodeSchema + } + // Update the configuration object in internal data. + if err = c.setConfigNodeToCtx(ctx, node); err != nil { + return + } + + // Cache the underlying connection pool object by node. + var ( + instanceCacheFunc = func() interface{} { + if sqlDb, err = c.db.Open(node); err != nil { + return nil + } + if sqlDb == nil { + return nil + } + if c.dynamicConfig.MaxIdleConnCount > 0 { + sqlDb.SetMaxIdleConns(c.dynamicConfig.MaxIdleConnCount) + } else { + sqlDb.SetMaxIdleConns(defaultMaxIdleConnCount) + } + if c.dynamicConfig.MaxOpenConnCount > 0 { + sqlDb.SetMaxOpenConns(c.dynamicConfig.MaxOpenConnCount) + } else { + sqlDb.SetMaxOpenConns(defaultMaxOpenConnCount) + } + if c.dynamicConfig.MaxConnLifeTime > 0 { + sqlDb.SetConnMaxLifetime(c.dynamicConfig.MaxConnLifeTime) + } else { + sqlDb.SetConnMaxLifetime(defaultMaxConnLifeTime) + } + return sqlDb + } + // it here uses NODE VALUE not pointer as the cache key, in case of oracle ORA-12516 error. + instanceValue = c.links.GetOrSetFuncLock(*node, instanceCacheFunc) + ) + if instanceValue != nil && sqlDb == nil { + // It reads from instance map. + sqlDb = instanceValue.(*sql.DB) + } + if node.Debug { + c.db.SetDebug(node.Debug) + } + if node.DryRun { + c.db.SetDryRun(node.DryRun) + } + return } diff --git a/database/gdb/gdb_core.go b/database/gdb/gdb_core.go index 50971611258..f1cd226eaa6 100644 --- a/database/gdb/gdb_core.go +++ b/database/gdb/gdb_core.go @@ -8,30 +8,29 @@ package gdb import ( - "context" - "database/sql" - "fmt" - "reflect" - "strings" - - "github.com/gogf/gf/v2/container/gmap" - "github.com/gogf/gf/v2/container/gset" - "github.com/gogf/gf/v2/container/gvar" - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/intlog" - "github.com/gogf/gf/v2/internal/reflection" - "github.com/gogf/gf/v2/internal/utils" - "github.com/gogf/gf/v2/os/gcache" - "github.com/gogf/gf/v2/text/gregex" - "github.com/gogf/gf/v2/text/gstr" - "github.com/gogf/gf/v2/util/gconv" - "github.com/gogf/gf/v2/util/gutil" + "context" + "database/sql" + "fmt" + "reflect" + "strings" + + "github.com/gogf/gf/v2/container/gmap" + "github.com/gogf/gf/v2/container/gset" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/intlog" + "github.com/gogf/gf/v2/internal/reflection" + "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/os/gcache" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/gutil" ) // GetCore returns the underlying *Core object. func (c *Core) GetCore() *Core { - return c + return c } // Ctx is a chaining function, which creates and returns a new DB that is a shallow copy @@ -39,67 +38,67 @@ func (c *Core) GetCore() *Core { // Note that this returned DB object can be used only once, so do not assign it to // a global or package variable for long using. func (c *Core) Ctx(ctx context.Context) DB { - if ctx == nil { - return c.db - } - // It makes a shallow copy of current db and changes its context for next chaining operation. - var ( - err error - newCore = &Core{} - configNode = c.db.GetConfig() - ) - *newCore = *c - // It creates a new DB object(NOT NEW CONNECTION), which is commonly a wrapper for object `Core`. - newCore.db, err = driverMap[configNode.Type].New(newCore, configNode) - if err != nil { - // It is really a serious error here. - // Do not let it continue. - panic(err) - } - newCore.ctx = WithDB(ctx, newCore.db) - newCore.ctx = c.injectInternalCtxData(newCore.ctx) - return newCore.db + if ctx == nil { + return c.db + } + // It makes a shallow copy of current db and changes its context for next chaining operation. + var ( + err error + newCore = &Core{} + configNode = c.db.GetConfig() + ) + *newCore = *c + // It creates a new DB object(NOT NEW CONNECTION), which is commonly a wrapper for object `Core`. + newCore.db, err = driverMap[configNode.Type].New(newCore, configNode) + if err != nil { + // It is really a serious error here. + // Do not let it continue. + panic(err) + } + newCore.ctx = WithDB(ctx, newCore.db) + newCore.ctx = c.injectInternalCtxData(newCore.ctx) + return newCore.db } // GetCtx returns the context for current DB. // It returns `context.Background()` is there's no context previously set. func (c *Core) GetCtx() context.Context { - ctx := c.ctx - if ctx == nil { - ctx = context.TODO() - } - return c.injectInternalCtxData(ctx) + ctx := c.ctx + if ctx == nil { + ctx = context.TODO() + } + return c.injectInternalCtxData(ctx) } // GetCtxTimeout returns the context and cancel function for specified timeout type. func (c *Core) GetCtxTimeout(ctx context.Context, timeoutType ctxTimeoutType) (context.Context, context.CancelFunc) { - if ctx == nil { - ctx = c.db.GetCtx() - } else { - ctx = context.WithValue(ctx, "WrappedByGetCtxTimeout", nil) - } - var config = c.db.GetConfig() - switch timeoutType { - case ctxTimeoutTypeExec: - if c.db.GetConfig().ExecTimeout > 0 { - return context.WithTimeout(ctx, config.ExecTimeout) - } - case ctxTimeoutTypeQuery: - if c.db.GetConfig().QueryTimeout > 0 { - return context.WithTimeout(ctx, config.QueryTimeout) - } - case ctxTimeoutTypePrepare: - if c.db.GetConfig().PrepareTimeout > 0 { - return context.WithTimeout(ctx, config.PrepareTimeout) - } - case ctxTimeoutTypeTrans: - if c.db.GetConfig().TranTimeout > 0 { - return context.WithTimeout(ctx, config.TranTimeout) - } - default: - panic(gerror.NewCodef(gcode.CodeInvalidParameter, "invalid context timeout type: %d", timeoutType)) - } - return ctx, func() {} + if ctx == nil { + ctx = c.db.GetCtx() + } else { + ctx = context.WithValue(ctx, "WrappedByGetCtxTimeout", nil) + } + var config = c.db.GetConfig() + switch timeoutType { + case ctxTimeoutTypeExec: + if c.db.GetConfig().ExecTimeout > 0 { + return context.WithTimeout(ctx, config.ExecTimeout) + } + case ctxTimeoutTypeQuery: + if c.db.GetConfig().QueryTimeout > 0 { + return context.WithTimeout(ctx, config.QueryTimeout) + } + case ctxTimeoutTypePrepare: + if c.db.GetConfig().PrepareTimeout > 0 { + return context.WithTimeout(ctx, config.PrepareTimeout) + } + case ctxTimeoutTypeTrans: + if c.db.GetConfig().TranTimeout > 0 { + return context.WithTimeout(ctx, config.TranTimeout) + } + default: + panic(gerror.NewCodef(gcode.CodeInvalidParameter, "invalid context timeout type: %d", timeoutType)) + } + return ctx, func() {} } // Close closes the database and prevents new queries from starting. @@ -109,97 +108,97 @@ func (c *Core) GetCtxTimeout(ctx context.Context, timeoutType ctxTimeoutType) (c // It is rare to Close a DB, as the DB handle is meant to be // long-lived and shared between many goroutines. func (c *Core) Close(ctx context.Context) (err error) { - if err = c.cache.Close(ctx); err != nil { - return err - } - c.links.LockFunc(func(m map[any]any) { - for k, v := range m { - if db, ok := v.(*sql.DB); ok { - err = db.Close() - if err != nil { - err = gerror.WrapCode(gcode.CodeDbOperationError, err, `db.Close failed`) - } - intlog.Printf(ctx, `close link: %s, err: %v`, k, err) - if err != nil { - return - } - delete(m, k) - } - } - }) - return + if err = c.cache.Close(ctx); err != nil { + return err + } + c.links.LockFunc(func(m map[any]any) { + for k, v := range m { + if db, ok := v.(*sql.DB); ok { + err = db.Close() + if err != nil { + err = gerror.WrapCode(gcode.CodeDbOperationError, err, `db.Close failed`) + } + intlog.Printf(ctx, `close link: %s, err: %v`, k, err) + if err != nil { + return + } + delete(m, k) + } + } + }) + return } // Master creates and returns a connection from master node if master-slave configured. // It returns the default connection if master-slave not configured. func (c *Core) Master(schema ...string) (*sql.DB, error) { - var ( - usedSchema = gutil.GetOrDefaultStr(c.schema, schema...) - charL, charR = c.db.GetChars() - ) - return c.getSqlDb(true, gstr.Trim(usedSchema, charL+charR)) + var ( + usedSchema = gutil.GetOrDefaultStr(c.schema, schema...) + charL, charR = c.db.GetChars() + ) + return c.getSqlDb(true, gstr.Trim(usedSchema, charL+charR)) } // Slave creates and returns a connection from slave node if master-slave configured. // It returns the default connection if master-slave not configured. func (c *Core) Slave(schema ...string) (*sql.DB, error) { - var ( - usedSchema = gutil.GetOrDefaultStr(c.schema, schema...) - charL, charR = c.db.GetChars() - ) - return c.getSqlDb(false, gstr.Trim(usedSchema, charL+charR)) + var ( + usedSchema = gutil.GetOrDefaultStr(c.schema, schema...) + charL, charR = c.db.GetChars() + ) + return c.getSqlDb(false, gstr.Trim(usedSchema, charL+charR)) } // GetAll queries and returns data records from database. func (c *Core) GetAll(ctx context.Context, sql string, args ...interface{}) (Result, error) { - return c.db.DoSelect(ctx, nil, sql, args...) + return c.db.DoSelect(ctx, nil, sql, args...) } // DoSelect queries and returns data records from database. func (c *Core) DoSelect(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) { - return c.db.DoQuery(ctx, link, sql, args...) + return c.db.DoQuery(ctx, link, sql, args...) } // GetOne queries and returns one record from database. func (c *Core) GetOne(ctx context.Context, sql string, args ...interface{}) (Record, error) { - list, err := c.db.GetAll(ctx, sql, args...) - if err != nil { - return nil, err - } - if len(list) > 0 { - return list[0], nil - } - return nil, nil + list, err := c.db.GetAll(ctx, sql, args...) + if err != nil { + return nil, err + } + if len(list) > 0 { + return list[0], nil + } + return nil, nil } // GetArray queries and returns data values as slice from database. // Note that if there are multiple columns in the result, it returns just one column values randomly. func (c *Core) GetArray(ctx context.Context, sql string, args ...interface{}) ([]Value, error) { - all, err := c.db.DoSelect(ctx, nil, sql, args...) - if err != nil { - return nil, err - } - return all.Array(), nil + all, err := c.db.DoSelect(ctx, nil, sql, args...) + if err != nil { + return nil, err + } + return all.Array(), nil } // doGetStruct queries one record from database and converts it to given struct. // The parameter `pointer` should be a pointer to struct. func (c *Core) doGetStruct(ctx context.Context, pointer interface{}, sql string, args ...interface{}) error { - one, err := c.db.GetOne(ctx, sql, args...) - if err != nil { - return err - } - return one.Struct(pointer) + one, err := c.db.GetOne(ctx, sql, args...) + if err != nil { + return err + } + return one.Struct(pointer) } // doGetStructs queries records from database and converts them to given struct. // The parameter `pointer` should be type of struct slice: []struct/[]*struct. func (c *Core) doGetStructs(ctx context.Context, pointer interface{}, sql string, args ...interface{}) error { - all, err := c.db.GetAll(ctx, sql, args...) - if err != nil { - return err - } - return all.Structs(pointer) + all, err := c.db.GetAll(ctx, sql, args...) + if err != nil { + return err + } + return all.Structs(pointer) } // GetScan queries one or more records from database and converts them to given struct or @@ -209,115 +208,115 @@ func (c *Core) doGetStructs(ctx context.Context, pointer interface{}, sql string // the conversion. If parameter `pointer` is type of slice, it calls GetStructs internally // for conversion. func (c *Core) GetScan(ctx context.Context, pointer interface{}, sql string, args ...interface{}) error { - reflectInfo := reflection.OriginTypeAndKind(pointer) - if reflectInfo.InputKind != reflect.Ptr { - return gerror.NewCodef( - gcode.CodeInvalidParameter, - "params should be type of pointer, but got: %v", - reflectInfo.InputKind, - ) - } - switch reflectInfo.OriginKind { - case reflect.Array, reflect.Slice: - return c.db.GetCore().doGetStructs(ctx, pointer, sql, args...) - - case reflect.Struct: - return c.db.GetCore().doGetStruct(ctx, pointer, sql, args...) - } - return gerror.NewCodef( - gcode.CodeInvalidParameter, - `in valid parameter type "%v", of which element type should be type of struct/slice`, - reflectInfo.InputType, - ) + reflectInfo := reflection.OriginTypeAndKind(pointer) + if reflectInfo.InputKind != reflect.Ptr { + return gerror.NewCodef( + gcode.CodeInvalidParameter, + "params should be type of pointer, but got: %v", + reflectInfo.InputKind, + ) + } + switch reflectInfo.OriginKind { + case reflect.Array, reflect.Slice: + return c.db.GetCore().doGetStructs(ctx, pointer, sql, args...) + + case reflect.Struct: + return c.db.GetCore().doGetStruct(ctx, pointer, sql, args...) + } + return gerror.NewCodef( + gcode.CodeInvalidParameter, + `in valid parameter type "%v", of which element type should be type of struct/slice`, + reflectInfo.InputType, + ) } // GetValue queries and returns the field value from database. // The sql should query only one field from database, or else it returns only one // field of the result. func (c *Core) GetValue(ctx context.Context, sql string, args ...interface{}) (Value, error) { - one, err := c.db.GetOne(ctx, sql, args...) - if err != nil { - return gvar.New(nil), err - } - for _, v := range one { - return v, nil - } - return gvar.New(nil), nil + one, err := c.db.GetOne(ctx, sql, args...) + if err != nil { + return nil, err + } + for _, v := range one { + return v, nil + } + return nil, nil } // GetCount queries and returns the count from database. func (c *Core) GetCount(ctx context.Context, sql string, args ...interface{}) (int, error) { - // If the query fields do not contain function "COUNT", - // it replaces the sql string and adds the "COUNT" function to the fields. - if !gregex.IsMatchString(`(?i)SELECT\s+COUNT\(.+\)\s+FROM`, sql) { - sql, _ = gregex.ReplaceString(`(?i)(SELECT)\s+(.+)\s+(FROM)`, `$1 COUNT($2) $3`, sql) - } - value, err := c.db.GetValue(ctx, sql, args...) - if err != nil { - return 0, err - } - return value.Int(), nil + // If the query fields do not contain function "COUNT", + // it replaces the sql string and adds the "COUNT" function to the fields. + if !gregex.IsMatchString(`(?i)SELECT\s+COUNT\(.+\)\s+FROM`, sql) { + sql, _ = gregex.ReplaceString(`(?i)(SELECT)\s+(.+)\s+(FROM)`, `$1 COUNT($2) $3`, sql) + } + value, err := c.db.GetValue(ctx, sql, args...) + if err != nil { + return 0, err + } + return value.Int(), nil } // Union does "(SELECT xxx FROM xxx) UNION (SELECT xxx FROM xxx) ..." statement. func (c *Core) Union(unions ...*Model) *Model { - var ctx = c.db.GetCtx() - return c.doUnion(ctx, unionTypeNormal, unions...) + var ctx = c.db.GetCtx() + return c.doUnion(ctx, unionTypeNormal, unions...) } // UnionAll does "(SELECT xxx FROM xxx) UNION ALL (SELECT xxx FROM xxx) ..." statement. func (c *Core) UnionAll(unions ...*Model) *Model { - var ctx = c.db.GetCtx() - return c.doUnion(ctx, unionTypeAll, unions...) + var ctx = c.db.GetCtx() + return c.doUnion(ctx, unionTypeAll, unions...) } func (c *Core) doUnion(ctx context.Context, unionType int, unions ...*Model) *Model { - var ( - unionTypeStr string - composedSqlStr string - composedArgs = make([]interface{}, 0) - ) - if unionType == unionTypeAll { - unionTypeStr = "UNION ALL" - } else { - unionTypeStr = "UNION" - } - for _, v := range unions { - sqlWithHolder, holderArgs := v.getFormattedSqlAndArgs(ctx, SelectTypeDefault, false) - if composedSqlStr == "" { - composedSqlStr += fmt.Sprintf(`(%s)`, sqlWithHolder) - } else { - composedSqlStr += fmt.Sprintf(` %s (%s)`, unionTypeStr, sqlWithHolder) - } - composedArgs = append(composedArgs, holderArgs...) - } - return c.db.Raw(composedSqlStr, composedArgs...) + var ( + unionTypeStr string + composedSqlStr string + composedArgs = make([]interface{}, 0) + ) + if unionType == unionTypeAll { + unionTypeStr = "UNION ALL" + } else { + unionTypeStr = "UNION" + } + for _, v := range unions { + sqlWithHolder, holderArgs := v.getFormattedSqlAndArgs(ctx, SelectTypeDefault, false) + if composedSqlStr == "" { + composedSqlStr += fmt.Sprintf(`(%s)`, sqlWithHolder) + } else { + composedSqlStr += fmt.Sprintf(` %s (%s)`, unionTypeStr, sqlWithHolder) + } + composedArgs = append(composedArgs, holderArgs...) + } + return c.db.Raw(composedSqlStr, composedArgs...) } // PingMaster pings the master node to check authentication or keeps the connection alive. func (c *Core) PingMaster() error { - var ctx = c.db.GetCtx() - if master, err := c.db.Master(); err != nil { - return err - } else { - if err = master.PingContext(ctx); err != nil { - err = gerror.WrapCode(gcode.CodeDbOperationError, err, `master.Ping failed`) - } - return err - } + var ctx = c.db.GetCtx() + if master, err := c.db.Master(); err != nil { + return err + } else { + if err = master.PingContext(ctx); err != nil { + err = gerror.WrapCode(gcode.CodeDbOperationError, err, `master.Ping failed`) + } + return err + } } // PingSlave pings the slave node to check authentication or keeps the connection alive. func (c *Core) PingSlave() error { - var ctx = c.db.GetCtx() - if slave, err := c.db.Slave(); err != nil { - return err - } else { - if err = slave.PingContext(ctx); err != nil { - err = gerror.WrapCode(gcode.CodeDbOperationError, err, `slave.Ping failed`) - } - return err - } + var ctx = c.db.GetCtx() + if slave, err := c.db.Slave(); err != nil { + return err + } else { + if err = slave.PingContext(ctx); err != nil { + err = gerror.WrapCode(gcode.CodeDbOperationError, err, `slave.Ping failed`) + } + return err + } } // Insert does "INSERT INTO ..." statement for the table. @@ -330,10 +329,10 @@ func (c *Core) PingSlave() error { // // The parameter `batch` specifies the batch operation count when given data is slice. func (c *Core) Insert(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) { - if len(batch) > 0 { - return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Insert() - } - return c.Model(table).Ctx(ctx).Data(data).Insert() + if len(batch) > 0 { + return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Insert() + } + return c.Model(table).Ctx(ctx).Data(data).Insert() } // InsertIgnore does "INSERT IGNORE INTO ..." statement for the table. @@ -346,18 +345,18 @@ func (c *Core) Insert(ctx context.Context, table string, data interface{}, batch // // The parameter `batch` specifies the batch operation count when given data is slice. func (c *Core) InsertIgnore(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) { - if len(batch) > 0 { - return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).InsertIgnore() - } - return c.Model(table).Ctx(ctx).Data(data).InsertIgnore() + if len(batch) > 0 { + return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).InsertIgnore() + } + return c.Model(table).Ctx(ctx).Data(data).InsertIgnore() } // InsertAndGetId performs action Insert and returns the last insert id that automatically generated. func (c *Core) InsertAndGetId(ctx context.Context, table string, data interface{}, batch ...int) (int64, error) { - if len(batch) > 0 { - return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).InsertAndGetId() - } - return c.Model(table).Ctx(ctx).Data(data).InsertAndGetId() + if len(batch) > 0 { + return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).InsertAndGetId() + } + return c.Model(table).Ctx(ctx).Data(data).InsertAndGetId() } // Replace does "REPLACE INTO ..." statement for the table. @@ -373,10 +372,10 @@ func (c *Core) InsertAndGetId(ctx context.Context, table string, data interface{ // If given data is type of slice, it then does batch replacing, and the optional parameter // `batch` specifies the batch operation count. func (c *Core) Replace(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) { - if len(batch) > 0 { - return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Replace() - } - return c.Model(table).Ctx(ctx).Data(data).Replace() + if len(batch) > 0 { + return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Replace() + } + return c.Model(table).Ctx(ctx).Data(data).Replace() } // Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the table. @@ -391,33 +390,33 @@ func (c *Core) Replace(ctx context.Context, table string, data interface{}, batc // If given data is type of slice, it then does batch saving, and the optional parameter // `batch` specifies the batch operation count. func (c *Core) Save(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) { - if len(batch) > 0 { - return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Save() - } - return c.Model(table).Ctx(ctx).Data(data).Save() + if len(batch) > 0 { + return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Save() + } + return c.Model(table).Ctx(ctx).Data(data).Save() } func (c *Core) fieldsToSequence(ctx context.Context, table string, fields []string) ([]string, error) { - var ( - fieldSet = gset.NewStrSetFrom(fields) - fieldsResultInSequence = make([]string, 0) - tableFields, err = c.db.TableFields(ctx, table) - ) - if err != nil { - return nil, err - } - // Sort the fields in order. - var fieldsOfTableInSequence = make([]string, len(tableFields)) - for _, field := range tableFields { - fieldsOfTableInSequence[field.Index] = field.Name - } - // Sort the input fields. - for _, fieldName := range fieldsOfTableInSequence { - if fieldSet.Contains(fieldName) { - fieldsResultInSequence = append(fieldsResultInSequence, fieldName) - } - } - return fieldsResultInSequence, nil + var ( + fieldSet = gset.NewStrSetFrom(fields) + fieldsResultInSequence = make([]string, 0) + tableFields, err = c.db.TableFields(ctx, table) + ) + if err != nil { + return nil, err + } + // Sort the fields in order. + var fieldsOfTableInSequence = make([]string, len(tableFields)) + for _, field := range tableFields { + fieldsOfTableInSequence[field.Index] = field.Name + } + // Sort the input fields. + for _, fieldName := range fieldsOfTableInSequence { + if fieldSet.Contains(fieldName) { + fieldsResultInSequence = append(fieldsResultInSequence, fieldName) + } + } + return fieldsResultInSequence, nil } // DoInsert inserts or updates data for given table. @@ -433,117 +432,117 @@ func (c *Core) fieldsToSequence(ctx context.Context, table string, fields []stri // InsertOptionSave: if there's unique/primary key in the data, it updates it or else inserts a new one; // InsertOptionIgnore: if there's unique/primary key in the data, it ignores the inserting; func (c *Core) DoInsert(ctx context.Context, link Link, table string, list List, option DoInsertOption) (result sql.Result, err error) { - var ( - keys []string // Field names. - values []string // Value holder string array, like: (?,?,?) - params []interface{} // Values that will be committed to underlying database driver. - onDuplicateStr string // onDuplicateStr is used in "ON DUPLICATE KEY UPDATE" statement. - ) - // ============================================================================================ - // Group the list by fields. Different fields to different list. - // It here uses ListMap to keep sequence for data inserting. - // ============================================================================================ - var keyListMap = gmap.NewListMap() - for _, item := range list { - var ( - tmpKeys = make([]string, 0) - tmpKeysInSequenceStr string - ) - for k := range item { - tmpKeys = append(tmpKeys, k) - } - keys, err = c.fieldsToSequence(ctx, table, tmpKeys) - if err != nil { - return nil, err - } - tmpKeysInSequenceStr = gstr.Join(keys, ",") - if !keyListMap.Contains(tmpKeysInSequenceStr) { - keyListMap.Set(tmpKeysInSequenceStr, make(List, 0)) - } - tmpKeysInSequenceList := keyListMap.Get(tmpKeysInSequenceStr).(List) - tmpKeysInSequenceList = append(tmpKeysInSequenceList, item) - keyListMap.Set(tmpKeysInSequenceStr, tmpKeysInSequenceList) - } - if keyListMap.Size() > 1 { - var ( - tmpResult sql.Result - sqlResult SqlResult - rowsAffected int64 - ) - keyListMap.Iterator(func(key, value interface{}) bool { - tmpResult, err = c.DoInsert(ctx, link, table, value.(List), option) - if err != nil { - return false - } - rowsAffected, err = tmpResult.RowsAffected() - if err != nil { - return false - } - sqlResult.Result = tmpResult - sqlResult.Affected += rowsAffected - return true - }) - return &sqlResult, err - } - - // Prepare the batch result pointer. - var ( - charL, charR = c.db.GetChars() - batchResult = new(SqlResult) - keysStr = charL + strings.Join(keys, charR+","+charL) + charR - operation = GetInsertOperationByOption(option.InsertOption) - ) - // Upsert clause only takes effect on Save operation. - if option.InsertOption == InsertOptionSave { - onDuplicateStr, err = c.db.FormatUpsert(keys, list, option) - if err != nil { - return nil, err - } - } - var ( - listLength = len(list) - valueHolders = make([]string, 0) - ) - for i := 0; i < listLength; i++ { - values = values[:0] - // Note that the map type is unordered, - // so it should use slice+key to retrieve the value. - for _, k := range keys { - if s, ok := list[i][k].(Raw); ok { - values = append(values, gconv.String(s)) - } else { - values = append(values, "?") - params = append(params, list[i][k]) - } - } - valueHolders = append(valueHolders, "("+gstr.Join(values, ",")+")") - // Batch package checks: It meets the batch number, or it is the last element. - if len(valueHolders) == option.BatchCount || (i == listLength-1 && len(valueHolders) > 0) { - var ( - stdSqlResult sql.Result - affectedRows int64 - ) - stdSqlResult, err = c.db.DoExec(ctx, link, fmt.Sprintf( - "%s INTO %s(%s) VALUES%s %s", - operation, c.QuotePrefixTableName(table), keysStr, - gstr.Join(valueHolders, ","), - onDuplicateStr, - ), params...) - if err != nil { - return stdSqlResult, err - } - if affectedRows, err = stdSqlResult.RowsAffected(); err != nil { - err = gerror.WrapCode(gcode.CodeDbOperationError, err, `sql.Result.RowsAffected failed`) - return stdSqlResult, err - } else { - batchResult.Result = stdSqlResult - batchResult.Affected += affectedRows - } - params = params[:0] - valueHolders = valueHolders[:0] - } - } - return batchResult, nil + var ( + keys []string // Field names. + values []string // Value holder string array, like: (?,?,?) + params []interface{} // Values that will be committed to underlying database driver. + onDuplicateStr string // onDuplicateStr is used in "ON DUPLICATE KEY UPDATE" statement. + ) + // ============================================================================================ + // Group the list by fields. Different fields to different list. + // It here uses ListMap to keep sequence for data inserting. + // ============================================================================================ + var keyListMap = gmap.NewListMap() + for _, item := range list { + var ( + tmpKeys = make([]string, 0) + tmpKeysInSequenceStr string + ) + for k := range item { + tmpKeys = append(tmpKeys, k) + } + keys, err = c.fieldsToSequence(ctx, table, tmpKeys) + if err != nil { + return nil, err + } + tmpKeysInSequenceStr = gstr.Join(keys, ",") + if !keyListMap.Contains(tmpKeysInSequenceStr) { + keyListMap.Set(tmpKeysInSequenceStr, make(List, 0)) + } + tmpKeysInSequenceList := keyListMap.Get(tmpKeysInSequenceStr).(List) + tmpKeysInSequenceList = append(tmpKeysInSequenceList, item) + keyListMap.Set(tmpKeysInSequenceStr, tmpKeysInSequenceList) + } + if keyListMap.Size() > 1 { + var ( + tmpResult sql.Result + sqlResult SqlResult + rowsAffected int64 + ) + keyListMap.Iterator(func(key, value interface{}) bool { + tmpResult, err = c.DoInsert(ctx, link, table, value.(List), option) + if err != nil { + return false + } + rowsAffected, err = tmpResult.RowsAffected() + if err != nil { + return false + } + sqlResult.Result = tmpResult + sqlResult.Affected += rowsAffected + return true + }) + return &sqlResult, err + } + + // Prepare the batch result pointer. + var ( + charL, charR = c.db.GetChars() + batchResult = new(SqlResult) + keysStr = charL + strings.Join(keys, charR+","+charL) + charR + operation = GetInsertOperationByOption(option.InsertOption) + ) + // Upsert clause only takes effect on Save operation. + if option.InsertOption == InsertOptionSave { + onDuplicateStr, err = c.db.FormatUpsert(keys, list, option) + if err != nil { + return nil, err + } + } + var ( + listLength = len(list) + valueHolders = make([]string, 0) + ) + for i := 0; i < listLength; i++ { + values = values[:0] + // Note that the map type is unordered, + // so it should use slice+key to retrieve the value. + for _, k := range keys { + if s, ok := list[i][k].(Raw); ok { + values = append(values, gconv.String(s)) + } else { + values = append(values, "?") + params = append(params, list[i][k]) + } + } + valueHolders = append(valueHolders, "("+gstr.Join(values, ",")+")") + // Batch package checks: It meets the batch number, or it is the last element. + if len(valueHolders) == option.BatchCount || (i == listLength-1 && len(valueHolders) > 0) { + var ( + stdSqlResult sql.Result + affectedRows int64 + ) + stdSqlResult, err = c.db.DoExec(ctx, link, fmt.Sprintf( + "%s INTO %s(%s) VALUES%s %s", + operation, c.QuotePrefixTableName(table), keysStr, + gstr.Join(valueHolders, ","), + onDuplicateStr, + ), params...) + if err != nil { + return stdSqlResult, err + } + if affectedRows, err = stdSqlResult.RowsAffected(); err != nil { + err = gerror.WrapCode(gcode.CodeDbOperationError, err, `sql.Result.RowsAffected failed`) + return stdSqlResult, err + } else { + batchResult.Result = stdSqlResult + batchResult.Affected += affectedRows + } + params = params[:0] + valueHolders = valueHolders[:0] + } + } + return batchResult, nil } // Update does "UPDATE ... " statement for the table. @@ -561,104 +560,104 @@ func (c *Core) DoInsert(ctx context.Context, link Link, table string, list List, // "age IN(?,?)", 18, 50 // User{ Id : 1, UserName : "john"}. func (c *Core) Update(ctx context.Context, table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) { - return c.Model(table).Ctx(ctx).Data(data).Where(condition, args...).Update() + return c.Model(table).Ctx(ctx).Data(data).Where(condition, args...).Update() } // DoUpdate does "UPDATE ... " statement for the table. // This function is usually used for custom interface definition, you do not need to call it manually. func (c *Core) DoUpdate(ctx context.Context, link Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) { - table = c.QuotePrefixTableName(table) - var ( - rv = reflect.ValueOf(data) - kind = rv.Kind() - ) - if kind == reflect.Ptr { - rv = rv.Elem() - kind = rv.Kind() - } - var ( - params []interface{} - updates string - ) - switch kind { - case reflect.Map, reflect.Struct: - var ( - fields []string - dataMap map[string]interface{} - counterHandler = func(column string, counter Counter) { - if counter.Value != 0 { - column = c.QuoteWord(column) - var ( - columnRef = c.QuoteWord(counter.Field) - columnVal = counter.Value - operator = "+" - ) - if columnVal < 0 { - operator = "-" - columnVal = -columnVal - } - fields = append(fields, fmt.Sprintf("%s=%s%s?", column, columnRef, operator)) - params = append(params, columnVal) - } - } - ) - dataMap, err = c.ConvertDataForRecord(ctx, data, table) - if err != nil { - return nil, err - } - // Sort the data keys in sequence of table fields. - var ( - dataKeys = make([]string, 0) - keysInSequence = make([]string, 0) - ) - for k := range dataMap { - dataKeys = append(dataKeys, k) - } - keysInSequence, err = c.fieldsToSequence(ctx, table, dataKeys) - if err != nil { - return nil, err - } - for _, k := range keysInSequence { - v := dataMap[k] - switch value := v.(type) { - case *Counter: - counterHandler(k, *value) - - case Counter: - counterHandler(k, value) - - default: - if s, ok := v.(Raw); ok { - fields = append(fields, c.QuoteWord(k)+"="+gconv.String(s)) - } else { - fields = append(fields, c.QuoteWord(k)+"=?") - params = append(params, v) - } - } - } - updates = strings.Join(fields, ",") - - default: - updates = gconv.String(data) - } - if len(updates) == 0 { - return nil, gerror.NewCode(gcode.CodeMissingParameter, "data cannot be empty") - } - if len(params) > 0 { - args = append(params, args...) - } - // If no link passed, it then uses the master link. - if link == nil { - if link, err = c.MasterLink(); err != nil { - return nil, err - } - } - return c.db.DoExec(ctx, link, fmt.Sprintf( - "UPDATE %s SET %s%s", - table, updates, condition, - ), - args..., - ) + table = c.QuotePrefixTableName(table) + var ( + rv = reflect.ValueOf(data) + kind = rv.Kind() + ) + if kind == reflect.Ptr { + rv = rv.Elem() + kind = rv.Kind() + } + var ( + params []interface{} + updates string + ) + switch kind { + case reflect.Map, reflect.Struct: + var ( + fields []string + dataMap map[string]interface{} + counterHandler = func(column string, counter Counter) { + if counter.Value != 0 { + column = c.QuoteWord(column) + var ( + columnRef = c.QuoteWord(counter.Field) + columnVal = counter.Value + operator = "+" + ) + if columnVal < 0 { + operator = "-" + columnVal = -columnVal + } + fields = append(fields, fmt.Sprintf("%s=%s%s?", column, columnRef, operator)) + params = append(params, columnVal) + } + } + ) + dataMap, err = c.ConvertDataForRecord(ctx, data, table) + if err != nil { + return nil, err + } + // Sort the data keys in sequence of table fields. + var ( + dataKeys = make([]string, 0) + keysInSequence = make([]string, 0) + ) + for k := range dataMap { + dataKeys = append(dataKeys, k) + } + keysInSequence, err = c.fieldsToSequence(ctx, table, dataKeys) + if err != nil { + return nil, err + } + for _, k := range keysInSequence { + v := dataMap[k] + switch value := v.(type) { + case *Counter: + counterHandler(k, *value) + + case Counter: + counterHandler(k, value) + + default: + if s, ok := v.(Raw); ok { + fields = append(fields, c.QuoteWord(k)+"="+gconv.String(s)) + } else { + fields = append(fields, c.QuoteWord(k)+"=?") + params = append(params, v) + } + } + } + updates = strings.Join(fields, ",") + + default: + updates = gconv.String(data) + } + if len(updates) == 0 { + return nil, gerror.NewCode(gcode.CodeMissingParameter, "data cannot be empty") + } + if len(params) > 0 { + args = append(params, args...) + } + // If no link passed, it then uses the master link. + if link == nil { + if link, err = c.MasterLink(); err != nil { + return nil, err + } + } + return c.db.DoExec(ctx, link, fmt.Sprintf( + "UPDATE %s SET %s%s", + table, updates, condition, + ), + args..., + ) } // Delete does "DELETE FROM ... " statement for the table. @@ -673,28 +672,28 @@ func (c *Core) DoUpdate(ctx context.Context, link Link, table string, data inter // "age IN(?,?)", 18, 50 // User{ Id : 1, UserName : "john"}. func (c *Core) Delete(ctx context.Context, table string, condition interface{}, args ...interface{}) (result sql.Result, err error) { - return c.Model(table).Ctx(ctx).Where(condition, args...).Delete() + return c.Model(table).Ctx(ctx).Where(condition, args...).Delete() } // DoDelete does "DELETE FROM ... " statement for the table. // This function is usually used for custom interface definition, you do not need call it manually. func (c *Core) DoDelete(ctx context.Context, link Link, table string, condition string, args ...interface{}) (result sql.Result, err error) { - if link == nil { - if link, err = c.MasterLink(); err != nil { - return nil, err - } - } - table = c.QuotePrefixTableName(table) - return c.db.DoExec(ctx, link, fmt.Sprintf("DELETE FROM %s%s", table, condition), args...) + if link == nil { + if link, err = c.MasterLink(); err != nil { + return nil, err + } + } + table = c.QuotePrefixTableName(table) + return c.db.DoExec(ctx, link, fmt.Sprintf("DELETE FROM %s%s", table, condition), args...) } // FilteredLink retrieves and returns filtered `linkInfo` that can be using for // logging or tracing purpose. func (c *Core) FilteredLink() string { - return fmt.Sprintf( - `%s@%s(%s:%s)/%s`, - c.config.User, c.config.Protocol, c.config.Host, c.config.Port, c.config.Name, - ) + return fmt.Sprintf( + `%s@%s(%s:%s)/%s`, + c.config.User, c.config.Protocol, c.config.Host, c.config.Port, c.config.Name, + ) } // MarshalJSON implements the interface MarshalJSON for json.Marshal. @@ -703,96 +702,97 @@ func (c *Core) FilteredLink() string { // Note that this interface implements mainly for workaround for a json infinite loop bug // of Golang version < v1.14. func (c *Core) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf(`%+v`, c)), nil + return []byte(fmt.Sprintf(`%+v`, c)), nil } // writeSqlToLogger outputs the Sql object to logger. // It is enabled only if configuration "debug" is true. func (c *Core) writeSqlToLogger(ctx context.Context, sql *Sql) { - var transactionIdStr string - if sql.IsTransaction { - if v := ctx.Value(transactionIdForLoggerCtx); v != nil { - transactionIdStr = fmt.Sprintf(`[txid:%d] `, v.(uint64)) - } - } - s := fmt.Sprintf( - "[%3d ms] [%s] [%s] [rows:%-3d] %s%s", - sql.End-sql.Start, sql.Group, sql.Schema, sql.RowsAffected, transactionIdStr, sql.Format, - ) - if sql.Error != nil { - s += "\nError: " + sql.Error.Error() - c.logger.Error(ctx, s) - } else { - c.logger.Debug(ctx, s) - } + var transactionIdStr string + if sql.IsTransaction { + if v := ctx.Value(transactionIdForLoggerCtx); v != nil { + transactionIdStr = fmt.Sprintf(`[txid:%d] `, v.(uint64)) + } + } + s := fmt.Sprintf( + "[%3d ms] [%s] [%s] [rows:%-3d] %s%s", + sql.End-sql.Start, sql.Group, sql.Schema, sql.RowsAffected, transactionIdStr, sql.Format, + ) + if sql.Error != nil { + s += "\nError: " + sql.Error.Error() + c.logger.Error(ctx, s) + } else { + c.logger.Debug(ctx, s) + } } // HasTable determine whether the table name exists in the database. func (c *Core) HasTable(name string) (bool, error) { - tables, err := c.GetTablesWithCache() - if err != nil { - return false, err - } - charL, charR := c.db.GetChars() - name = gstr.Trim(name, charL+charR) - for _, table := range tables { - if table == name { - return true, nil - } - } - return false, nil -} - + tables, err := c.GetTablesWithCache() + if err != nil { + return false, err + } + charL, charR := c.db.GetChars() + name = gstr.Trim(name, charL+charR) + for _, table := range tables { + if table == name { + return true, nil + } + } + return false, nil +} + +// GetInnerMemCache retrieves and returns the inner memory cache object. func (c *Core) GetInnerMemCache() *gcache.Cache { - return c.innerMemCache + return c.innerMemCache } // GetTablesWithCache retrieves and returns the table names of current database with cache. func (c *Core) GetTablesWithCache() ([]string, error) { - var ( - ctx = c.db.GetCtx() - cacheKey = fmt.Sprintf(`Tables:%s`, c.db.GetGroup()) - cacheDuration = gcache.DurationNoExpire - innerMemCache = c.GetInnerMemCache() - ) - result, err := innerMemCache.GetOrSetFuncLock( - ctx, cacheKey, - func(ctx context.Context) (interface{}, error) { - tableList, err := c.db.Tables(ctx) - if err != nil { - return nil, err - } - return tableList, nil - }, cacheDuration, - ) - if err != nil { - return nil, err - } - return result.Strings(), nil + var ( + ctx = c.db.GetCtx() + cacheKey = fmt.Sprintf(`Tables:%s`, c.db.GetGroup()) + cacheDuration = gcache.DurationNoExpire + innerMemCache = c.GetInnerMemCache() + ) + result, err := innerMemCache.GetOrSetFuncLock( + ctx, cacheKey, + func(ctx context.Context) (interface{}, error) { + tableList, err := c.db.Tables(ctx) + if err != nil { + return nil, err + } + return tableList, nil + }, cacheDuration, + ) + if err != nil { + return nil, err + } + return result.Strings(), nil } // IsSoftCreatedFieldName checks and returns whether given field name is an automatic-filled created time. func (c *Core) IsSoftCreatedFieldName(fieldName string) bool { - if fieldName == "" { - return false - } - if config := c.db.GetConfig(); config.CreatedAt != "" { - if utils.EqualFoldWithoutChars(fieldName, config.CreatedAt) { - return true - } - return gstr.InArray(append([]string{config.CreatedAt}, createdFieldNames...), fieldName) - } - for _, v := range createdFieldNames { - if utils.EqualFoldWithoutChars(fieldName, v) { - return true - } - } - return false + if fieldName == "" { + return false + } + if config := c.db.GetConfig(); config.CreatedAt != "" { + if utils.EqualFoldWithoutChars(fieldName, config.CreatedAt) { + return true + } + return gstr.InArray(append([]string{config.CreatedAt}, createdFieldNames...), fieldName) + } + for _, v := range createdFieldNames { + if utils.EqualFoldWithoutChars(fieldName, v) { + return true + } + } + return false } // FormatSqlBeforeExecuting formats the sql string and its arguments before executing. // The internal handleArguments function might be called twice during the SQL procedure, // but do not worry about it, it's safe and efficient. func (c *Core) FormatSqlBeforeExecuting(sql string, args []interface{}) (newSql string, newArgs []interface{}) { - return handleSliceAndStructArgsForSql(sql, args) + return handleSliceAndStructArgsForSql(sql, args) } diff --git a/database/gdb/gdb_core_structure.go b/database/gdb/gdb_core_structure.go index bbb9df7574c..25f90ebd1e9 100644 --- a/database/gdb/gdb_core_structure.go +++ b/database/gdb/gdb_core_structure.go @@ -7,61 +7,61 @@ package gdb import ( - "context" - "database/sql/driver" - "reflect" - "strings" - "time" - - "github.com/gogf/gf/v2/encoding/gbinary" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/intlog" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/text/gregex" - "github.com/gogf/gf/v2/text/gstr" - "github.com/gogf/gf/v2/util/gconv" - "github.com/gogf/gf/v2/util/gutil" + "context" + "database/sql/driver" + "reflect" + "strings" + "time" + + "github.com/gogf/gf/v2/encoding/gbinary" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/intlog" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/gutil" ) // GetFieldTypeStr retrieves and returns the field type string for certain field by name. func (c *Core) GetFieldTypeStr(ctx context.Context, fieldName, table, schema string) string { - field := c.GetFieldType(ctx, fieldName, table, schema) - if field != nil { - // Kinds of data type examples: - // year(4) - // datetime - // varchar(64) - // bigint(20) - // int(10) unsigned - typeName := gstr.StrTillEx(field.Type, "(") // int(10) unsigned -> int - if typeName != "" { - typeName = gstr.Trim(typeName) - } else { - typeName = field.Type - } - return typeName - } - return "" + field := c.GetFieldType(ctx, fieldName, table, schema) + if field != nil { + // Kinds of data type examples: + // year(4) + // datetime + // varchar(64) + // bigint(20) + // int(10) unsigned + typeName := gstr.StrTillEx(field.Type, "(") // int(10) unsigned -> int + if typeName != "" { + typeName = gstr.Trim(typeName) + } else { + typeName = field.Type + } + return typeName + } + return "" } // GetFieldType retrieves and returns the field type object for certain field by name. func (c *Core) GetFieldType(ctx context.Context, fieldName, table, schema string) *TableField { - fieldsMap, err := c.db.TableFields(ctx, table, schema) - if err != nil { - intlog.Errorf( - ctx, - `TableFields failed for table "%s", schema "%s": %+v`, - table, schema, err, - ) - return nil - } - for tableFieldName, tableField := range fieldsMap { - if tableFieldName == fieldName { - return tableField - } - } - return nil + fieldsMap, err := c.db.TableFields(ctx, table, schema) + if err != nil { + intlog.Errorf( + ctx, + `TableFields failed for table "%s", schema "%s": %+v`, + table, schema, err, + ) + return nil + } + for tableFieldName, tableField := range fieldsMap { + if tableFieldName == fieldName { + return tableField + } + } + return nil } // ConvertDataForRecord is a very important function, which does converting for any data that @@ -70,418 +70,420 @@ func (c *Core) GetFieldType(ctx context.Context, fieldName, table, schema string // 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{}, table string) (map[string]interface{}, error) { - var ( - err error - data = MapOrStructToMapDeep(value, true) - ) - for fieldName, fieldValue := range data { - var fieldType = c.GetFieldTypeStr(ctx, fieldName, table, c.GetSchema()) - data[fieldName], err = c.db.ConvertValueForField( - ctx, - fieldType, - fieldValue, - ) - if err != nil { - return nil, gerror.Wrapf(err, `ConvertDataForRecord failed for value: %#v`, fieldValue) - } - } - return data, nil + var ( + err error + data = MapOrStructToMapDeep(value, true) + ) + for fieldName, fieldValue := range data { + var fieldType = c.GetFieldTypeStr(ctx, fieldName, table, c.GetSchema()) + data[fieldName], err = c.db.ConvertValueForField( + ctx, + fieldType, + fieldValue, + ) + if err != nil { + return nil, gerror.Wrapf(err, `ConvertDataForRecord failed for value: %#v`, fieldValue) + } + } + return data, nil } // ConvertValueForField converts value to the type of the record field. // The parameter `fieldType` is the target record field. // The parameter `fieldValue` is the value that to be committed to record field. func (c *Core) ConvertValueForField(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) { - var ( - err error - convertedValue = fieldValue - ) - switch fieldValue.(type) { - case time.Time, *time.Time, gtime.Time, *gtime.Time: - goto Default - } - // If `value` implements interface `driver.Valuer`, it then uses the interface for value converting. - if valuer, ok := fieldValue.(driver.Valuer); ok { - if convertedValue, err = valuer.Value(); err != nil { - return nil, err - } - return convertedValue, nil - } + var ( + err error + convertedValue = fieldValue + ) + switch fieldValue.(type) { + case time.Time, *time.Time, gtime.Time, *gtime.Time: + goto Default + } + // If `value` implements interface `driver.Valuer`, it then uses the interface for value converting. + if valuer, ok := fieldValue.(driver.Valuer); ok { + if convertedValue, err = valuer.Value(); err != nil { + return nil, err + } + return convertedValue, nil + } Default: - // Default value converting. - var ( - rvValue = reflect.ValueOf(fieldValue) - rvKind = rvValue.Kind() - ) - for rvKind == reflect.Ptr { - rvValue = rvValue.Elem() - rvKind = rvValue.Kind() - } - switch rvKind { - case reflect.Invalid: - convertedValue = nil - - case reflect.Slice, reflect.Array, reflect.Map: - // It should ignore the bytes type. - if _, ok := fieldValue.([]byte); !ok { - // Convert the value to JSON. - convertedValue, err = json.Marshal(fieldValue) - if err != nil { - return nil, err - } - } - case reflect.Struct: - switch r := fieldValue.(type) { - // If the time is zero, it then updates it to nil, - // which will insert/update the value to database as "null". - case time.Time: - if r.IsZero() { - convertedValue = nil - } else { - switch fieldType { - case fieldTypeYear: - convertedValue = r.Format("2006") - case fieldTypeDate: - convertedValue = r.Format("2006-01-02") - case fieldTypeTime: - convertedValue = r.Format("15:04:05") - default: - } - } - - case *time.Time: - if r == nil { - // Nothing to do. - } else { - switch fieldType { - case fieldTypeYear: - convertedValue = r.Format("2006") - case fieldTypeDate: - convertedValue = r.Format("2006-01-02") - case fieldTypeTime: - convertedValue = r.Format("15:04:05") - default: - } - } - - case gtime.Time: - if r.IsZero() { - convertedValue = nil - } else { - switch fieldType { - case fieldTypeYear: - convertedValue = r.Layout("2006") - case fieldTypeDate: - convertedValue = r.Layout("2006-01-02") - case fieldTypeTime: - convertedValue = r.Layout("15:04:05") - default: - convertedValue = r.Time - } - } - - case *gtime.Time: - if r.IsZero() { - convertedValue = nil - } else { - switch fieldType { - case fieldTypeYear: - convertedValue = r.Layout("2006") - case fieldTypeDate: - convertedValue = r.Layout("2006-01-02") - case fieldTypeTime: - convertedValue = r.Layout("15:04:05") - default: - convertedValue = r.Time - } - } - - case Counter, *Counter: - // Nothing to do. - - default: - // If `value` implements interface iNil, - // check its IsNil() function, if got ture, - // which will insert/update the value to database as "null". - if v, ok := fieldValue.(iNil); ok && v.IsNil() { - convertedValue = nil - } else if s, ok := fieldValue.(iString); ok { - // Use string conversion in default. - convertedValue = s.String() - } else { - // Convert the value to JSON. - convertedValue, err = json.Marshal(fieldValue) - if err != nil { - return nil, err - } - } - } - default: - } - - return convertedValue, nil + // Default value converting. + var ( + rvValue = reflect.ValueOf(fieldValue) + rvKind = rvValue.Kind() + ) + for rvKind == reflect.Ptr { + rvValue = rvValue.Elem() + rvKind = rvValue.Kind() + } + switch rvKind { + case reflect.Invalid: + convertedValue = nil + + case reflect.Slice, reflect.Array, reflect.Map: + // It should ignore the bytes type. + if _, ok := fieldValue.([]byte); !ok { + // Convert the value to JSON. + convertedValue, err = json.Marshal(fieldValue) + if err != nil { + return nil, err + } + } + case reflect.Struct: + switch r := fieldValue.(type) { + // If the time is zero, it then updates it to nil, + // which will insert/update the value to database as "null". + case time.Time: + if r.IsZero() { + convertedValue = nil + } else { + switch fieldType { + case fieldTypeYear: + convertedValue = r.Format("2006") + case fieldTypeDate: + convertedValue = r.Format("2006-01-02") + case fieldTypeTime: + convertedValue = r.Format("15:04:05") + default: + } + } + + case *time.Time: + if r == nil { + // Nothing to do. + } else { + switch fieldType { + case fieldTypeYear: + convertedValue = r.Format("2006") + case fieldTypeDate: + convertedValue = r.Format("2006-01-02") + case fieldTypeTime: + convertedValue = r.Format("15:04:05") + default: + } + } + + case gtime.Time: + if r.IsZero() { + convertedValue = nil + } else { + switch fieldType { + case fieldTypeYear: + convertedValue = r.Layout("2006") + case fieldTypeDate: + convertedValue = r.Layout("2006-01-02") + case fieldTypeTime: + convertedValue = r.Layout("15:04:05") + default: + convertedValue = r.Time + } + } + + case *gtime.Time: + if r.IsZero() { + convertedValue = nil + } else { + switch fieldType { + case fieldTypeYear: + convertedValue = r.Layout("2006") + case fieldTypeDate: + convertedValue = r.Layout("2006-01-02") + case fieldTypeTime: + convertedValue = r.Layout("15:04:05") + default: + convertedValue = r.Time + } + } + + case Counter, *Counter: + // Nothing to do. + + default: + // If `value` implements interface iNil, + // check its IsNil() function, if got ture, + // which will insert/update the value to database as "null". + if v, ok := fieldValue.(iNil); ok && v.IsNil() { + convertedValue = nil + } else if s, ok := fieldValue.(iString); ok { + // Use string conversion in default. + convertedValue = s.String() + } else { + // Convert the value to JSON. + convertedValue, err = json.Marshal(fieldValue) + if err != nil { + return nil, err + } + } + } + default: + } + + return convertedValue, nil } // CheckLocalTypeForField checks and returns corresponding type for given db type. -func (c *Core) CheckLocalTypeForField(ctx context.Context, fieldType string, fieldValue interface{}) (LocalType, error) { - var ( - typeName string - typePattern string - ) - match, _ := gregex.MatchString(`(.+?)\((.+)\)`, fieldType) - if len(match) == 3 { - typeName = gstr.Trim(match[1]) - typePattern = gstr.Trim(match[2]) - } else { - typeName = gstr.Split(fieldType, " ")[0] - } - - typeName = strings.ToLower(typeName) - - switch typeName { - case - fieldTypeBinary, - fieldTypeVarbinary, - fieldTypeBlob, - fieldTypeTinyblob, - fieldTypeMediumblob, - fieldTypeLongblob: - return LocalTypeBytes, nil - - case - fieldTypeInt, - fieldTypeTinyint, - fieldTypeSmallInt, - fieldTypeSmallint, - fieldTypeMediumInt, - fieldTypeMediumint, - fieldTypeSerial: - if gstr.ContainsI(fieldType, "unsigned") { - return LocalTypeUint, nil - } - return LocalTypeInt, nil - - case - fieldTypeBigInt, - fieldTypeBigint, - fieldTypeBigserial: - if gstr.ContainsI(fieldType, "unsigned") { - return LocalTypeUint64, nil - } - return LocalTypeInt64, nil - - case - fieldTypeReal: - return LocalTypeFloat32, nil - - case - fieldTypeDecimal, - fieldTypeMoney, - fieldTypeNumeric, - fieldTypeSmallmoney: - return LocalTypeString, nil - case - fieldTypeFloat, - fieldTypeDouble: - return LocalTypeFloat64, nil - - case - fieldTypeBit: - // It is suggested using bit(1) as boolean. - if typePattern == "1" { - return LocalTypeBool, nil - } - s := gconv.String(fieldValue) - // mssql is true|false string. - if strings.EqualFold(s, "true") || strings.EqualFold(s, "false") { - return LocalTypeBool, nil - } - if gstr.ContainsI(fieldType, "unsigned") { - return LocalTypeUint64Bytes, nil - } - return LocalTypeInt64Bytes, nil - - case - fieldTypeBool: - return LocalTypeBool, nil - - case - fieldTypeDate: - return LocalTypeDate, nil - - case - fieldTypeTime: - return LocalTypeTime, nil - - case - fieldTypeDatetime, - fieldTypeTimestamp, - fieldTypeTimestampz: - return LocalTypeDatetime, nil - - case - fieldTypeJson: - return LocalTypeJson, nil - - case - fieldTypeJsonb: - return LocalTypeJsonb, nil - - default: - // Auto-detect field type, using key match. - switch { - case strings.Contains(typeName, "text") || strings.Contains(typeName, "char") || strings.Contains(typeName, "character"): - return LocalTypeString, nil - - case strings.Contains(typeName, "float") || strings.Contains(typeName, "double") || strings.Contains(typeName, "numeric"): - return LocalTypeFloat64, nil - - case strings.Contains(typeName, "bool"): - return LocalTypeBool, nil - - case strings.Contains(typeName, "binary") || strings.Contains(typeName, "blob"): - return LocalTypeBytes, nil - - case strings.Contains(typeName, "int"): - if gstr.ContainsI(fieldType, "unsigned") { - return LocalTypeUint, nil - } - return LocalTypeInt, nil - - case strings.Contains(typeName, "time"): - return LocalTypeDatetime, nil - - case strings.Contains(typeName, "date"): - return LocalTypeDatetime, nil - - default: - return LocalTypeString, nil - } - } +// The `fieldType` is retrieved from ColumnTypes of db driver, example: +// UNSIGNED INT +func (c *Core) CheckLocalTypeForField(ctx context.Context, fieldType string, _ interface{}) (LocalType, error) { + var ( + typeName string + typePattern string + ) + match, _ := gregex.MatchString(`(.+?)\((.+)\)`, fieldType) + if len(match) == 3 { + typeName = gstr.Trim(match[1]) + typePattern = gstr.Trim(match[2]) + } else { + var array = gstr.SplitAndTrim(fieldType, " ") + if gstr.Equal(array[0], "unsigned") { + typeName = array[1] + } else { + typeName = array[0] + } + } + + typeName = strings.ToLower(typeName) + + switch typeName { + case + fieldTypeBinary, + fieldTypeVarbinary, + fieldTypeBlob, + fieldTypeTinyblob, + fieldTypeMediumblob, + fieldTypeLongblob: + return LocalTypeBytes, nil + + case + fieldTypeInt, + fieldTypeTinyint, + fieldTypeSmallInt, + fieldTypeSmallint, + fieldTypeMediumInt, + fieldTypeMediumint, + fieldTypeSerial: + if gstr.ContainsI(fieldType, "unsigned") { + return LocalTypeUint, nil + } + return LocalTypeInt, nil + + case + fieldTypeBigInt, + fieldTypeBigint, + fieldTypeBigserial: + if gstr.ContainsI(fieldType, "unsigned") { + return LocalTypeUint64, nil + } + return LocalTypeInt64, nil + + case + fieldTypeReal: + return LocalTypeFloat32, nil + + case + fieldTypeDecimal, + fieldTypeMoney, + fieldTypeNumeric, + fieldTypeSmallmoney: + return LocalTypeString, nil + case + fieldTypeFloat, + fieldTypeDouble: + return LocalTypeFloat64, nil + + case + fieldTypeBit: + // It is suggested using bit(1) as boolean. + if typePattern == "1" { + return LocalTypeBool, nil + } + if gstr.ContainsI(fieldType, "unsigned") { + return LocalTypeUint64Bytes, nil + } + return LocalTypeInt64Bytes, nil + + case + fieldTypeBool: + return LocalTypeBool, nil + + case + fieldTypeDate: + return LocalTypeDate, nil + + case + fieldTypeTime: + return LocalTypeTime, nil + + case + fieldTypeDatetime, + fieldTypeTimestamp, + fieldTypeTimestampz: + return LocalTypeDatetime, nil + + case + fieldTypeJson: + return LocalTypeJson, nil + + case + fieldTypeJsonb: + return LocalTypeJsonb, nil + + default: + // Auto-detect field type, using key match. + switch { + case strings.Contains(typeName, "text") || strings.Contains(typeName, "char") || strings.Contains(typeName, "character"): + return LocalTypeString, nil + + case strings.Contains(typeName, "float") || strings.Contains(typeName, "double") || strings.Contains(typeName, "numeric"): + return LocalTypeFloat64, nil + + case strings.Contains(typeName, "bool"): + return LocalTypeBool, nil + + case strings.Contains(typeName, "binary") || strings.Contains(typeName, "blob"): + return LocalTypeBytes, nil + + case strings.Contains(typeName, "int"): + if gstr.ContainsI(fieldType, "unsigned") { + return LocalTypeUint, nil + } + return LocalTypeInt, nil + + case strings.Contains(typeName, "time"): + return LocalTypeDatetime, nil + + case strings.Contains(typeName, "date"): + return LocalTypeDatetime, nil + + default: + return LocalTypeString, nil + } + } } // ConvertValueForLocal converts value to local Golang type of value according field type name from database. // The parameter `fieldType` is in lower case, like: // `float(5,2)`, `unsigned double(5,2)`, `decimal(10,2)`, `char(45)`, `varchar(100)`, etc. func (c *Core) ConvertValueForLocal( - ctx context.Context, fieldType string, fieldValue interface{}, + ctx context.Context, fieldType string, fieldValue interface{}, ) (interface{}, error) { - // If there's no type retrieved, it returns the `fieldValue` directly - // to use its original data type, as `fieldValue` is type of interface{}. - if fieldType == "" { - return fieldValue, nil - } - typeName, err := c.db.CheckLocalTypeForField(ctx, fieldType, fieldValue) - if err != nil { - return nil, err - } - switch typeName { - case LocalTypeBytes: - var typeNameStr = string(typeName) - if strings.Contains(typeNameStr, "binary") || strings.Contains(typeNameStr, "blob") { - return fieldValue, nil - } - return gconv.Bytes(fieldValue), nil - - case LocalTypeInt: - return gconv.Int(gconv.String(fieldValue)), nil - - case LocalTypeUint: - return gconv.Uint(gconv.String(fieldValue)), nil - - case LocalTypeInt64: - return gconv.Int64(gconv.String(fieldValue)), nil - - case LocalTypeUint64: - return gconv.Uint64(gconv.String(fieldValue)), nil - - case LocalTypeInt64Bytes: - return gbinary.BeDecodeToInt64(gconv.Bytes(fieldValue)), nil - - case LocalTypeUint64Bytes: - return gbinary.BeDecodeToUint64(gconv.Bytes(fieldValue)), nil - - case LocalTypeFloat32: - return gconv.Float32(gconv.String(fieldValue)), nil - - case LocalTypeFloat64: - return gconv.Float64(gconv.String(fieldValue)), nil - - case LocalTypeBool: - s := gconv.String(fieldValue) - // mssql is true|false string. - if strings.EqualFold(s, "true") { - return 1, nil - } - if strings.EqualFold(s, "false") { - return 0, nil - } - return gconv.Bool(fieldValue), nil - - case LocalTypeDate: - if t, ok := fieldValue.(time.Time); ok { - return gtime.NewFromTime(t).Format("Y-m-d"), nil - } - t, _ := gtime.StrToTime(gconv.String(fieldValue)) - return t.Format("Y-m-d"), nil - - case LocalTypeTime: - if t, ok := fieldValue.(time.Time); ok { - return gtime.NewFromTime(t).Format("H:i:s"), nil - } - t, _ := gtime.StrToTime(gconv.String(fieldValue)) - return t.Format("H:i:s"), nil - - case LocalTypeDatetime: - if t, ok := fieldValue.(time.Time); ok { - return gtime.NewFromTime(t), nil - } - t, _ := gtime.StrToTime(gconv.String(fieldValue)) - return t, nil - - default: - return gconv.String(fieldValue), nil - } + // If there's no type retrieved, it returns the `fieldValue` directly + // to use its original data type, as `fieldValue` is type of interface{}. + if fieldType == "" { + return fieldValue, nil + } + typeName, err := c.db.CheckLocalTypeForField(ctx, fieldType, fieldValue) + if err != nil { + return nil, err + } + switch typeName { + case LocalTypeBytes: + var typeNameStr = string(typeName) + if strings.Contains(typeNameStr, "binary") || strings.Contains(typeNameStr, "blob") { + return fieldValue, nil + } + return gconv.Bytes(fieldValue), nil + + case LocalTypeInt: + return gconv.Int(gconv.String(fieldValue)), nil + + case LocalTypeUint: + return gconv.Uint(gconv.String(fieldValue)), nil + + case LocalTypeInt64: + return gconv.Int64(gconv.String(fieldValue)), nil + + case LocalTypeUint64: + return gconv.Uint64(gconv.String(fieldValue)), nil + + case LocalTypeInt64Bytes: + return gbinary.BeDecodeToInt64(gconv.Bytes(fieldValue)), nil + + case LocalTypeUint64Bytes: + return gbinary.BeDecodeToUint64(gconv.Bytes(fieldValue)), nil + + case LocalTypeFloat32: + return gconv.Float32(gconv.String(fieldValue)), nil + + case LocalTypeFloat64: + return gconv.Float64(gconv.String(fieldValue)), nil + + case LocalTypeBool: + s := gconv.String(fieldValue) + // mssql is true|false string. + if strings.EqualFold(s, "true") { + return 1, nil + } + if strings.EqualFold(s, "false") { + return 0, nil + } + return gconv.Bool(fieldValue), nil + + case LocalTypeDate: + if t, ok := fieldValue.(time.Time); ok { + return gtime.NewFromTime(t).Format("Y-m-d"), nil + } + t, _ := gtime.StrToTime(gconv.String(fieldValue)) + return t.Format("Y-m-d"), nil + + case LocalTypeTime: + if t, ok := fieldValue.(time.Time); ok { + return gtime.NewFromTime(t).Format("H:i:s"), nil + } + t, _ := gtime.StrToTime(gconv.String(fieldValue)) + return t.Format("H:i:s"), nil + + case LocalTypeDatetime: + if t, ok := fieldValue.(time.Time); ok { + return gtime.NewFromTime(t), nil + } + t, _ := gtime.StrToTime(gconv.String(fieldValue)) + return t, nil + + default: + return gconv.String(fieldValue), nil + } } // mappingAndFilterData automatically mappings the map key to table field and removes // all key-value pairs that are not the field of given table. func (c *Core) mappingAndFilterData(ctx context.Context, schema, table string, data map[string]interface{}, filter bool) (map[string]interface{}, error) { - fieldsMap, err := c.db.TableFields(ctx, c.guessPrimaryTableName(table), schema) - if err != nil { - return nil, err - } - if len(fieldsMap) == 0 { - return nil, gerror.Newf(`The table %s may not exist, or the table contains no fields`, table) - } - fieldsKeyMap := make(map[string]interface{}, len(fieldsMap)) - for k := range fieldsMap { - fieldsKeyMap[k] = nil - } - // Automatic data key to table field name mapping. - var foundKey string - for dataKey, dataValue := range data { - if _, ok := fieldsKeyMap[dataKey]; !ok { - foundKey, _ = gutil.MapPossibleItemByKey(fieldsKeyMap, dataKey) - if foundKey != "" { - if _, ok = data[foundKey]; !ok { - data[foundKey] = dataValue - } - delete(data, dataKey) - } - } - } - // Data filtering. - // It deletes all key-value pairs that has incorrect field name. - if filter { - for dataKey := range data { - if _, ok := fieldsMap[dataKey]; !ok { - delete(data, dataKey) - } - } - if len(data) == 0 { - return nil, gerror.Newf(`input data match no fields in table %s`, table) - } - } - return data, nil + fieldsMap, err := c.db.TableFields(ctx, c.guessPrimaryTableName(table), schema) + if err != nil { + return nil, err + } + if len(fieldsMap) == 0 { + return nil, gerror.Newf(`The table %s may not exist, or the table contains no fields`, table) + } + fieldsKeyMap := make(map[string]interface{}, len(fieldsMap)) + for k := range fieldsMap { + fieldsKeyMap[k] = nil + } + // Automatic data key to table field name mapping. + var foundKey string + for dataKey, dataValue := range data { + if _, ok := fieldsKeyMap[dataKey]; !ok { + foundKey, _ = gutil.MapPossibleItemByKey(fieldsKeyMap, dataKey) + if foundKey != "" { + if _, ok = data[foundKey]; !ok { + data[foundKey] = dataValue + } + delete(data, dataKey) + } + } + } + // Data filtering. + // It deletes all key-value pairs that has incorrect field name. + if filter { + for dataKey := range data { + if _, ok := fieldsMap[dataKey]; !ok { + delete(data, dataKey) + } + } + if len(data) == 0 { + return nil, gerror.Newf(`input data match no fields in table %s`, table) + } + } + return data, nil } diff --git a/database/gdb/gdb_core_underlying.go b/database/gdb/gdb_core_underlying.go index 045d11c65af..bc380a335df 100644 --- a/database/gdb/gdb_core_underlying.go +++ b/database/gdb/gdb_core_underlying.go @@ -8,299 +8,298 @@ package gdb import ( - "context" - "database/sql" - "fmt" - "reflect" - - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/trace" - - "github.com/gogf/gf/v2" - "github.com/gogf/gf/v2/container/gvar" - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/intlog" - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/util/gconv" - "github.com/gogf/gf/v2/util/guid" + "context" + "database/sql" + "fmt" + "reflect" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" + + "github.com/gogf/gf/v2" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/intlog" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/guid" ) // Query commits one query SQL to underlying driver and returns the execution result. // It is most commonly used for data querying. func (c *Core) Query(ctx context.Context, sql string, args ...interface{}) (result Result, err error) { - return c.db.DoQuery(ctx, nil, sql, args...) + return c.db.DoQuery(ctx, nil, sql, args...) } // DoQuery commits the sql string and its arguments to underlying driver // through given link object and returns the execution result. func (c *Core) DoQuery(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) { - // Transaction checks. - if link == nil { - if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { - // Firstly, check and retrieve transaction link from context. - link = &txLink{tx.GetSqlTX()} - } else if link, err = c.SlaveLink(); err != nil { - // Or else it creates one from master node. - return nil, err - } - } else if !link.IsTransaction() { - // If current link is not transaction link, it checks and retrieves transaction from context. - if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { - link = &txLink{tx.GetSqlTX()} - } - } - - // Sql filtering. - sql, args = c.FormatSqlBeforeExecuting(sql, args) - sql, args, err = c.db.DoFilter(ctx, link, sql, args) - if err != nil { - return nil, err - } - // SQL format and retrieve. - if v := ctx.Value(ctxKeyCatchSQL); v != nil { - var ( - manager = v.(*CatchSQLManager) - formattedSql = FormatSqlWithArgs(sql, args) - ) - manager.SQLArray.Append(formattedSql) - if !manager.DoCommit && ctx.Value(ctxKeyInternalProducedSQL) == nil { - return nil, nil - } - } - // Link execution. - var out DoCommitOutput - out, err = c.db.DoCommit(ctx, DoCommitInput{ - Link: link, - Sql: sql, - Args: args, - Stmt: nil, - Type: SqlTypeQueryContext, - IsTransaction: link.IsTransaction(), - }) - if err != nil { - return nil, err - } - return out.Records, err + // Transaction checks. + if link == nil { + if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { + // Firstly, check and retrieve transaction link from context. + link = &txLink{tx.GetSqlTX()} + } else if link, err = c.SlaveLink(); err != nil { + // Or else it creates one from master node. + return nil, err + } + } else if !link.IsTransaction() { + // If current link is not transaction link, it checks and retrieves transaction from context. + if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { + link = &txLink{tx.GetSqlTX()} + } + } + + // Sql filtering. + sql, args = c.FormatSqlBeforeExecuting(sql, args) + sql, args, err = c.db.DoFilter(ctx, link, sql, args) + if err != nil { + return nil, err + } + // SQL format and retrieve. + if v := ctx.Value(ctxKeyCatchSQL); v != nil { + var ( + manager = v.(*CatchSQLManager) + formattedSql = FormatSqlWithArgs(sql, args) + ) + manager.SQLArray.Append(formattedSql) + if !manager.DoCommit && ctx.Value(ctxKeyInternalProducedSQL) == nil { + return nil, nil + } + } + // Link execution. + var out DoCommitOutput + out, err = c.db.DoCommit(ctx, DoCommitInput{ + Link: link, + Sql: sql, + Args: args, + Stmt: nil, + Type: SqlTypeQueryContext, + IsTransaction: link.IsTransaction(), + }) + if err != nil { + return nil, err + } + return out.Records, err } // Exec commits one query SQL to underlying driver and returns the execution result. // It is most commonly used for data inserting and updating. func (c *Core) Exec(ctx context.Context, sql string, args ...interface{}) (result sql.Result, err error) { - return c.db.DoExec(ctx, nil, sql, args...) + return c.db.DoExec(ctx, nil, sql, args...) } // DoExec commits the sql string and its arguments to underlying driver // through given link object and returns the execution result. func (c *Core) DoExec(ctx context.Context, link Link, sql string, args ...interface{}) (result sql.Result, err error) { - // Transaction checks. - if link == nil { - if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { - // Firstly, check and retrieve transaction link from context. - link = &txLink{tx.GetSqlTX()} - } else if link, err = c.MasterLink(); err != nil { - // Or else it creates one from master node. - return nil, err - } - } else if !link.IsTransaction() { - // If current link is not transaction link, it checks and retrieves transaction from context. - if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { - link = &txLink{tx.GetSqlTX()} - } - } - - // SQL filtering. - sql, args = c.FormatSqlBeforeExecuting(sql, args) - sql, args, err = c.db.DoFilter(ctx, link, sql, args) - if err != nil { - return nil, err - } - // SQL format and retrieve. - if v := ctx.Value(ctxKeyCatchSQL); v != nil { - var ( - manager = v.(*CatchSQLManager) - formattedSql = FormatSqlWithArgs(sql, args) - ) - manager.SQLArray.Append(formattedSql) - if !manager.DoCommit && ctx.Value(ctxKeyInternalProducedSQL) == nil { - return new(SqlResult), nil - } - } - // Link execution. - var out DoCommitOutput - out, err = c.db.DoCommit(ctx, DoCommitInput{ - Link: link, - Sql: sql, - Args: args, - Stmt: nil, - Type: SqlTypeExecContext, - IsTransaction: link.IsTransaction(), - }) - if err != nil { - return nil, err - } - return out.Result, err + // Transaction checks. + if link == nil { + if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { + // Firstly, check and retrieve transaction link from context. + link = &txLink{tx.GetSqlTX()} + } else if link, err = c.MasterLink(); err != nil { + // Or else it creates one from master node. + return nil, err + } + } else if !link.IsTransaction() { + // If current link is not transaction link, it checks and retrieves transaction from context. + if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { + link = &txLink{tx.GetSqlTX()} + } + } + + // SQL filtering. + sql, args = c.FormatSqlBeforeExecuting(sql, args) + sql, args, err = c.db.DoFilter(ctx, link, sql, args) + if err != nil { + return nil, err + } + // SQL format and retrieve. + if v := ctx.Value(ctxKeyCatchSQL); v != nil { + var ( + manager = v.(*CatchSQLManager) + formattedSql = FormatSqlWithArgs(sql, args) + ) + manager.SQLArray.Append(formattedSql) + if !manager.DoCommit && ctx.Value(ctxKeyInternalProducedSQL) == nil { + return new(SqlResult), nil + } + } + // Link execution. + var out DoCommitOutput + out, err = c.db.DoCommit(ctx, DoCommitInput{ + Link: link, + Sql: sql, + Args: args, + Stmt: nil, + Type: SqlTypeExecContext, + IsTransaction: link.IsTransaction(), + }) + if err != nil { + return nil, err + } + return out.Result, err } // DoFilter is a hook function, which filters the sql and its arguments before it's committed to underlying driver. // The parameter `link` specifies the current database connection operation object. You can modify the sql // string `sql` and its arguments `args` as you wish before they're committed to driver. func (c *Core) DoFilter( - ctx context.Context, link Link, sql string, args []interface{}, + ctx context.Context, link Link, sql string, args []interface{}, ) (newSql string, newArgs []interface{}, err error) { - return sql, args, nil + return sql, args, nil } // DoCommit commits current sql and arguments to underlying sql driver. func (c *Core) DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutput, err error) { - var ( - sqlTx *sql.Tx - sqlStmt *sql.Stmt - sqlRows *sql.Rows - sqlResult sql.Result - stmtSqlRows *sql.Rows - stmtSqlRow *sql.Row - rowsAffected int64 - cancelFuncForTimeout context.CancelFunc - formattedSql = FormatSqlWithArgs(in.Sql, in.Args) - timestampMilli1 = gtime.TimestampMilli() - ) - - // Trace span start. - tr := otel.GetTracerProvider().Tracer(traceInstrumentName, trace.WithInstrumentationVersion(gf.VERSION)) - ctx, span := tr.Start(ctx, string(in.Type), trace.WithSpanKind(trace.SpanKindInternal)) - defer span.End() - - // Execution by type. - switch in.Type { - case SqlTypeBegin: - ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeTrans) - formattedSql = fmt.Sprintf( - `%s (IosolationLevel: %s, ReadOnly: %t)`, - formattedSql, in.TxOptions.Isolation.String(), in.TxOptions.ReadOnly, - ) - if sqlTx, err = in.Db.BeginTx(ctx, &in.TxOptions); err == nil { - out.Tx = &TXCore{ - db: c.db, - tx: sqlTx, - ctx: context.WithValue(ctx, transactionIdForLoggerCtx, transactionIdGenerator.Add(1)), - master: in.Db, - transactionId: guid.S(), - cancelFunc: cancelFuncForTimeout, - } - ctx = out.Tx.GetCtx() - } - out.RawResult = sqlTx - - case SqlTypeTXCommit: - if in.TxCancelFunc != nil { - defer in.TxCancelFunc() - } - err = in.Tx.Commit() - - case SqlTypeTXRollback: - if in.TxCancelFunc != nil { - defer in.TxCancelFunc() - } - err = in.Tx.Rollback() - - case SqlTypeExecContext: - ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeExec) - defer cancelFuncForTimeout() - if c.db.GetDryRun() { - sqlResult = new(SqlResult) - } else { - sqlResult, err = in.Link.ExecContext(ctx, in.Sql, in.Args...) - } - out.RawResult = sqlResult - - case SqlTypeQueryContext: - ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery) - defer cancelFuncForTimeout() - sqlRows, err = in.Link.QueryContext(ctx, in.Sql, in.Args...) - out.RawResult = sqlRows - - case SqlTypePrepareContext: - ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypePrepare) - defer cancelFuncForTimeout() - sqlStmt, err = in.Link.PrepareContext(ctx, in.Sql) - out.RawResult = sqlStmt - - case SqlTypeStmtExecContext: - ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeExec) - defer cancelFuncForTimeout() - if c.db.GetDryRun() { - sqlResult = new(SqlResult) - } else { - sqlResult, err = in.Stmt.ExecContext(ctx, in.Args...) - } - out.RawResult = sqlResult - - case SqlTypeStmtQueryContext: - ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery) - defer cancelFuncForTimeout() - stmtSqlRows, err = in.Stmt.QueryContext(ctx, in.Args...) - out.RawResult = stmtSqlRows - - case SqlTypeStmtQueryRowContext: - ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery) - defer cancelFuncForTimeout() - stmtSqlRow = in.Stmt.QueryRowContext(ctx, in.Args...) - out.RawResult = stmtSqlRow - - default: - panic(gerror.NewCodef(gcode.CodeInvalidParameter, `invalid SqlType "%s"`, in.Type)) - } - // Result handling. - switch { - case sqlResult != nil && !c.GetIgnoreResultFromCtx(ctx): - rowsAffected, err = sqlResult.RowsAffected() - out.Result = sqlResult - - case sqlRows != nil: - out.Records, err = c.RowsToResult(ctx, sqlRows) - rowsAffected = int64(len(out.Records)) - - case sqlStmt != nil: - out.Stmt = &Stmt{ - Stmt: sqlStmt, - core: c, - link: in.Link, - sql: in.Sql, - } - } - var ( - timestampMilli2 = gtime.TimestampMilli() - sqlObj = &Sql{ - Sql: in.Sql, - Type: in.Type, - Args: in.Args, - Format: formattedSql, - Error: err, - Start: timestampMilli1, - End: timestampMilli2, - Group: c.db.GetGroup(), - Schema: c.db.GetSchema(), - RowsAffected: rowsAffected, - IsTransaction: in.IsTransaction, - } - ) - - // Tracing. - c.traceSpanEnd(ctx, span, sqlObj) - - // Logging. - if c.db.GetDebug() { - c.writeSqlToLogger(ctx, sqlObj) - } - if err != nil && err != sql.ErrNoRows { - err = gerror.WrapCode( - gcode.CodeDbOperationError, - err, - FormatSqlWithArgs(in.Sql, in.Args), - ) - } - return out, err + var ( + sqlTx *sql.Tx + sqlStmt *sql.Stmt + sqlRows *sql.Rows + sqlResult sql.Result + stmtSqlRows *sql.Rows + stmtSqlRow *sql.Row + rowsAffected int64 + cancelFuncForTimeout context.CancelFunc + formattedSql = FormatSqlWithArgs(in.Sql, in.Args) + timestampMilli1 = gtime.TimestampMilli() + ) + + // Trace span start. + tr := otel.GetTracerProvider().Tracer(traceInstrumentName, trace.WithInstrumentationVersion(gf.VERSION)) + ctx, span := tr.Start(ctx, string(in.Type), trace.WithSpanKind(trace.SpanKindInternal)) + defer span.End() + + // Execution by type. + switch in.Type { + case SqlTypeBegin: + ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeTrans) + formattedSql = fmt.Sprintf( + `%s (IosolationLevel: %s, ReadOnly: %t)`, + formattedSql, in.TxOptions.Isolation.String(), in.TxOptions.ReadOnly, + ) + if sqlTx, err = in.Db.BeginTx(ctx, &in.TxOptions); err == nil { + out.Tx = &TXCore{ + db: c.db, + tx: sqlTx, + ctx: context.WithValue(ctx, transactionIdForLoggerCtx, transactionIdGenerator.Add(1)), + master: in.Db, + transactionId: guid.S(), + cancelFunc: cancelFuncForTimeout, + } + ctx = out.Tx.GetCtx() + } + out.RawResult = sqlTx + + case SqlTypeTXCommit: + if in.TxCancelFunc != nil { + defer in.TxCancelFunc() + } + err = in.Tx.Commit() + + case SqlTypeTXRollback: + if in.TxCancelFunc != nil { + defer in.TxCancelFunc() + } + err = in.Tx.Rollback() + + case SqlTypeExecContext: + ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeExec) + defer cancelFuncForTimeout() + if c.db.GetDryRun() { + sqlResult = new(SqlResult) + } else { + sqlResult, err = in.Link.ExecContext(ctx, in.Sql, in.Args...) + } + out.RawResult = sqlResult + + case SqlTypeQueryContext: + ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery) + defer cancelFuncForTimeout() + sqlRows, err = in.Link.QueryContext(ctx, in.Sql, in.Args...) + out.RawResult = sqlRows + + case SqlTypePrepareContext: + ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypePrepare) + defer cancelFuncForTimeout() + sqlStmt, err = in.Link.PrepareContext(ctx, in.Sql) + out.RawResult = sqlStmt + + case SqlTypeStmtExecContext: + ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeExec) + defer cancelFuncForTimeout() + if c.db.GetDryRun() { + sqlResult = new(SqlResult) + } else { + sqlResult, err = in.Stmt.ExecContext(ctx, in.Args...) + } + out.RawResult = sqlResult + + case SqlTypeStmtQueryContext: + ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery) + defer cancelFuncForTimeout() + stmtSqlRows, err = in.Stmt.QueryContext(ctx, in.Args...) + out.RawResult = stmtSqlRows + + case SqlTypeStmtQueryRowContext: + ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery) + defer cancelFuncForTimeout() + stmtSqlRow = in.Stmt.QueryRowContext(ctx, in.Args...) + out.RawResult = stmtSqlRow + + default: + panic(gerror.NewCodef(gcode.CodeInvalidParameter, `invalid SqlType "%s"`, in.Type)) + } + // Result handling. + switch { + case sqlResult != nil && !c.GetIgnoreResultFromCtx(ctx): + rowsAffected, err = sqlResult.RowsAffected() + out.Result = sqlResult + + case sqlRows != nil: + out.Records, err = c.RowsToResult(ctx, sqlRows) + rowsAffected = int64(len(out.Records)) + + case sqlStmt != nil: + out.Stmt = &Stmt{ + Stmt: sqlStmt, + core: c, + link: in.Link, + sql: in.Sql, + } + } + var ( + timestampMilli2 = gtime.TimestampMilli() + sqlObj = &Sql{ + Sql: in.Sql, + Type: in.Type, + Args: in.Args, + Format: formattedSql, + Error: err, + Start: timestampMilli1, + End: timestampMilli2, + Group: c.db.GetGroup(), + Schema: c.db.GetSchema(), + RowsAffected: rowsAffected, + IsTransaction: in.IsTransaction, + } + ) + + // Tracing. + c.traceSpanEnd(ctx, span, sqlObj) + + // Logging. + if c.db.GetDebug() { + c.writeSqlToLogger(ctx, sqlObj) + } + if err != nil && err != sql.ErrNoRows { + err = gerror.WrapCode( + gcode.CodeDbOperationError, + err, + FormatSqlWithArgs(in.Sql, in.Args), + ) + } + return out, err } // Prepare creates a prepared statement for later queries or executions. @@ -312,190 +311,200 @@ func (c *Core) DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutp // The parameter `execOnMaster` specifies whether executing the sql on master node, // or else it executes the sql on slave node if master-slave configured. func (c *Core) Prepare(ctx context.Context, sql string, execOnMaster ...bool) (*Stmt, error) { - var ( - err error - link Link - ) - if len(execOnMaster) > 0 && execOnMaster[0] { - if link, err = c.MasterLink(); err != nil { - return nil, err - } - } else { - if link, err = c.SlaveLink(); err != nil { - return nil, err - } - } - return c.db.DoPrepare(ctx, link, sql) + var ( + err error + link Link + ) + if len(execOnMaster) > 0 && execOnMaster[0] { + if link, err = c.MasterLink(); err != nil { + return nil, err + } + } else { + if link, err = c.SlaveLink(); err != nil { + return nil, err + } + } + return c.db.DoPrepare(ctx, link, sql) } // DoPrepare calls prepare function on given link object and returns the statement object. func (c *Core) DoPrepare(ctx context.Context, link Link, sql string) (stmt *Stmt, err error) { - // Transaction checks. - if link == nil { - if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { - // Firstly, check and retrieve transaction link from context. - link = &txLink{tx.GetSqlTX()} - } else { - // Or else it creates one from master node. - if link, err = c.MasterLink(); err != nil { - return nil, err - } - } - } else if !link.IsTransaction() { - // If current link is not transaction link, it checks and retrieves transaction from context. - if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { - link = &txLink{tx.GetSqlTX()} - } - } - - if c.db.GetConfig().PrepareTimeout > 0 { - // DO NOT USE cancel function in prepare statement. - var cancelFunc context.CancelFunc - ctx, cancelFunc = context.WithTimeout(ctx, c.db.GetConfig().PrepareTimeout) - defer cancelFunc() - } - - // Link execution. - var out DoCommitOutput - out, err = c.db.DoCommit(ctx, DoCommitInput{ - Link: link, - Sql: sql, - Type: SqlTypePrepareContext, - IsTransaction: link.IsTransaction(), - }) - if err != nil { - return nil, err - } - return out.Stmt, err + // Transaction checks. + if link == nil { + if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { + // Firstly, check and retrieve transaction link from context. + link = &txLink{tx.GetSqlTX()} + } else { + // Or else it creates one from master node. + if link, err = c.MasterLink(); err != nil { + return nil, err + } + } + } else if !link.IsTransaction() { + // If current link is not transaction link, it checks and retrieves transaction from context. + if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { + link = &txLink{tx.GetSqlTX()} + } + } + + if c.db.GetConfig().PrepareTimeout > 0 { + // DO NOT USE cancel function in prepare statement. + var cancelFunc context.CancelFunc + ctx, cancelFunc = context.WithTimeout(ctx, c.db.GetConfig().PrepareTimeout) + defer cancelFunc() + } + + // Link execution. + var out DoCommitOutput + out, err = c.db.DoCommit(ctx, DoCommitInput{ + Link: link, + Sql: sql, + Type: SqlTypePrepareContext, + IsTransaction: link.IsTransaction(), + }) + if err != nil { + return nil, err + } + return out.Stmt, err } // FormatUpsert formats and returns SQL clause part for upsert statement. // In default implements, this function performs upsert statement for MySQL like: // `INSERT INTO ... ON DUPLICATE KEY UPDATE x=VALUES(z),m=VALUES(y)...` func (c *Core) FormatUpsert(columns []string, list List, option DoInsertOption) (string, error) { - var onDuplicateStr string - if option.OnDuplicateStr != "" { - onDuplicateStr = option.OnDuplicateStr - } else if len(option.OnDuplicateMap) > 0 { - for k, v := range option.OnDuplicateMap { - if len(onDuplicateStr) > 0 { - onDuplicateStr += "," - } - switch v.(type) { - case Raw, *Raw: - onDuplicateStr += fmt.Sprintf( - "%s=%s", - c.QuoteWord(k), - v, - ) - default: - onDuplicateStr += fmt.Sprintf( - "%s=VALUES(%s)", - c.QuoteWord(k), - c.QuoteWord(gconv.String(v)), - ) - } - } - } else { - for _, column := range columns { - // If it's `SAVE` operation, do not automatically update the creating time. - if c.IsSoftCreatedFieldName(column) { - continue - } - if len(onDuplicateStr) > 0 { - onDuplicateStr += "," - } - onDuplicateStr += fmt.Sprintf( - "%s=VALUES(%s)", - c.QuoteWord(column), - c.QuoteWord(column), - ) - } - } - - return InsertOnDuplicateKeyUpdate + " " + onDuplicateStr, nil + var onDuplicateStr string + if option.OnDuplicateStr != "" { + onDuplicateStr = option.OnDuplicateStr + } else if len(option.OnDuplicateMap) > 0 { + for k, v := range option.OnDuplicateMap { + if len(onDuplicateStr) > 0 { + onDuplicateStr += "," + } + switch v.(type) { + case Raw, *Raw: + onDuplicateStr += fmt.Sprintf( + "%s=%s", + c.QuoteWord(k), + v, + ) + default: + onDuplicateStr += fmt.Sprintf( + "%s=VALUES(%s)", + c.QuoteWord(k), + c.QuoteWord(gconv.String(v)), + ) + } + } + } else { + for _, column := range columns { + // If it's `SAVE` operation, do not automatically update the creating time. + if c.IsSoftCreatedFieldName(column) { + continue + } + if len(onDuplicateStr) > 0 { + onDuplicateStr += "," + } + onDuplicateStr += fmt.Sprintf( + "%s=VALUES(%s)", + c.QuoteWord(column), + c.QuoteWord(column), + ) + } + } + + return InsertOnDuplicateKeyUpdate + " " + onDuplicateStr, nil } // RowsToResult converts underlying data record type sql.Rows to Result type. func (c *Core) RowsToResult(ctx context.Context, rows *sql.Rows) (Result, error) { - if rows == nil { - return nil, nil - } - defer func() { - if err := rows.Close(); err != nil { - intlog.Errorf(ctx, `%+v`, err) - } - }() - if !rows.Next() { - return nil, nil - } - // Column names and types. - columnTypes, err := rows.ColumnTypes() - if err != nil { - return nil, err - } - - if len(columnTypes) > 0 { - if internalData := c.getInternalColumnFromCtx(ctx); internalData != nil { - internalData.FirstResultColumn = columnTypes[0].Name() - } - } - var ( - values = make([]interface{}, len(columnTypes)) - result = make(Result, 0) - scanArgs = make([]interface{}, len(values)) - ) - for i := range values { - scanArgs[i] = &values[i] - } - for { - if err = rows.Scan(scanArgs...); err != nil { - return result, err - } - record := Record{} - for i, value := range values { - if value == nil { - // DO NOT use `gvar.New(nil)` here as it creates an initialized object - // which will cause struct converting issue. - record[columnTypes[i].Name()] = nil - } else { - var convertedValue interface{} - if convertedValue, err = c.columnValueToLocalValue(ctx, value, columnTypes[i]); err != nil { - return nil, err - } - record[columnTypes[i].Name()] = gvar.New(convertedValue) - } - } - result = append(result, record) - if !rows.Next() { - break - } - } - return result, nil + if rows == nil { + return nil, nil + } + defer func() { + if err := rows.Close(); err != nil { + intlog.Errorf(ctx, `%+v`, err) + } + }() + if !rows.Next() { + return nil, nil + } + // Column names and types. + columnTypes, err := rows.ColumnTypes() + if err != nil { + return nil, err + } + + if len(columnTypes) > 0 { + if internalData := c.getInternalColumnFromCtx(ctx); internalData != nil { + internalData.FirstResultColumn = columnTypes[0].Name() + } + } + var ( + values = make([]interface{}, len(columnTypes)) + result = make(Result, 0) + scanArgs = make([]interface{}, len(values)) + ) + for i := range values { + scanArgs[i] = &values[i] + } + for { + if err = rows.Scan(scanArgs...); err != nil { + return result, err + } + record := Record{} + for i, value := range values { + if value == nil { + // DO NOT use `gvar.New(nil)` here as it creates an initialized object + // which will cause struct converting issue. + record[columnTypes[i].Name()] = nil + } else { + var ( + convertedValue interface{} + columnType = columnTypes[i] + localType = LocalTypeUndefined + ) + if convertedValue, err = c.columnValueToLocalValue(ctx, value, columnType); err != nil { + return nil, err + } + localType, err = c.db.CheckLocalTypeForField(ctx, columnType.DatabaseTypeName(), value) + if err != nil { + return nil, err + } + record[columnTypes[i].Name()] = NewValueWithType(convertedValue, localType) + } + } + result = append(result, record) + if !rows.Next() { + break + } + } + return result, nil } // OrderRandomFunction returns the SQL function for random ordering. func (c *Core) OrderRandomFunction() string { - return "RAND()" + return "RAND()" } -func (c *Core) columnValueToLocalValue(ctx context.Context, value interface{}, columnType *sql.ColumnType) (interface{}, error) { - var scanType = columnType.ScanType() - if scanType != nil { - // Common basic builtin types. - switch scanType.Kind() { - case - reflect.Bool, - reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, - reflect.Float32, reflect.Float64: - return gconv.Convert( - gconv.String(value), - columnType.ScanType().String(), - ), nil - default: - } - } - // Other complex types, especially custom types. - return c.db.ConvertValueForLocal(ctx, columnType.DatabaseTypeName(), value) +func (c *Core) columnValueToLocalValue( + ctx context.Context, value interface{}, columnType *sql.ColumnType, +) (interface{}, error) { + var scanType = columnType.ScanType() + if scanType != nil { + // Common basic builtin types. + switch scanType.Kind() { + case + reflect.Bool, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64: + return gconv.Convert( + gconv.String(value), + columnType.ScanType().String(), + ), nil + default: + } + } + // Other complex types, especially custom types. + return c.db.ConvertValueForLocal(ctx, columnType.DatabaseTypeName(), value) } diff --git a/database/gdb/gdb_type_result.go b/database/gdb/gdb_type_result.go index 03e7051d3a9..5ebce52d2c1 100644 --- a/database/gdb/gdb_type_result.go +++ b/database/gdb/gdb_type_result.go @@ -7,198 +7,199 @@ package gdb import ( - "database/sql" - "math" + "database/sql" + "math" - "github.com/gogf/gf/v2/container/gvar" - "github.com/gogf/gf/v2/encoding/gjson" - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/util/gconv" ) // IsEmpty checks and returns whether `r` is empty. func (r Result) IsEmpty() bool { - return r == nil || r.Len() == 0 + return r == nil || r.Len() == 0 } // Len returns the length of result list. func (r Result) Len() int { - return len(r) + return len(r) } // Size is alias of function Len. func (r Result) Size() int { - return r.Len() + return r.Len() } // Chunk splits a Result into multiple Results, // the size of each array is determined by `size`. // The last chunk may contain less than size elements. func (r Result) Chunk(size int) []Result { - if size < 1 { - return nil - } - length := len(r) - chunks := int(math.Ceil(float64(length) / float64(size))) - var n []Result - for i, end := 0, 0; chunks > 0; chunks-- { - end = (i + 1) * size - if end > length { - end = length - } - n = append(n, r[i*size:end]) - i++ - } - return n + if size < 1 { + return nil + } + length := len(r) + chunks := int(math.Ceil(float64(length) / float64(size))) + var n []Result + for i, end := 0, 0; chunks > 0; chunks-- { + end = (i + 1) * size + if end > length { + end = length + } + n = append(n, r[i*size:end]) + i++ + } + return n } // Json converts `r` to JSON format content. func (r Result) Json() string { - content, _ := gjson.New(r.List()).ToJsonString() - return content + content, _ := gjson.New(r.List()).ToJsonString() + return content } // Xml converts `r` to XML format content. func (r Result) Xml(rootTag ...string) string { - content, _ := gjson.New(r.List()).ToXmlString(rootTag...) - return content + content, _ := gjson.New(r.List()).ToXmlString(rootTag...) + return content } // List converts `r` to a List. func (r Result) List() List { - list := make(List, len(r)) - for k, v := range r { - list[k] = v.Map() - } - return list + list := make(List, len(r)) + for k, v := range r { + list[k] = v.Map() + } + return list } // Array retrieves and returns specified column values as slice. // The parameter `field` is optional is the column field is only one. // The default `field` is the first field name of the first item in `Result` if parameter `field` is not given. func (r Result) Array(field ...string) []Value { - array := make([]Value, len(r)) - if len(r) == 0 { - return array - } - key := "" - if len(field) > 0 && field[0] != "" { - key = field[0] - } else { - for k := range r[0] { - key = k - break - } - } - for k, v := range r { - array[k] = v[key] - } - return array + array := make([]Value, len(r)) + if len(r) == 0 { + return array + } + key := "" + if len(field) > 0 && field[0] != "" { + key = field[0] + } else { + for k := range r[0] { + key = k + break + } + } + for k, v := range r { + array[k] = v[key] + } + return array } // MapKeyValue converts `r` to a map[string]Value of which key is specified by `key`. // Note that the item value may be type of slice. func (r Result) MapKeyValue(key string) map[string]Value { - var ( - s string - m = make(map[string]Value) - tempMap = make(map[string][]interface{}) - hasMultiValues bool - ) - for _, item := range r { - if k, ok := item[key]; ok { - s = k.String() - tempMap[s] = append(tempMap[s], item) - if len(tempMap[s]) > 1 { - hasMultiValues = true - } - } - } - for k, v := range tempMap { - if hasMultiValues { - m[k] = gvar.New(v) - } else { - m[k] = gvar.New(v[0]) - } - } - return m + var ( + s string + m = make(map[string]Value) + tempMap = make(map[string][]interface{}) + localType LocalType + hasMultiValues bool + ) + for _, item := range r { + if k, ok := item[key]; ok { + s = k.String() + localType = k.LocalType() + tempMap[s] = append(tempMap[s], item) + if len(tempMap[s]) > 1 { + hasMultiValues = true + } + } + } + for k, v := range tempMap { + if hasMultiValues { + m[k] = NewValue(v) + } else { + m[k] = NewValueWithType(v[0], localType) + } + } + return m } // MapKeyStr converts `r` to a map[string]Map of which key is specified by `key`. func (r Result) MapKeyStr(key string) map[string]Map { - m := make(map[string]Map) - for _, item := range r { - if v, ok := item[key]; ok { - m[v.String()] = item.Map() - } - } - return m + m := make(map[string]Map) + for _, item := range r { + if v, ok := item[key]; ok { + m[v.String()] = item.Map() + } + } + return m } // MapKeyInt converts `r` to a map[int]Map of which key is specified by `key`. func (r Result) MapKeyInt(key string) map[int]Map { - m := make(map[int]Map) - for _, item := range r { - if v, ok := item[key]; ok { - m[v.Int()] = item.Map() - } - } - return m + m := make(map[int]Map) + for _, item := range r { + if v, ok := item[key]; ok { + m[v.Int()] = item.Map() + } + } + return m } // MapKeyUint converts `r` to a map[uint]Map of which key is specified by `key`. func (r Result) MapKeyUint(key string) map[uint]Map { - m := make(map[uint]Map) - for _, item := range r { - if v, ok := item[key]; ok { - m[v.Uint()] = item.Map() - } - } - return m + m := make(map[uint]Map) + for _, item := range r { + if v, ok := item[key]; ok { + m[v.Uint()] = item.Map() + } + } + return m } // RecordKeyStr converts `r` to a map[string]Record of which key is specified by `key`. func (r Result) RecordKeyStr(key string) map[string]Record { - m := make(map[string]Record) - for _, item := range r { - if v, ok := item[key]; ok { - m[v.String()] = item - } - } - return m + m := make(map[string]Record) + for _, item := range r { + if v, ok := item[key]; ok { + m[v.String()] = item + } + } + return m } // RecordKeyInt converts `r` to a map[int]Record of which key is specified by `key`. func (r Result) RecordKeyInt(key string) map[int]Record { - m := make(map[int]Record) - for _, item := range r { - if v, ok := item[key]; ok { - m[v.Int()] = item - } - } - return m + m := make(map[int]Record) + for _, item := range r { + if v, ok := item[key]; ok { + m[v.Int()] = item + } + } + return m } // RecordKeyUint converts `r` to a map[uint]Record of which key is specified by `key`. func (r Result) RecordKeyUint(key string) map[uint]Record { - m := make(map[uint]Record) - for _, item := range r { - if v, ok := item[key]; ok { - m[v.Uint()] = item - } - } - return m + m := make(map[uint]Record) + for _, item := range r { + if v, ok := item[key]; ok { + m[v.Uint()] = item + } + } + return m } // Structs converts `r` to struct slice. // Note that the parameter `pointer` should be type of *[]struct/*[]*struct. func (r Result) Structs(pointer interface{}) (err error) { - // If the result is empty and the target pointer is not empty, it returns error. - if r.IsEmpty() { - if !empty.IsEmpty(pointer, true) { - return sql.ErrNoRows - } - return nil - } - return gconv.StructsTag(r, pointer, OrmTagForStruct) + // If the result is empty and the target pointer is not empty, it returns error. + if r.IsEmpty() { + if !empty.IsEmpty(pointer, true) { + return sql.ErrNoRows + } + return nil + } + return gconv.StructsTag(r, pointer, OrmTagForStruct) } diff --git a/database/gdb/gdb_type_value.go b/database/gdb/gdb_type_value.go new file mode 100644 index 00000000000..4945e7c59d9 --- /dev/null +++ b/database/gdb/gdb_type_value.go @@ -0,0 +1,19 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gdb + +import "github.com/gogf/gf/v2/database/gdb/internal/fieldvar" + +// NewValue creates and returns a new Value object. +func NewValue(value any) Value { + return fieldvar.New(value) +} + +// NewValueWithType creates and returns a new Value object with specified local type. +func NewValueWithType(value any, localType LocalType) Value { + return fieldvar.NewWithType(value, localType) +} diff --git a/database/gdb/internal/defines/defines.go b/database/gdb/internal/defines/defines.go new file mode 100644 index 00000000000..090aa55b74d --- /dev/null +++ b/database/gdb/internal/defines/defines.go @@ -0,0 +1,36 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +// Package defines provides some common definitions for gdb package. +package defines + +// LocalType is a type that defines the local storage type of a field value. +// It is used to specify how the field value should be processed locally. +type LocalType string + +const ( + LocalTypeUndefined LocalType = "" + LocalTypeString LocalType = "string" + LocalTypeTime LocalType = "time" + LocalTypeDate LocalType = "date" + LocalTypeDatetime LocalType = "datetime" + LocalTypeInt LocalType = "int" + LocalTypeUint LocalType = "uint" + LocalTypeInt64 LocalType = "int64" + LocalTypeUint64 LocalType = "uint64" + LocalTypeIntSlice LocalType = "[]int" + LocalTypeInt64Slice LocalType = "[]int64" + LocalTypeUint64Slice LocalType = "[]uint64" + LocalTypeStringSlice LocalType = "[]string" + LocalTypeInt64Bytes LocalType = "int64-bytes" + LocalTypeUint64Bytes LocalType = "uint64-bytes" + LocalTypeFloat32 LocalType = "float32" + LocalTypeFloat64 LocalType = "float64" + LocalTypeBytes LocalType = "[]byte" + LocalTypeBool LocalType = "bool" + LocalTypeJson LocalType = "json" + LocalTypeJsonb LocalType = "jsonb" +) diff --git a/database/gdb/internal/fieldvar/fieldvar.go b/database/gdb/internal/fieldvar/fieldvar.go new file mode 100644 index 00000000000..41b36997fd9 --- /dev/null +++ b/database/gdb/internal/fieldvar/fieldvar.go @@ -0,0 +1,63 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +// Package fieldvar provides a variable wrapper for field value in database operations. +// It is used for field value storage and conversion in database operations. +package fieldvar + +import ( + "github.com/gogf/gf/v2/database/gdb/internal/defines" + "github.com/gogf/gf/v2/internal/json" +) + +// Var is a wrapper for any type of value, which is used for field variable. +// Note that, do not embed *gvar.Var into Var but use it as an attribute, as there issue in nil pointer receiver +// when calling methods that is not defined directly on Var. +type Var struct { + value any + localType defines.LocalType +} + +// New creates and returns a new Var object. +func New(value any) *Var { + return &Var{ + value: value, + } +} + +// NewWithType creates and returns a new Var object with specified local type. +func NewWithType(value any, localType defines.LocalType) *Var { + return &Var{ + value: value, + localType: localType, + } +} + +// LocalType returns the local type of the value. +func (v *Var) LocalType() defines.LocalType { + return v.localType +} + +// MarshalJSON implements the interface MarshalJSON for json.Marshal. +func (v *Var) MarshalJSON() ([]byte, error) { + return json.Marshal(v.Val()) +} + +// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. +func (v *Var) UnmarshalJSON(b []byte) error { + var i interface{} + if err := json.UnmarshalUseNumber(b, &i); err != nil { + return err + } + v.Set(i) + return nil +} + +// UnmarshalValue is an interface implement which sets any type of value for Var. +func (v *Var) UnmarshalValue(value interface{}) error { + v.Set(value) + return nil +} diff --git a/database/gdb/internal/fieldvar/fieldvar_basic.go b/database/gdb/internal/fieldvar/fieldvar_basic.go new file mode 100644 index 00000000000..75b91458176 --- /dev/null +++ b/database/gdb/internal/fieldvar/fieldvar_basic.go @@ -0,0 +1,99 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package fieldvar + +import ( + "github.com/gogf/gf/v2/util/gconv" +) + +// Val returns the current value of `v`. +func (v *Var) Val() interface{} { + if v == nil { + return nil + } + return v.value +} + +// Interface is alias of Val. +func (v *Var) Interface() interface{} { + return v.Val() +} + +// Bytes converts and returns `v` as []byte. +func (v *Var) Bytes() []byte { + return gconv.Bytes(v.Val()) +} + +// String converts and returns `v` as string. +func (v *Var) String() string { + return gconv.String(v.Val()) +} + +// Bool converts and returns `v` as bool. +func (v *Var) Bool() bool { + return gconv.Bool(v.Val()) +} + +// Int converts and returns `v` as int. +func (v *Var) Int() int { + return gconv.Int(v.Val()) +} + +// Int8 converts and returns `v` as int8. +func (v *Var) Int8() int8 { + return gconv.Int8(v.Val()) +} + +// Int16 converts and returns `v` as int16. +func (v *Var) Int16() int16 { + return gconv.Int16(v.Val()) +} + +// Int32 converts and returns `v` as int32. +func (v *Var) Int32() int32 { + return gconv.Int32(v.Val()) +} + +// Int64 converts and returns `v` as int64. +func (v *Var) Int64() int64 { + return gconv.Int64(v.Val()) +} + +// Uint converts and returns `v` as uint. +func (v *Var) Uint() uint { + return gconv.Uint(v.Val()) +} + +// Uint8 converts and returns `v` as uint8. +func (v *Var) Uint8() uint8 { + return gconv.Uint8(v.Val()) +} + +// Uint16 converts and returns `v` as uint16. +func (v *Var) Uint16() uint16 { + return gconv.Uint16(v.Val()) +} + +// Uint32 converts and returns `v` as uint32. +func (v *Var) Uint32() uint32 { + return gconv.Uint32(v.Val()) +} + +// Uint64 converts and returns `v` as uint64. +func (v *Var) Uint64() uint64 { + return gconv.Uint64(v.Val()) +} + +// Float32 converts and returns `v` as float32. +func (v *Var) Float32() float32 { + return gconv.Float32(v.Val()) +} + +// Float64 converts and returns `v` as float64. +func (v *Var) Float64() float64 { + return gconv.Float64(v.Val()) +} diff --git a/database/gdb/internal/fieldvar/fieldvar_copy.go b/database/gdb/internal/fieldvar/fieldvar_copy.go new file mode 100644 index 00000000000..4698a9a881b --- /dev/null +++ b/database/gdb/internal/fieldvar/fieldvar_copy.go @@ -0,0 +1,30 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package fieldvar + +import ( + "github.com/gogf/gf/v2/internal/deepcopy" + "github.com/gogf/gf/v2/util/gutil" +) + +// Copy does a deep copy of current Var and returns a pointer to this Var. +func (v *Var) Copy() *Var { + return NewWithType(gutil.Copy(v.Val()), v.localType) +} + +// Clone does a shallow copy of current Var and returns a pointer to this Var. +func (v *Var) Clone() *Var { + return NewWithType(v.Val(), v.localType) +} + +// DeepCopy implements interface for deep copy of current type. +func (v *Var) DeepCopy() interface{} { + if v == nil { + return nil + } + return NewWithType(deepcopy.Copy(v.Val()), v.localType) +} diff --git a/database/gdb/internal/fieldvar/fieldvar_is.go b/database/gdb/internal/fieldvar/fieldvar_is.go new file mode 100644 index 00000000000..3c8c17a3a4c --- /dev/null +++ b/database/gdb/internal/fieldvar/fieldvar_is.go @@ -0,0 +1,51 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package fieldvar + +import ( + "github.com/gogf/gf/v2/internal/utils" +) + +// IsNil checks whether `v` is nil. +func (v *Var) IsNil() bool { + return utils.IsNil(v.Val()) +} + +// IsEmpty checks whether `v` is empty. +func (v *Var) IsEmpty() bool { + return utils.IsEmpty(v.Val()) +} + +// IsInt checks whether `v` is type of int. +func (v *Var) IsInt() bool { + return utils.IsInt(v.Val()) +} + +// IsUint checks whether `v` is type of uint. +func (v *Var) IsUint() bool { + return utils.IsUint(v.Val()) +} + +// IsFloat checks whether `v` is type of float. +func (v *Var) IsFloat() bool { + return utils.IsFloat(v.Val()) +} + +// IsSlice checks whether `v` is type of slice. +func (v *Var) IsSlice() bool { + return utils.IsSlice(v.Val()) +} + +// IsMap checks whether `v` is type of map. +func (v *Var) IsMap() bool { + return utils.IsMap(v.Val()) +} + +// IsStruct checks whether `v` is type of struct. +func (v *Var) IsStruct() bool { + return utils.IsStruct(v.Val()) +} diff --git a/database/gdb/internal/fieldvar/fieldvar_map.go b/database/gdb/internal/fieldvar/fieldvar_map.go new file mode 100644 index 00000000000..a70d6c84afa --- /dev/null +++ b/database/gdb/internal/fieldvar/fieldvar_map.go @@ -0,0 +1,65 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package fieldvar + +import "github.com/gogf/gf/v2/util/gconv" + +// MapOption specifies the option for map converting. +type MapOption = gconv.MapOption + +// Map converts and returns `v` as map[string]interface{}. +func (v *Var) Map(option ...MapOption) map[string]interface{} { + return gconv.Map(v.Val(), option...) +} + +// MapStrAny is like function Map, but implements the interface of MapStrAny. +func (v *Var) MapStrAny(option ...MapOption) map[string]interface{} { + return v.Map(option...) +} + +// MapStrStr converts and returns `v` as map[string]string. +func (v *Var) MapStrStr(option ...MapOption) map[string]string { + return gconv.MapStrStr(v.Val(), option...) +} + +// MapStrVar converts and returns `v` as map[string]Var. +func (v *Var) MapStrVar(option ...MapOption) map[string]*Var { + m := v.Map(option...) + if len(m) > 0 { + vMap := make(map[string]*Var, len(m)) + for k, v := range m { + vMap[k] = New(v) + } + return vMap + } + return nil +} + +// Maps converts and returns `v` as map[string]string. +// See gconv.Maps. +func (v *Var) Maps(option ...MapOption) []map[string]interface{} { + return gconv.Maps(v.Val(), option...) +} + +// MapToMap converts any map type variable `params` to another map type variable `pointer`. +// See gconv.MapToMap. +func (v *Var) MapToMap(pointer interface{}, mapping ...map[string]string) (err error) { + return gconv.MapToMap(v.Val(), pointer, mapping...) +} + +// MapToMaps converts any map type variable `params` to another map type variable `pointer`. +// See gconv.MapToMaps. +func (v *Var) MapToMaps(pointer interface{}, mapping ...map[string]string) (err error) { + return gconv.MapToMaps(v.Val(), pointer, mapping...) +} + +// MapToMapsDeep converts any map type variable `params` to another map type variable +// `pointer` recursively. +// See gconv.MapToMapsDeep. +func (v *Var) MapToMapsDeep(pointer interface{}, mapping ...map[string]string) (err error) { + return gconv.MapToMaps(v.Val(), pointer, mapping...) +} diff --git a/database/gdb/internal/fieldvar/fieldvar_scan.go b/database/gdb/internal/fieldvar/fieldvar_scan.go new file mode 100644 index 00000000000..3da52ab78d4 --- /dev/null +++ b/database/gdb/internal/fieldvar/fieldvar_scan.go @@ -0,0 +1,18 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package fieldvar + +import ( + "github.com/gogf/gf/v2/util/gconv" +) + +// Scan automatically checks the type of `pointer` and converts value of Var to `pointer`. +// +// See gconv.Scan. +func (v *Var) Scan(pointer interface{}, mapping ...map[string]string) error { + return gconv.Scan(v.Val(), pointer, mapping...) +} diff --git a/database/gdb/internal/fieldvar/fieldvar_set.go b/database/gdb/internal/fieldvar/fieldvar_set.go new file mode 100644 index 00000000000..e31f9a449f5 --- /dev/null +++ b/database/gdb/internal/fieldvar/fieldvar_set.go @@ -0,0 +1,14 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package fieldvar + +// Set sets `value` to `v`, and returns the old value. +func (v *Var) Set(value interface{}) (old interface{}) { + old = v.value + v.value = value + return +} diff --git a/database/gdb/internal/fieldvar/fieldvar_slice.go b/database/gdb/internal/fieldvar/fieldvar_slice.go new file mode 100644 index 00000000000..6659d7b9a8e --- /dev/null +++ b/database/gdb/internal/fieldvar/fieldvar_slice.go @@ -0,0 +1,86 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package fieldvar + +import ( + "github.com/gogf/gf/v2/database/gdb/internal/defines" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/util/gconv" +) + +// Ints converts and returns `v` as []int. +func (v *Var) Ints() []int { + return gconv.Ints(v.Val()) +} + +// Int64s converts and returns `v` as []int64. +func (v *Var) Int64s() []int64 { + return gconv.Int64s(v.Val()) +} + +// Uints converts and returns `v` as []uint. +func (v *Var) Uints() []uint { + return gconv.Uints(v.Val()) +} + +// Uint64s converts and returns `v` as []uint64. +func (v *Var) Uint64s() []uint64 { + return gconv.Uint64s(v.Val()) +} + +// Floats is alias of Float64s. +func (v *Var) Floats() []float64 { + return gconv.Floats(v.Val()) +} + +// Float32s converts and returns `v` as []float32. +func (v *Var) Float32s() []float32 { + return gconv.Float32s(v.Val()) +} + +// Float64s converts and returns `v` as []float64. +func (v *Var) Float64s() []float64 { + return gconv.Float64s(v.Val()) +} + +// Strings converts and returns `v` as []string. +func (v *Var) Strings() []string { + if v.localType == defines.LocalTypeJson { + var s []string + _ = json.Unmarshal(v.Bytes(), &s) + return s + } + return gconv.Strings(v.Val()) +} + +// Interfaces converts and returns `v` as []interfaces{}. +func (v *Var) Interfaces() []interface{} { + return gconv.Interfaces(v.Val()) +} + +// Slice is alias of Interfaces. +func (v *Var) Slice() []interface{} { + return v.Interfaces() +} + +// Array is alias of Interfaces. +func (v *Var) Array() []interface{} { + return v.Interfaces() +} + +// Vars converts and returns `v` as []Var. +func (v *Var) Vars() []*Var { + array := gconv.Interfaces(v.Val()) + if len(array) == 0 { + return nil + } + vars := make([]*Var, len(array)) + for k, v := range array { + vars[k] = New(v) + } + return vars +} diff --git a/database/gdb/internal/fieldvar/fieldvar_struct.go b/database/gdb/internal/fieldvar/fieldvar_struct.go new file mode 100644 index 00000000000..904f48e32fc --- /dev/null +++ b/database/gdb/internal/fieldvar/fieldvar_struct.go @@ -0,0 +1,23 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package fieldvar + +import ( + "github.com/gogf/gf/v2/util/gconv" +) + +// Struct maps value of `v` to `pointer`. +// The parameter `pointer` should be a pointer to a struct instance. +// The parameter `mapping` is used to specify the key-to-attribute mapping rules. +func (v *Var) Struct(pointer interface{}, mapping ...map[string]string) error { + return gconv.Struct(v.Val(), pointer, mapping...) +} + +// Structs converts and returns `v` as given struct slice. +func (v *Var) Structs(pointer interface{}, mapping ...map[string]string) error { + return gconv.Structs(v.Val(), pointer, mapping...) +} diff --git a/database/gdb/internal/fieldvar/fieldvar_time.go b/database/gdb/internal/fieldvar/fieldvar_time.go new file mode 100644 index 00000000000..4a8bf30c6d6 --- /dev/null +++ b/database/gdb/internal/fieldvar/fieldvar_time.go @@ -0,0 +1,34 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package fieldvar + +import ( + "time" + + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" +) + +// Time converts and returns `v` as time.Time. +// The parameter `format` specifies the format of the time string using gtime, +// Example: Y-m-d H:i:s. +func (v *Var) Time(format ...string) time.Time { + return gconv.Time(v.Val(), format...) +} + +// Duration converts and returns `v` as time.Duration. +// If value of `v` is string, then it uses time.ParseDuration for conversion. +func (v *Var) Duration() time.Duration { + return gconv.Duration(v.Val()) +} + +// GTime converts and returns `v` as *gtime.Time. +// The parameter `format` specifies the format of the time string using gtime, +// Example: Y-m-d H:i:s. +func (v *Var) GTime(format ...string) *gtime.Time { + return gconv.GTime(v.Val(), format...) +} diff --git a/example/go.mod b/example/go.mod index 426044591d5..1c106f2d9eb 100644 --- a/example/go.mod +++ b/example/go.mod @@ -25,12 +25,12 @@ require ( github.com/nacos-group/nacos-sdk-go/v2 v2.2.7 github.com/polarismesh/polaris-go v1.5.8 github.com/prometheus/client_golang v1.20.2 - go.opentelemetry.io/otel v1.29.0 + go.opentelemetry.io/otel v1.32.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 go.opentelemetry.io/otel/exporters/prometheus v0.46.0 - go.opentelemetry.io/otel/sdk v1.29.0 + go.opentelemetry.io/otel/sdk v1.32.0 golang.org/x/time v0.6.0 google.golang.org/grpc v1.68.1 google.golang.org/protobuf v1.34.2 @@ -129,9 +129,9 @@ require ( go.etcd.io/etcd/client/pkg/v3 v3.5.17 // indirect go.etcd.io/etcd/client/v3 v3.5.17 // indirect go.opentelemetry.io/contrib/instrumentation/runtime v0.49.0 // indirect - go.opentelemetry.io/otel/metric v1.29.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.29.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.10.0 // indirect go.uber.org/zap v1.26.0 // indirect diff --git a/example/go.sum b/example/go.sum index 71f6c7064a6..cf23d2c40d6 100644 --- a/example/go.sum +++ b/example/go.sum @@ -665,8 +665,8 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -709,8 +709,8 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tevid/gohamcrest v1.1.1 h1:ou+xSqlIw1xfGTg1uq1nif/htZ2S3EzRqLm2BP+tYU0= @@ -748,8 +748,8 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/contrib/instrumentation/runtime v0.49.0 h1:dg9y+7ArpumB6zwImJv47RHfdgOGQ1EMkzP5vLkEnTU= go.opentelemetry.io/contrib/instrumentation/runtime v0.49.0/go.mod h1:Ul4MtXqu/hJBM+v7a6dCF0nHwckPMLpIpLeCi4+zfdw= -go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= -go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg= @@ -758,14 +758,14 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 h1:JAv0J go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0/go.mod h1:QNKLmUEAq2QUbPQUfvw4fmv0bgbK7UlOSFCnXyfvSNc= go.opentelemetry.io/otel/exporters/prometheus v0.46.0 h1:I8WIFXR351FoLJYuloU4EgXbtNX2URfU/85pUPheIEQ= go.opentelemetry.io/otel/exporters/prometheus v0.46.0/go.mod h1:ztwVUHe5DTR/1v7PeuGRnU5Bbd4QKYwApWmuutKsJSs= -go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= -go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= -go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= -go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= -go.opentelemetry.io/otel/sdk/metric v1.24.0 h1:yyMQrPzF+k88/DbH7o4FMAs80puqd+9osbiBrJrz/w8= -go.opentelemetry.io/otel/sdk/metric v1.24.0/go.mod h1:I6Y5FjH6rvEnTTAYQz3Mmv2kl6Ek5IIrmwTLqMrrOE0= -go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= -go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= +go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= From 008315326857ca315696d4e8c3c5f8be290df6cc Mon Sep 17 00:00:00 2001 From: John Guo Date: Thu, 9 Jan 2025 12:06:38 +0800 Subject: [PATCH 02/48] gofmt --- container/gvar/gvar.go | 44 +- container/gvar/gvar_basic.go | 54 +- container/gvar/gvar_copy.go | 16 +- container/gvar/gvar_scan.go | 4 +- container/gvar/gvar_set.go | 20 +- container/gvar/gvar_time.go | 12 +- database/gdb/gdb.go | 1676 ++++++++--------- database/gdb/gdb_core.go | 1054 +++++------ database/gdb/gdb_core_structure.go | 876 ++++----- database/gdb/gdb_core_underlying.go | 870 ++++----- database/gdb/gdb_type_result.go | 248 +-- database/gdb/gdb_type_value.go | 4 +- .../gdb/internal/fieldvar/fieldvar_basic.go | 42 +- .../gdb/internal/fieldvar/fieldvar_copy.go | 16 +- .../gdb/internal/fieldvar/fieldvar_map.go | 32 +- .../gdb/internal/fieldvar/fieldvar_slice.go | 56 +- .../gdb/internal/fieldvar/fieldvar_struct.go | 6 +- .../gdb/internal/fieldvar/fieldvar_time.go | 12 +- 18 files changed, 2521 insertions(+), 2521 deletions(-) diff --git a/container/gvar/gvar.go b/container/gvar/gvar.go index 99e13134f44..07cd9af69b6 100644 --- a/container/gvar/gvar.go +++ b/container/gvar/gvar.go @@ -8,48 +8,48 @@ package gvar import ( - "github.com/gogf/gf/v2/container/gtype" - "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/container/gtype" + "github.com/gogf/gf/v2/internal/json" ) // Var is an universal variable type implementer. type Var struct { - value interface{} // Underlying value. - safe bool // Concurrent safe or not. + value interface{} // Underlying value. + safe bool // Concurrent safe or not. } // New creates and returns a new Var with given `value`. // The optional parameter `safe` specifies whether Var is used in concurrent-safety, // which is false in default. func New(value interface{}, safe ...bool) *Var { - if len(safe) > 0 && safe[0] { - return &Var{ - value: gtype.NewInterface(value), - safe: true, - } - } - return &Var{ - value: value, - } + if len(safe) > 0 && safe[0] { + return &Var{ + value: gtype.NewInterface(value), + safe: true, + } + } + return &Var{ + value: value, + } } // MarshalJSON implements the interface MarshalJSON for json.Marshal. func (v *Var) MarshalJSON() ([]byte, error) { - return json.Marshal(v.Val()) + return json.Marshal(v.Val()) } // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. func (v *Var) UnmarshalJSON(b []byte) error { - var i interface{} - if err := json.UnmarshalUseNumber(b, &i); err != nil { - return err - } - v.Set(i) - return nil + var i interface{} + if err := json.UnmarshalUseNumber(b, &i); err != nil { + return err + } + v.Set(i) + return nil } // UnmarshalValue is an interface implement which sets any type of value for Var. func (v *Var) UnmarshalValue(value interface{}) error { - v.Set(value) - return nil + v.Set(value) + return nil } diff --git a/container/gvar/gvar_basic.go b/container/gvar/gvar_basic.go index 9bd87ece7f5..a7613afb9f9 100644 --- a/container/gvar/gvar_basic.go +++ b/container/gvar/gvar_basic.go @@ -7,99 +7,99 @@ package gvar import ( - "github.com/gogf/gf/v2/container/gtype" - "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/container/gtype" + "github.com/gogf/gf/v2/util/gconv" ) // Val returns the current value of `v`. func (v *Var) Val() interface{} { - if v == nil { - return nil - } - if v.safe { - if t, ok := v.value.(*gtype.Interface); ok { - return t.Val() - } - } - return v.value + if v == nil { + return nil + } + if v.safe { + if t, ok := v.value.(*gtype.Interface); ok { + return t.Val() + } + } + return v.value } // Interface is alias of Val. func (v *Var) Interface() interface{} { - return v.Val() + return v.Val() } // Bytes converts and returns `v` as []byte. func (v *Var) Bytes() []byte { - return gconv.Bytes(v.Val()) + return gconv.Bytes(v.Val()) } // String converts and returns `v` as string. func (v *Var) String() string { - return gconv.String(v.Val()) + return gconv.String(v.Val()) } // Bool converts and returns `v` as bool. func (v *Var) Bool() bool { - return gconv.Bool(v.Val()) + return gconv.Bool(v.Val()) } // Int converts and returns `v` as int. func (v *Var) Int() int { - return gconv.Int(v.Val()) + return gconv.Int(v.Val()) } // Int8 converts and returns `v` as int8. func (v *Var) Int8() int8 { - return gconv.Int8(v.Val()) + return gconv.Int8(v.Val()) } // Int16 converts and returns `v` as int16. func (v *Var) Int16() int16 { - return gconv.Int16(v.Val()) + return gconv.Int16(v.Val()) } // Int32 converts and returns `v` as int32. func (v *Var) Int32() int32 { - return gconv.Int32(v.Val()) + return gconv.Int32(v.Val()) } // Int64 converts and returns `v` as int64. func (v *Var) Int64() int64 { - return gconv.Int64(v.Val()) + return gconv.Int64(v.Val()) } // Uint converts and returns `v` as uint. func (v *Var) Uint() uint { - return gconv.Uint(v.Val()) + return gconv.Uint(v.Val()) } // Uint8 converts and returns `v` as uint8. func (v *Var) Uint8() uint8 { - return gconv.Uint8(v.Val()) + return gconv.Uint8(v.Val()) } // Uint16 converts and returns `v` as uint16. func (v *Var) Uint16() uint16 { - return gconv.Uint16(v.Val()) + return gconv.Uint16(v.Val()) } // Uint32 converts and returns `v` as uint32. func (v *Var) Uint32() uint32 { - return gconv.Uint32(v.Val()) + return gconv.Uint32(v.Val()) } // Uint64 converts and returns `v` as uint64. func (v *Var) Uint64() uint64 { - return gconv.Uint64(v.Val()) + return gconv.Uint64(v.Val()) } // Float32 converts and returns `v` as float32. func (v *Var) Float32() float32 { - return gconv.Float32(v.Val()) + return gconv.Float32(v.Val()) } // Float64 converts and returns `v` as float64. func (v *Var) Float64() float64 { - return gconv.Float64(v.Val()) + return gconv.Float64(v.Val()) } diff --git a/container/gvar/gvar_copy.go b/container/gvar/gvar_copy.go index 2bb99919cf0..a85d3748288 100644 --- a/container/gvar/gvar_copy.go +++ b/container/gvar/gvar_copy.go @@ -7,24 +7,24 @@ package gvar import ( - "github.com/gogf/gf/v2/internal/deepcopy" - "github.com/gogf/gf/v2/util/gutil" + "github.com/gogf/gf/v2/internal/deepcopy" + "github.com/gogf/gf/v2/util/gutil" ) // Copy does a deep copy of current Var and returns a pointer to this Var. func (v *Var) Copy() *Var { - return New(gutil.Copy(v.Val()), v.safe) + return New(gutil.Copy(v.Val()), v.safe) } // Clone does a shallow copy of current Var and returns a pointer to this Var. func (v *Var) Clone() *Var { - return New(v.Val(), v.safe) + return New(v.Val(), v.safe) } // DeepCopy implements interface for deep copy of current type. func (v *Var) DeepCopy() interface{} { - if v == nil { - return nil - } - return New(deepcopy.Copy(v.Val()), v.safe) + if v == nil { + return nil + } + return New(deepcopy.Copy(v.Val()), v.safe) } diff --git a/container/gvar/gvar_scan.go b/container/gvar/gvar_scan.go index 9d47a22f230..5c38bfbfe6d 100644 --- a/container/gvar/gvar_scan.go +++ b/container/gvar/gvar_scan.go @@ -7,12 +7,12 @@ package gvar import ( - "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/gconv" ) // Scan automatically checks the type of `pointer` and converts value of Var to `pointer`. // // See gconv.Scan. func (v *Var) Scan(pointer interface{}, mapping ...map[string]string) error { - return gconv.Scan(v.Val(), pointer, mapping...) + return gconv.Scan(v.Val(), pointer, mapping...) } diff --git a/container/gvar/gvar_set.go b/container/gvar/gvar_set.go index 57ac97ae5b7..a00b2a627d4 100644 --- a/container/gvar/gvar_set.go +++ b/container/gvar/gvar_set.go @@ -7,18 +7,18 @@ package gvar import ( - "github.com/gogf/gf/v2/container/gtype" + "github.com/gogf/gf/v2/container/gtype" ) // Set sets `value` to `v`, and returns the old value. func (v *Var) Set(value interface{}) (old interface{}) { - if v.safe { - if t, ok := v.value.(*gtype.Interface); ok { - old = t.Set(value) - return - } - } - old = v.value - v.value = value - return + if v.safe { + if t, ok := v.value.(*gtype.Interface); ok { + old = t.Set(value) + return + } + } + old = v.value + v.value = value + return } diff --git a/container/gvar/gvar_time.go b/container/gvar/gvar_time.go index d709ce89fdd..2f47ad0815a 100644 --- a/container/gvar/gvar_time.go +++ b/container/gvar/gvar_time.go @@ -7,28 +7,28 @@ package gvar import ( - "time" + "time" - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" ) // Time converts and returns `v` as time.Time. // The parameter `format` specifies the format of the time string using gtime, // eg: Y-m-d H:i:s. func (v *Var) Time(format ...string) time.Time { - return gconv.Time(v.Val(), format...) + return gconv.Time(v.Val(), format...) } // Duration converts and returns `v` as time.Duration. // If value of `v` is string, then it uses time.ParseDuration for conversion. func (v *Var) Duration() time.Duration { - return gconv.Duration(v.Val()) + return gconv.Duration(v.Val()) } // GTime converts and returns `v` as *gtime.Time. // The parameter `format` specifies the format of the time string using gtime, // eg: Y-m-d H:i:s. func (v *Var) GTime(format ...string) *gtime.Time { - return gconv.GTime(v.Val(), format...) + return gconv.GTime(v.Val(), format...) } diff --git a/database/gdb/gdb.go b/database/gdb/gdb.go index efa41d521b9..e3419719260 100644 --- a/database/gdb/gdb.go +++ b/database/gdb/gdb.go @@ -10,901 +10,901 @@ package gdb import ( - "context" - "database/sql" - "time" - - "github.com/gogf/gf/v2/container/garray" - "github.com/gogf/gf/v2/container/gmap" - "github.com/gogf/gf/v2/container/gtype" - "github.com/gogf/gf/v2/database/gdb/internal/defines" - "github.com/gogf/gf/v2/database/gdb/internal/fieldvar" - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/os/gcache" - "github.com/gogf/gf/v2/os/gcmd" - "github.com/gogf/gf/v2/os/gctx" - "github.com/gogf/gf/v2/os/glog" - "github.com/gogf/gf/v2/util/grand" - "github.com/gogf/gf/v2/util/gutil" + "context" + "database/sql" + "time" + + "github.com/gogf/gf/v2/container/garray" + "github.com/gogf/gf/v2/container/gmap" + "github.com/gogf/gf/v2/container/gtype" + "github.com/gogf/gf/v2/database/gdb/internal/defines" + "github.com/gogf/gf/v2/database/gdb/internal/fieldvar" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/os/gcache" + "github.com/gogf/gf/v2/os/gcmd" + "github.com/gogf/gf/v2/os/gctx" + "github.com/gogf/gf/v2/os/glog" + "github.com/gogf/gf/v2/util/grand" + "github.com/gogf/gf/v2/util/gutil" ) // DB defines the interfaces for ORM operations. type DB interface { - // =========================================================================== - // Model creation. - // =========================================================================== - - // Model creates and returns a new ORM model from given schema. - // The parameter `table` can be more than one table names, and also alias name, like: - // 1. Model names: - // Model("user") - // Model("user u") - // Model("user, user_detail") - // Model("user u, user_detail ud") - // 2. Model name with alias: Model("user", "u") - // Also see Core.Model. - Model(tableNameOrStruct ...interface{}) *Model - - // Raw creates and returns a model based on a raw sql not a table. - Raw(rawSql string, args ...interface{}) *Model - - // Schema switches to a specified schema. - // Also see Core.Schema. - Schema(schema string) *Schema - - // With creates and returns an ORM model based on metadata of given object. - // Also see Core.With. - With(objects ...interface{}) *Model - - // Open creates a raw connection object for database with given node configuration. - // Note that it is not recommended using the function manually. - Open(config *ConfigNode) (*sql.DB, error) - - // Ctx is a chaining function, which creates and returns a new DB that is a shallow copy - // of current DB object and with given context in it. - // Also see Core.Ctx. - Ctx(ctx context.Context) DB - - // Close closes the database and prevents new queries from starting. - // Close then waits for all queries that have started processing on the server - // to finish. - // - // It is rare to Close a DB, as the DB handle is meant to be - // long-lived and shared between many goroutines. - Close(ctx context.Context) error - - // =========================================================================== - // Query APIs. - // =========================================================================== - - // Query executes a SQL query that returns rows using given SQL and arguments. - // The args are for any placeholder parameters in the query. - Query(ctx context.Context, sql string, args ...interface{}) (Result, error) - - // Exec executes a SQL query that doesn't return rows (e.g., INSERT, UPDATE, DELETE). - // It returns sql.Result for accessing LastInsertId or RowsAffected. - Exec(ctx context.Context, sql string, args ...interface{}) (sql.Result, error) - - // Prepare creates a prepared statement for later queries or executions. - // The execOnMaster parameter determines whether the statement executes on master node. - Prepare(ctx context.Context, sql string, execOnMaster ...bool) (*Stmt, error) - - // =========================================================================== - // Common APIs for CRUD. - // =========================================================================== - - // Insert inserts one or multiple records into table. - // The data can be a map, struct, or slice of maps/structs. - // The optional batch parameter specifies the batch size for bulk inserts. - Insert(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) - - // InsertIgnore inserts records but ignores duplicate key errors. - // It works like Insert but adds IGNORE keyword to the SQL statement. - InsertIgnore(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) - - // InsertAndGetId inserts a record and returns the auto-generated ID. - // It's a convenience method combining Insert with LastInsertId. - InsertAndGetId(ctx context.Context, table string, data interface{}, batch ...int) (int64, error) - - // Replace inserts or replaces records using REPLACE INTO syntax. - // Existing records with same unique key will be deleted and re-inserted. - Replace(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) - - // Save inserts or updates records using INSERT ... ON DUPLICATE KEY UPDATE syntax. - // It updates existing records instead of replacing them entirely. - Save(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) - - // Update updates records in table that match the condition. - // The data can be a map or struct containing the new values. - // The condition specifies the WHERE clause with optional placeholder args. - Update(ctx context.Context, table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) - - // Delete deletes records from table that match the condition. - // The condition specifies the WHERE clause with optional placeholder args. - Delete(ctx context.Context, table string, condition interface{}, args ...interface{}) (sql.Result, error) - - // =========================================================================== - // Internal APIs for CRUD, which can be overwritten by custom CRUD implements. - // =========================================================================== - - // DoSelect executes a SELECT query using the given link and returns the result. - // This is an internal method that can be overridden by custom implementations. - DoSelect(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) - - // DoInsert performs the actual INSERT operation with given options. - // This is an internal method that can be overridden by custom implementations. - DoInsert(ctx context.Context, link Link, table string, data List, option DoInsertOption) (result sql.Result, err error) - - // DoUpdate performs the actual UPDATE operation. - // This is an internal method that can be overridden by custom implementations. - DoUpdate(ctx context.Context, link Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) - - // DoDelete performs the actual DELETE operation. - // This is an internal method that can be overridden by custom implementations. - DoDelete(ctx context.Context, link Link, table string, condition string, args ...interface{}) (result sql.Result, err error) - - // DoQuery executes a query that returns rows. - // This is an internal method that can be overridden by custom implementations. - DoQuery(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) - - // DoExec executes a query that doesn't return rows. - // This is an internal method that can be overridden by custom implementations. - DoExec(ctx context.Context, link Link, sql string, args ...interface{}) (result sql.Result, err error) - - // DoFilter processes and filters SQL and args before execution. - // This is an internal method that can be overridden to implement custom SQL filtering. - DoFilter(ctx context.Context, link Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) - - // DoCommit handles the actual commit operation for transactions. - // This is an internal method that can be overridden by custom implementations. - DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutput, err error) - - // DoPrepare creates a prepared statement on the given link. - // This is an internal method that can be overridden by custom implementations. - DoPrepare(ctx context.Context, link Link, sql string) (*Stmt, error) - - // =========================================================================== - // Query APIs for convenience purpose. - // =========================================================================== - - // GetAll executes a query and returns all rows as Result. - // It's a convenience wrapper around Query. - GetAll(ctx context.Context, sql string, args ...interface{}) (Result, error) + // =========================================================================== + // Model creation. + // =========================================================================== + + // Model creates and returns a new ORM model from given schema. + // The parameter `table` can be more than one table names, and also alias name, like: + // 1. Model names: + // Model("user") + // Model("user u") + // Model("user, user_detail") + // Model("user u, user_detail ud") + // 2. Model name with alias: Model("user", "u") + // Also see Core.Model. + Model(tableNameOrStruct ...interface{}) *Model + + // Raw creates and returns a model based on a raw sql not a table. + Raw(rawSql string, args ...interface{}) *Model + + // Schema switches to a specified schema. + // Also see Core.Schema. + Schema(schema string) *Schema + + // With creates and returns an ORM model based on metadata of given object. + // Also see Core.With. + With(objects ...interface{}) *Model + + // Open creates a raw connection object for database with given node configuration. + // Note that it is not recommended using the function manually. + Open(config *ConfigNode) (*sql.DB, error) + + // Ctx is a chaining function, which creates and returns a new DB that is a shallow copy + // of current DB object and with given context in it. + // Also see Core.Ctx. + Ctx(ctx context.Context) DB + + // Close closes the database and prevents new queries from starting. + // Close then waits for all queries that have started processing on the server + // to finish. + // + // It is rare to Close a DB, as the DB handle is meant to be + // long-lived and shared between many goroutines. + Close(ctx context.Context) error + + // =========================================================================== + // Query APIs. + // =========================================================================== + + // Query executes a SQL query that returns rows using given SQL and arguments. + // The args are for any placeholder parameters in the query. + Query(ctx context.Context, sql string, args ...interface{}) (Result, error) + + // Exec executes a SQL query that doesn't return rows (e.g., INSERT, UPDATE, DELETE). + // It returns sql.Result for accessing LastInsertId or RowsAffected. + Exec(ctx context.Context, sql string, args ...interface{}) (sql.Result, error) + + // Prepare creates a prepared statement for later queries or executions. + // The execOnMaster parameter determines whether the statement executes on master node. + Prepare(ctx context.Context, sql string, execOnMaster ...bool) (*Stmt, error) + + // =========================================================================== + // Common APIs for CRUD. + // =========================================================================== + + // Insert inserts one or multiple records into table. + // The data can be a map, struct, or slice of maps/structs. + // The optional batch parameter specifies the batch size for bulk inserts. + Insert(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) + + // InsertIgnore inserts records but ignores duplicate key errors. + // It works like Insert but adds IGNORE keyword to the SQL statement. + InsertIgnore(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) + + // InsertAndGetId inserts a record and returns the auto-generated ID. + // It's a convenience method combining Insert with LastInsertId. + InsertAndGetId(ctx context.Context, table string, data interface{}, batch ...int) (int64, error) + + // Replace inserts or replaces records using REPLACE INTO syntax. + // Existing records with same unique key will be deleted and re-inserted. + Replace(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) + + // Save inserts or updates records using INSERT ... ON DUPLICATE KEY UPDATE syntax. + // It updates existing records instead of replacing them entirely. + Save(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) + + // Update updates records in table that match the condition. + // The data can be a map or struct containing the new values. + // The condition specifies the WHERE clause with optional placeholder args. + Update(ctx context.Context, table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) + + // Delete deletes records from table that match the condition. + // The condition specifies the WHERE clause with optional placeholder args. + Delete(ctx context.Context, table string, condition interface{}, args ...interface{}) (sql.Result, error) + + // =========================================================================== + // Internal APIs for CRUD, which can be overwritten by custom CRUD implements. + // =========================================================================== + + // DoSelect executes a SELECT query using the given link and returns the result. + // This is an internal method that can be overridden by custom implementations. + DoSelect(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) + + // DoInsert performs the actual INSERT operation with given options. + // This is an internal method that can be overridden by custom implementations. + DoInsert(ctx context.Context, link Link, table string, data List, option DoInsertOption) (result sql.Result, err error) + + // DoUpdate performs the actual UPDATE operation. + // This is an internal method that can be overridden by custom implementations. + DoUpdate(ctx context.Context, link Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) + + // DoDelete performs the actual DELETE operation. + // This is an internal method that can be overridden by custom implementations. + DoDelete(ctx context.Context, link Link, table string, condition string, args ...interface{}) (result sql.Result, err error) + + // DoQuery executes a query that returns rows. + // This is an internal method that can be overridden by custom implementations. + DoQuery(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) + + // DoExec executes a query that doesn't return rows. + // This is an internal method that can be overridden by custom implementations. + DoExec(ctx context.Context, link Link, sql string, args ...interface{}) (result sql.Result, err error) + + // DoFilter processes and filters SQL and args before execution. + // This is an internal method that can be overridden to implement custom SQL filtering. + DoFilter(ctx context.Context, link Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) + + // DoCommit handles the actual commit operation for transactions. + // This is an internal method that can be overridden by custom implementations. + DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutput, err error) + + // DoPrepare creates a prepared statement on the given link. + // This is an internal method that can be overridden by custom implementations. + DoPrepare(ctx context.Context, link Link, sql string) (*Stmt, error) + + // =========================================================================== + // Query APIs for convenience purpose. + // =========================================================================== + + // GetAll executes a query and returns all rows as Result. + // It's a convenience wrapper around Query. + GetAll(ctx context.Context, sql string, args ...interface{}) (Result, error) - // GetOne executes a query and returns the first row as Record. - // It's useful when you expect only one row to be returned. - GetOne(ctx context.Context, sql string, args ...interface{}) (Record, error) + // GetOne executes a query and returns the first row as Record. + // It's useful when you expect only one row to be returned. + GetOne(ctx context.Context, sql string, args ...interface{}) (Record, error) - // GetValue executes a query and returns the first column of the first row. - // It's useful for queries like SELECT COUNT(*) or getting a single value. - GetValue(ctx context.Context, sql string, args ...interface{}) (Value, error) + // GetValue executes a query and returns the first column of the first row. + // It's useful for queries like SELECT COUNT(*) or getting a single value. + GetValue(ctx context.Context, sql string, args ...interface{}) (Value, error) - // GetArray executes a query and returns the first column of all rows. - // It's useful for queries like SELECT id FROM table. - GetArray(ctx context.Context, sql string, args ...interface{}) ([]Value, error) + // GetArray executes a query and returns the first column of all rows. + // It's useful for queries like SELECT id FROM table. + GetArray(ctx context.Context, sql string, args ...interface{}) ([]Value, error) - // GetCount executes a COUNT query and returns the result as an integer. - // It's a convenience method for counting rows. - GetCount(ctx context.Context, sql string, args ...interface{}) (int, error) + // GetCount executes a COUNT query and returns the result as an integer. + // It's a convenience method for counting rows. + GetCount(ctx context.Context, sql string, args ...interface{}) (int, error) - // GetScan executes a query and scans the result into the given object pointer. - // It automatically maps database columns to struct fields or slice elements. - GetScan(ctx context.Context, objPointer interface{}, sql string, args ...interface{}) error + // GetScan executes a query and scans the result into the given object pointer. + // It automatically maps database columns to struct fields or slice elements. + GetScan(ctx context.Context, objPointer interface{}, sql string, args ...interface{}) error - // Union combines multiple SELECT queries using UNION operator. - // It returns a new Model that represents the combined query. - Union(unions ...*Model) *Model + // Union combines multiple SELECT queries using UNION operator. + // It returns a new Model that represents the combined query. + Union(unions ...*Model) *Model - // UnionAll combines multiple SELECT queries using UNION ALL operator. - // Unlike Union, it keeps duplicate rows in the result. - UnionAll(unions ...*Model) *Model + // UnionAll combines multiple SELECT queries using UNION ALL operator. + // Unlike Union, it keeps duplicate rows in the result. + UnionAll(unions ...*Model) *Model - // =========================================================================== - // Master/Slave specification support. - // =========================================================================== + // =========================================================================== + // Master/Slave specification support. + // =========================================================================== - // Master returns a connection to the master database node. - // The optional schema parameter specifies which database schema to use. - Master(schema ...string) (*sql.DB, error) + // Master returns a connection to the master database node. + // The optional schema parameter specifies which database schema to use. + Master(schema ...string) (*sql.DB, error) - // Slave returns a connection to a slave database node. - // The optional schema parameter specifies which database schema to use. - Slave(schema ...string) (*sql.DB, error) + // Slave returns a connection to a slave database node. + // The optional schema parameter specifies which database schema to use. + Slave(schema ...string) (*sql.DB, error) - // =========================================================================== - // Ping-Pong. - // =========================================================================== + // =========================================================================== + // Ping-Pong. + // =========================================================================== - // PingMaster checks if the master database node is accessible. - // It returns an error if the connection fails. - PingMaster() error + // PingMaster checks if the master database node is accessible. + // It returns an error if the connection fails. + PingMaster() error - // PingSlave checks if any slave database node is accessible. - // It returns an error if no slave connections are available. - PingSlave() error + // PingSlave checks if any slave database node is accessible. + // It returns an error if no slave connections are available. + PingSlave() error - // =========================================================================== - // Transaction. - // =========================================================================== + // =========================================================================== + // Transaction. + // =========================================================================== - // Begin starts a new transaction and returns a TX interface. - // The returned TX must be committed or rolled back to release resources. - Begin(ctx context.Context) (TX, error) + // Begin starts a new transaction and returns a TX interface. + // The returned TX must be committed or rolled back to release resources. + Begin(ctx context.Context) (TX, error) - // BeginWithOptions starts a new transaction with the given options and returns a TX interface. - // The options allow specifying isolation level and read-only mode. - // The returned TX must be committed or rolled back to release resources. - BeginWithOptions(ctx context.Context, opts TxOptions) (TX, error) + // BeginWithOptions starts a new transaction with the given options and returns a TX interface. + // The options allow specifying isolation level and read-only mode. + // The returned TX must be committed or rolled back to release resources. + BeginWithOptions(ctx context.Context, opts TxOptions) (TX, error) - // Transaction executes a function within a transaction. - // It automatically handles commit/rollback based on whether f returns an error. - Transaction(ctx context.Context, f func(ctx context.Context, tx TX) error) error + // Transaction executes a function within a transaction. + // It automatically handles commit/rollback based on whether f returns an error. + Transaction(ctx context.Context, f func(ctx context.Context, tx TX) error) error - // TransactionWithOptions executes a function within a transaction with specific options. - // It allows customizing transaction behavior like isolation level and timeout. - TransactionWithOptions(ctx context.Context, opts TxOptions, f func(ctx context.Context, tx TX) error) error + // TransactionWithOptions executes a function within a transaction with specific options. + // It allows customizing transaction behavior like isolation level and timeout. + TransactionWithOptions(ctx context.Context, opts TxOptions, f func(ctx context.Context, tx TX) error) error - // =========================================================================== - // Configuration methods. - // =========================================================================== + // =========================================================================== + // Configuration methods. + // =========================================================================== - // GetCache returns the cache instance used by this database. - // The cache is used for query results caching. - GetCache() *gcache.Cache + // GetCache returns the cache instance used by this database. + // The cache is used for query results caching. + GetCache() *gcache.Cache - // SetDebug enables or disables debug mode for SQL logging. - // When enabled, all SQL statements and their execution time are logged. - SetDebug(debug bool) + // SetDebug enables or disables debug mode for SQL logging. + // When enabled, all SQL statements and their execution time are logged. + SetDebug(debug bool) - // GetDebug returns whether debug mode is enabled. - GetDebug() bool + // GetDebug returns whether debug mode is enabled. + GetDebug() bool - // GetSchema returns the current database schema name. - GetSchema() string + // GetSchema returns the current database schema name. + GetSchema() string - // GetPrefix returns the table name prefix used by this database. - GetPrefix() string + // GetPrefix returns the table name prefix used by this database. + GetPrefix() string - // GetGroup returns the configuration group name of this database. - GetGroup() string + // GetGroup returns the configuration group name of this database. + GetGroup() string - // SetDryRun enables or disables dry-run mode. - // In dry-run mode, SQL statements are generated but not executed. - SetDryRun(enabled bool) + // SetDryRun enables or disables dry-run mode. + // In dry-run mode, SQL statements are generated but not executed. + SetDryRun(enabled bool) - // GetDryRun returns whether dry-run mode is enabled. - GetDryRun() bool + // GetDryRun returns whether dry-run mode is enabled. + GetDryRun() bool - // SetLogger sets a custom logger for database operations. - // The logger must implement glog.ILogger interface. - SetLogger(logger glog.ILogger) + // SetLogger sets a custom logger for database operations. + // The logger must implement glog.ILogger interface. + SetLogger(logger glog.ILogger) - // GetLogger returns the current logger used by this database. - GetLogger() glog.ILogger + // GetLogger returns the current logger used by this database. + GetLogger() glog.ILogger - // GetConfig returns the configuration node used by this database. - GetConfig() *ConfigNode + // GetConfig returns the configuration node used by this database. + GetConfig() *ConfigNode - // SetMaxIdleConnCount sets the maximum number of idle connections in the pool. - SetMaxIdleConnCount(n int) + // SetMaxIdleConnCount sets the maximum number of idle connections in the pool. + SetMaxIdleConnCount(n int) - // SetMaxOpenConnCount sets the maximum number of open connections to the database. - SetMaxOpenConnCount(n int) + // SetMaxOpenConnCount sets the maximum number of open connections to the database. + SetMaxOpenConnCount(n int) - // SetMaxConnLifeTime sets the maximum amount of time a connection may be reused. - SetMaxConnLifeTime(d time.Duration) + // SetMaxConnLifeTime sets the maximum amount of time a connection may be reused. + SetMaxConnLifeTime(d time.Duration) - // =========================================================================== - // Utility methods. - // =========================================================================== + // =========================================================================== + // Utility methods. + // =========================================================================== - // Stats returns statistics about the database connection pool. - // It includes information like the number of active and idle connections. - Stats(ctx context.Context) []StatsItem + // Stats returns statistics about the database connection pool. + // It includes information like the number of active and idle connections. + Stats(ctx context.Context) []StatsItem - // GetCtx returns the context associated with this database instance. - GetCtx() context.Context + // GetCtx returns the context associated with this database instance. + GetCtx() context.Context - // GetCore returns the underlying Core instance of this database. - GetCore() *Core + // GetCore returns the underlying Core instance of this database. + GetCore() *Core - // GetChars returns the left and right quote characters used for escaping identifiers. - // For example, in MySQL these are backticks: ` and `. - GetChars() (charLeft string, charRight string) + // GetChars returns the left and right quote characters used for escaping identifiers. + // For example, in MySQL these are backticks: ` and `. + GetChars() (charLeft string, charRight string) - // Tables returns a list of all table names in the specified schema. - // If no schema is specified, it uses the default schema. - Tables(ctx context.Context, schema ...string) (tables []string, err error) + // Tables returns a list of all table names in the specified schema. + // If no schema is specified, it uses the default schema. + Tables(ctx context.Context, schema ...string) (tables []string, err error) - // TableFields returns detailed information about all fields in the specified table. - // The returned map keys are field names and values contain field metadata. - TableFields(ctx context.Context, table string, schema ...string) (map[string]*TableField, error) + // TableFields returns detailed information about all fields in the specified table. + // The returned map keys are field names and values contain field metadata. + TableFields(ctx context.Context, table string, schema ...string) (map[string]*TableField, error) - // ConvertValueForField converts a value to the appropriate type for a database field. - // It handles type conversion from Go types to database-specific types. - ConvertValueForField(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) + // ConvertValueForField converts a value to the appropriate type for a database field. + // It handles type conversion from Go types to database-specific types. + ConvertValueForField(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) - // ConvertValueForLocal converts a database value to the appropriate Go type. - // It handles type conversion from database-specific types to Go types. - ConvertValueForLocal(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) + // ConvertValueForLocal converts a database value to the appropriate Go type. + // It handles type conversion from database-specific types to Go types. + ConvertValueForLocal(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) - // CheckLocalTypeForField checks if a Go value is compatible with a database field type. - // It returns the appropriate LocalType and any conversion errors. - CheckLocalTypeForField(ctx context.Context, fieldType string, fieldValue interface{}) (LocalType, error) + // CheckLocalTypeForField checks if a Go value is compatible with a database field type. + // It returns the appropriate LocalType and any conversion errors. + CheckLocalTypeForField(ctx context.Context, fieldType string, fieldValue interface{}) (LocalType, error) - // FormatUpsert formats an upsert (INSERT ... ON DUPLICATE KEY UPDATE) statement. - // It generates the appropriate SQL based on the columns, values, and options provided. - FormatUpsert(columns []string, list List, option DoInsertOption) (string, error) + // FormatUpsert formats an upsert (INSERT ... ON DUPLICATE KEY UPDATE) statement. + // It generates the appropriate SQL based on the columns, values, and options provided. + FormatUpsert(columns []string, list List, option DoInsertOption) (string, error) - // OrderRandomFunction returns the SQL function for random ordering. - // The implementation is database-specific (e.g., RAND() for MySQL). - OrderRandomFunction() string + // OrderRandomFunction returns the SQL function for random ordering. + // The implementation is database-specific (e.g., RAND() for MySQL). + OrderRandomFunction() string } // TX defines the interfaces for ORM transaction operations. type TX interface { - Link + Link - // Ctx binds a context to current transaction. - // The context is used for operations like timeout control. - Ctx(ctx context.Context) TX + // Ctx binds a context to current transaction. + // The context is used for operations like timeout control. + Ctx(ctx context.Context) TX - // Raw creates and returns a model based on a raw SQL. - // The rawSql can contain placeholders ? and corresponding args. - Raw(rawSql string, args ...interface{}) *Model + // Raw creates and returns a model based on a raw SQL. + // The rawSql can contain placeholders ? and corresponding args. + Raw(rawSql string, args ...interface{}) *Model - // Model creates and returns a Model from given table name/struct. - // The parameter can be table name as string, or struct/*struct type. - Model(tableNameQueryOrStruct ...interface{}) *Model + // Model creates and returns a Model from given table name/struct. + // The parameter can be table name as string, or struct/*struct type. + Model(tableNameQueryOrStruct ...interface{}) *Model - // With creates and returns a Model from given object. - // It automatically analyzes the object and generates corresponding SQL. - With(object interface{}) *Model + // With creates and returns a Model from given object. + // It automatically analyzes the object and generates corresponding SQL. + With(object interface{}) *Model - // =========================================================================== - // Nested transaction if necessary. - // =========================================================================== + // =========================================================================== + // Nested transaction if necessary. + // =========================================================================== - // Begin starts a nested transaction. - // It creates a new savepoint for current transaction. - Begin() error + // Begin starts a nested transaction. + // It creates a new savepoint for current transaction. + Begin() error - // Commit commits current transaction/savepoint. - // For nested transactions, it releases the current savepoint. - Commit() error + // Commit commits current transaction/savepoint. + // For nested transactions, it releases the current savepoint. + Commit() error - // Rollback rolls back current transaction/savepoint. - // For nested transactions, it rolls back to the current savepoint. - Rollback() error + // Rollback rolls back current transaction/savepoint. + // For nested transactions, it rolls back to the current savepoint. + Rollback() error - // Transaction executes given function in a nested transaction. - // It automatically handles commit/rollback based on function's error return. - Transaction(ctx context.Context, f func(ctx context.Context, tx TX) error) (err error) + // Transaction executes given function in a nested transaction. + // It automatically handles commit/rollback based on function's error return. + Transaction(ctx context.Context, f func(ctx context.Context, tx TX) error) (err error) - // TransactionWithOptions executes given function in a nested transaction with options. - // It allows customizing transaction behavior like isolation level. - TransactionWithOptions(ctx context.Context, opts TxOptions, f func(ctx context.Context, tx TX) error) error + // TransactionWithOptions executes given function in a nested transaction with options. + // It allows customizing transaction behavior like isolation level. + TransactionWithOptions(ctx context.Context, opts TxOptions, f func(ctx context.Context, tx TX) error) error - // =========================================================================== - // Core method. - // =========================================================================== + // =========================================================================== + // Core method. + // =========================================================================== - // Query executes a query that returns rows using given SQL and arguments. - // The args are for any placeholder parameters in the query. - Query(sql string, args ...interface{}) (result Result, err error) + // Query executes a query that returns rows using given SQL and arguments. + // The args are for any placeholder parameters in the query. + Query(sql string, args ...interface{}) (result Result, err error) - // Exec executes a query that doesn't return rows. - // For example: INSERT, UPDATE, DELETE. - Exec(sql string, args ...interface{}) (sql.Result, error) + // Exec executes a query that doesn't return rows. + // For example: INSERT, UPDATE, DELETE. + Exec(sql string, args ...interface{}) (sql.Result, error) - // Prepare creates a prepared statement for later queries or executions. - // Multiple queries or executions may be run concurrently from the statement. - Prepare(sql string) (*Stmt, error) + // Prepare creates a prepared statement for later queries or executions. + // Multiple queries or executions may be run concurrently from the statement. + Prepare(sql string) (*Stmt, error) - // =========================================================================== - // Query. - // =========================================================================== + // =========================================================================== + // Query. + // =========================================================================== - // GetAll executes a query and returns all rows as Result. - // It's a convenient wrapper for Query. - GetAll(sql string, args ...interface{}) (Result, error) + // GetAll executes a query and returns all rows as Result. + // It's a convenient wrapper for Query. + GetAll(sql string, args ...interface{}) (Result, error) - // GetOne executes a query and returns the first row as Record. - // It's useful when you expect only one row to be returned. - GetOne(sql string, args ...interface{}) (Record, error) + // GetOne executes a query and returns the first row as Record. + // It's useful when you expect only one row to be returned. + GetOne(sql string, args ...interface{}) (Record, error) - // GetStruct executes a query and scans the result into given struct. - // The obj should be a pointer to struct. - GetStruct(obj interface{}, sql string, args ...interface{}) error + // GetStruct executes a query and scans the result into given struct. + // The obj should be a pointer to struct. + GetStruct(obj interface{}, sql string, args ...interface{}) error - // GetStructs executes a query and scans all results into given struct slice. - // The objPointerSlice should be a pointer to slice of struct. - GetStructs(objPointerSlice interface{}, sql string, args ...interface{}) error + // GetStructs executes a query and scans all results into given struct slice. + // The objPointerSlice should be a pointer to slice of struct. + GetStructs(objPointerSlice interface{}, sql string, args ...interface{}) error - // GetScan executes a query and scans the result into given variables. - // The pointer can be type of struct/*struct/[]struct/[]*struct. - GetScan(pointer interface{}, sql string, args ...interface{}) error + // GetScan executes a query and scans the result into given variables. + // The pointer can be type of struct/*struct/[]struct/[]*struct. + GetScan(pointer interface{}, sql string, args ...interface{}) error - // GetValue executes a query and returns the first column of first row. - // It's useful for queries like SELECT COUNT(*). - GetValue(sql string, args ...interface{}) (Value, error) + // GetValue executes a query and returns the first column of first row. + // It's useful for queries like SELECT COUNT(*). + GetValue(sql string, args ...interface{}) (Value, error) - // GetCount executes a query that should return a count value. - // It's a convenient wrapper for count queries. - GetCount(sql string, args ...interface{}) (int64, error) + // GetCount executes a query that should return a count value. + // It's a convenient wrapper for count queries. + GetCount(sql string, args ...interface{}) (int64, error) - // =========================================================================== - // CRUD. - // =========================================================================== + // =========================================================================== + // CRUD. + // =========================================================================== - // Insert inserts one or multiple records into table. - // The data can be map/struct/*struct/[]map/[]struct/[]*struct. - Insert(table string, data interface{}, batch ...int) (sql.Result, error) + // Insert inserts one or multiple records into table. + // The data can be map/struct/*struct/[]map/[]struct/[]*struct. + Insert(table string, data interface{}, batch ...int) (sql.Result, error) - // InsertIgnore inserts one or multiple records with IGNORE option. - // It ignores records that would cause duplicate key conflicts. - InsertIgnore(table string, data interface{}, batch ...int) (sql.Result, error) + // InsertIgnore inserts one or multiple records with IGNORE option. + // It ignores records that would cause duplicate key conflicts. + InsertIgnore(table string, data interface{}, batch ...int) (sql.Result, error) - // InsertAndGetId inserts one record and returns its id value. - // It's commonly used with auto-increment primary key. - InsertAndGetId(table string, data interface{}, batch ...int) (int64, error) + // InsertAndGetId inserts one record and returns its id value. + // It's commonly used with auto-increment primary key. + InsertAndGetId(table string, data interface{}, batch ...int) (int64, error) - // Replace inserts or replaces records using REPLACE INTO syntax. - // Existing records with same unique key will be deleted and re-inserted. - Replace(table string, data interface{}, batch ...int) (sql.Result, error) + // Replace inserts or replaces records using REPLACE INTO syntax. + // Existing records with same unique key will be deleted and re-inserted. + Replace(table string, data interface{}, batch ...int) (sql.Result, error) - // Save inserts or updates records using INSERT ... ON DUPLICATE KEY UPDATE syntax. - // It updates existing records instead of replacing them entirely. - Save(table string, data interface{}, batch ...int) (sql.Result, error) + // Save inserts or updates records using INSERT ... ON DUPLICATE KEY UPDATE syntax. + // It updates existing records instead of replacing them entirely. + Save(table string, data interface{}, batch ...int) (sql.Result, error) - // Update updates records in table that match given condition. - // The data can be map/struct, and condition supports various formats. - Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) + // Update updates records in table that match given condition. + // The data can be map/struct, and condition supports various formats. + Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) - // Delete deletes records from table that match given condition. - // The condition supports various formats with optional arguments. - Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error) + // Delete deletes records from table that match given condition. + // The condition supports various formats with optional arguments. + Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error) - // =========================================================================== - // Utility methods. - // =========================================================================== + // =========================================================================== + // Utility methods. + // =========================================================================== - // GetCtx returns the context that is bound to current transaction. - GetCtx() context.Context + // GetCtx returns the context that is bound to current transaction. + GetCtx() context.Context - // GetDB returns the underlying DB interface object. - GetDB() DB + // GetDB returns the underlying DB interface object. + GetDB() DB - // GetSqlTX returns the underlying *sql.Tx object. - // Note: be very careful when using this method. - GetSqlTX() *sql.Tx + // GetSqlTX returns the underlying *sql.Tx object. + // Note: be very careful when using this method. + GetSqlTX() *sql.Tx - // IsClosed checks if current transaction is closed. - // A transaction is closed after Commit or Rollback. - IsClosed() bool + // IsClosed checks if current transaction is closed. + // A transaction is closed after Commit or Rollback. + IsClosed() bool - // =========================================================================== - // Save point feature. - // =========================================================================== + // =========================================================================== + // Save point feature. + // =========================================================================== - // SavePoint creates a save point with given name. - // It's used in nested transactions to create rollback points. - SavePoint(point string) error + // SavePoint creates a save point with given name. + // It's used in nested transactions to create rollback points. + SavePoint(point string) error - // RollbackTo rolls back transaction to previously created save point. - // If the save point doesn't exist, it returns an error. - RollbackTo(point string) error + // RollbackTo rolls back transaction to previously created save point. + // If the save point doesn't exist, it returns an error. + RollbackTo(point string) error } // StatsItem defines the stats information for a configuration node. type StatsItem interface { - // Node returns the configuration node info. - Node() ConfigNode + // Node returns the configuration node info. + Node() ConfigNode - // Stats returns the connection stat for current node. - Stats() sql.DBStats + // Stats returns the connection stat for current node. + Stats() sql.DBStats } // Core is the base struct for database management. type Core struct { - db DB // DB interface object. - ctx context.Context // Context for chaining operation only. Do not set a default value in Core initialization. - group string // Configuration group name. - schema string // Custom schema for this object. - debug *gtype.Bool // Enable debug mode for the database, which can be changed in runtime. - cache *gcache.Cache // Cache manager, SQL result cache only. - links *gmap.Map // links caches all created links by node. - logger glog.ILogger // Logger for logging functionality. - config *ConfigNode // Current config node. - dynamicConfig dynamicConfig // Dynamic configurations, which can be changed in runtime. - innerMemCache *gcache.Cache // Internal memory cache for storing temporary data. + db DB // DB interface object. + ctx context.Context // Context for chaining operation only. Do not set a default value in Core initialization. + group string // Configuration group name. + schema string // Custom schema for this object. + debug *gtype.Bool // Enable debug mode for the database, which can be changed in runtime. + cache *gcache.Cache // Cache manager, SQL result cache only. + links *gmap.Map // links caches all created links by node. + logger glog.ILogger // Logger for logging functionality. + config *ConfigNode // Current config node. + dynamicConfig dynamicConfig // Dynamic configurations, which can be changed in runtime. + innerMemCache *gcache.Cache // Internal memory cache for storing temporary data. } type dynamicConfig struct { - MaxIdleConnCount int - MaxOpenConnCount int - MaxConnLifeTime time.Duration + MaxIdleConnCount int + MaxOpenConnCount int + MaxConnLifeTime time.Duration } // DoCommitInput is the input parameters for function DoCommit. type DoCommitInput struct { - // Db is the underlying database connection object. - Db *sql.DB + // Db is the underlying database connection object. + Db *sql.DB - // Tx is the underlying transaction object. - Tx *sql.Tx + // Tx is the underlying transaction object. + Tx *sql.Tx - // Stmt is the prepared statement object. - Stmt *sql.Stmt + // Stmt is the prepared statement object. + Stmt *sql.Stmt - // Link is the common database function wrapper interface. - Link Link + // Link is the common database function wrapper interface. + Link Link - // Sql is the SQL string to be executed. - Sql string + // Sql is the SQL string to be executed. + Sql string - // Args is the arguments for SQL placeholders. - Args []interface{} + // Args is the arguments for SQL placeholders. + Args []interface{} - // Type indicates the type of SQL operation. - Type SqlType + // Type indicates the type of SQL operation. + Type SqlType - // TxOptions specifies the transaction options. - TxOptions sql.TxOptions + // TxOptions specifies the transaction options. + TxOptions sql.TxOptions - // TxCancelFunc is the context cancel function for transaction. - TxCancelFunc context.CancelFunc + // TxCancelFunc is the context cancel function for transaction. + TxCancelFunc context.CancelFunc - // IsTransaction indicates whether current operation is in transaction. - IsTransaction bool + // IsTransaction indicates whether current operation is in transaction. + IsTransaction bool } // DoCommitOutput is the output parameters for function DoCommit. type DoCommitOutput struct { - // Result is the result of exec statement. - Result sql.Result + // Result is the result of exec statement. + Result sql.Result - // Records is the result of query statement. - Records []Record + // Records is the result of query statement. + Records []Record - // Stmt is the Statement object result for Prepare. - Stmt *Stmt + // Stmt is the Statement object result for Prepare. + Stmt *Stmt - // Tx is the transaction object result for Begin. - Tx TX + // Tx is the transaction object result for Begin. + Tx TX - // RawResult is the underlying result, which might be sql.Result/*sql.Rows/*sql.Row. - RawResult interface{} + // RawResult is the underlying result, which might be sql.Result/*sql.Rows/*sql.Row. + RawResult interface{} } // Driver is the interface for integrating sql drivers into package gdb. type Driver interface { - // New creates and returns a database object for specified database server. - New(core *Core, node *ConfigNode) (DB, error) + // New creates and returns a database object for specified database server. + New(core *Core, node *ConfigNode) (DB, error) } // Link is a common database function wrapper interface. // Note that, any operation using `Link` will have no SQL logging. type Link interface { - QueryContext(ctx context.Context, sql string, args ...interface{}) (*sql.Rows, error) - ExecContext(ctx context.Context, sql string, args ...interface{}) (sql.Result, error) - PrepareContext(ctx context.Context, sql string) (*sql.Stmt, error) - IsOnMaster() bool - IsTransaction() bool + QueryContext(ctx context.Context, sql string, args ...interface{}) (*sql.Rows, error) + ExecContext(ctx context.Context, sql string, args ...interface{}) (sql.Result, error) + PrepareContext(ctx context.Context, sql string) (*sql.Stmt, error) + IsOnMaster() bool + IsTransaction() bool } // Sql is the sql recording struct. type Sql struct { - Sql string // SQL string(may contain reserved char '?'). - Type SqlType // SQL operation type. - Args []interface{} // Arguments for this sql. - Format string // Formatted sql which contains arguments in the sql. - Error error // Execution result. - Start int64 // Start execution timestamp in milliseconds. - End int64 // End execution timestamp in milliseconds. - Group string // Group is the group name of the configuration that the sql is executed from. - Schema string // Schema is the schema name of the configuration that the sql is executed from. - IsTransaction bool // IsTransaction marks whether this sql is executed in transaction. - RowsAffected int64 // RowsAffected marks retrieved or affected number with current sql statement. + Sql string // SQL string(may contain reserved char '?'). + Type SqlType // SQL operation type. + Args []interface{} // Arguments for this sql. + Format string // Formatted sql which contains arguments in the sql. + Error error // Execution result. + Start int64 // Start execution timestamp in milliseconds. + End int64 // End execution timestamp in milliseconds. + Group string // Group is the group name of the configuration that the sql is executed from. + Schema string // Schema is the schema name of the configuration that the sql is executed from. + IsTransaction bool // IsTransaction marks whether this sql is executed in transaction. + RowsAffected int64 // RowsAffected marks retrieved or affected number with current sql statement. } // DoInsertOption is the input struct for function DoInsert. type DoInsertOption struct { - // OnDuplicateStr is the custom string for `on duplicated` statement. - OnDuplicateStr string + // OnDuplicateStr is the custom string for `on duplicated` statement. + OnDuplicateStr string - // OnDuplicateMap is the custom key-value map from `OnDuplicateEx` function for `on duplicated` statement. - OnDuplicateMap map[string]interface{} + // OnDuplicateMap is the custom key-value map from `OnDuplicateEx` function for `on duplicated` statement. + OnDuplicateMap map[string]interface{} - // OnConflict is the custom conflict key of upsert clause, if the database needs it. - OnConflict []string + // OnConflict is the custom conflict key of upsert clause, if the database needs it. + OnConflict []string - // InsertOption is the insert operation in constant value. - InsertOption InsertOption + // InsertOption is the insert operation in constant value. + InsertOption InsertOption - // BatchCount is the batch count for batch inserting. - BatchCount int + // BatchCount is the batch count for batch inserting. + BatchCount int } // TableField is the struct for table field. type TableField struct { - // Index is for ordering purpose as map is unordered. - Index int + // Index is for ordering purpose as map is unordered. + Index int - // Name is the field name. - Name string + // Name is the field name. + Name string - // Type is the field type. Eg: 'int(10) unsigned', 'varchar(64)'. - Type string + // Type is the field type. Eg: 'int(10) unsigned', 'varchar(64)'. + Type string - // Null is whether the field can be null or not. - Null bool + // Null is whether the field can be null or not. + Null bool - // Key is the index information(empty if it's not an index). Eg: PRI, MUL. - Key string + // Key is the index information(empty if it's not an index). Eg: PRI, MUL. + Key string - // Default is the default value for the field. - Default interface{} + // Default is the default value for the field. + Default interface{} - // Extra is the extra information. Eg: auto_increment. - Extra string + // Extra is the extra information. Eg: auto_increment. + Extra string - // Comment is the field comment. - Comment string + // Comment is the field comment. + Comment string } // Counter is the type for update count. type Counter struct { - // Field is the field name. - Field string + // Field is the field name. + Field string - // Value is the value. - Value float64 + // Value is the value. + Value float64 } type ( - // Raw is a raw sql that will not be treated as argument but as a direct sql part. - Raw string + // Raw is a raw sql that will not be treated as argument but as a direct sql part. + Raw string - // Value is the field value type. - Value = *fieldvar.Var + // Value is the field value type. + Value = *fieldvar.Var - // Record is the row record of the table. - Record map[string]Value + // Record is the row record of the table. + Record map[string]Value - // Result is the row record array. - Result []Record + // Result is the row record array. + Result []Record - // Map is alias of map[string]interface{}, which is the most common usage map type. - Map = map[string]interface{} + // Map is alias of map[string]interface{}, which is the most common usage map type. + Map = map[string]interface{} - // List is type of map array. - List = []Map + // List is type of map array. + List = []Map ) type CatchSQLManager struct { - // SQLArray is the array of sql. - SQLArray *garray.StrArray + // SQLArray is the array of sql. + SQLArray *garray.StrArray - // DoCommit marks it will be committed to underlying driver or not. - DoCommit bool + // DoCommit marks it will be committed to underlying driver or not. + DoCommit bool } const ( - defaultModelSafe = false - defaultCharset = `utf8` - defaultProtocol = `tcp` - unionTypeNormal = 0 - unionTypeAll = 1 - defaultMaxIdleConnCount = 10 // Max idle connection count in pool. - defaultMaxOpenConnCount = 0 // Max open connection count in pool. Default is no limit. - defaultMaxConnLifeTime = 30 * time.Second // Max lifetime for per connection in pool in seconds. - cachePrefixTableFields = `TableFields:` - cachePrefixSelectCache = `SelectCache:` - commandEnvKeyForDryRun = "gf.gdb.dryrun" - modelForDaoSuffix = `ForDao` - dbRoleSlave = `slave` - ctxKeyForDB gctx.StrKey = `CtxKeyForDB` - ctxKeyCatchSQL gctx.StrKey = `CtxKeyCatchSQL` - ctxKeyInternalProducedSQL gctx.StrKey = `CtxKeyInternalProducedSQL` - - linkPattern = `^(\w+):(.*?):(.*?)@(\w+?)\((.+?)\)/{0,1}([^\?]*)\?{0,1}(.*?)$` - linkPatternDescription = `type:username:password@protocol(host:port)/dbname?param1=value1&...¶mN=valueN` + defaultModelSafe = false + defaultCharset = `utf8` + defaultProtocol = `tcp` + unionTypeNormal = 0 + unionTypeAll = 1 + defaultMaxIdleConnCount = 10 // Max idle connection count in pool. + defaultMaxOpenConnCount = 0 // Max open connection count in pool. Default is no limit. + defaultMaxConnLifeTime = 30 * time.Second // Max lifetime for per connection in pool in seconds. + cachePrefixTableFields = `TableFields:` + cachePrefixSelectCache = `SelectCache:` + commandEnvKeyForDryRun = "gf.gdb.dryrun" + modelForDaoSuffix = `ForDao` + dbRoleSlave = `slave` + ctxKeyForDB gctx.StrKey = `CtxKeyForDB` + ctxKeyCatchSQL gctx.StrKey = `CtxKeyCatchSQL` + ctxKeyInternalProducedSQL gctx.StrKey = `CtxKeyInternalProducedSQL` + + linkPattern = `^(\w+):(.*?):(.*?)@(\w+?)\((.+?)\)/{0,1}([^\?]*)\?{0,1}(.*?)$` + linkPatternDescription = `type:username:password@protocol(host:port)/dbname?param1=value1&...¶mN=valueN` ) type ctxTimeoutType int const ( - ctxTimeoutTypeExec ctxTimeoutType = iota - ctxTimeoutTypeQuery - ctxTimeoutTypePrepare - ctxTimeoutTypeTrans + ctxTimeoutTypeExec ctxTimeoutType = iota + ctxTimeoutTypeQuery + ctxTimeoutTypePrepare + ctxTimeoutTypeTrans ) type SelectType int const ( - SelectTypeDefault SelectType = iota - SelectTypeCount - SelectTypeValue - SelectTypeArray + SelectTypeDefault SelectType = iota + SelectTypeCount + SelectTypeValue + SelectTypeArray ) type joinOperator string const ( - joinOperatorLeft joinOperator = "LEFT" - joinOperatorRight joinOperator = "RIGHT" - joinOperatorInner joinOperator = "INNER" + joinOperatorLeft joinOperator = "LEFT" + joinOperatorRight joinOperator = "RIGHT" + joinOperatorInner joinOperator = "INNER" ) type InsertOption int const ( - InsertOptionDefault InsertOption = iota - InsertOptionReplace - InsertOptionSave - InsertOptionIgnore + InsertOptionDefault InsertOption = iota + InsertOptionReplace + InsertOptionSave + InsertOptionIgnore ) const ( - InsertOperationInsert = "INSERT" - InsertOperationReplace = "REPLACE" - InsertOperationIgnore = "INSERT IGNORE" - InsertOnDuplicateKeyUpdate = "ON DUPLICATE KEY UPDATE" + InsertOperationInsert = "INSERT" + InsertOperationReplace = "REPLACE" + InsertOperationIgnore = "INSERT IGNORE" + InsertOnDuplicateKeyUpdate = "ON DUPLICATE KEY UPDATE" ) type SqlType string const ( - SqlTypeBegin SqlType = "DB.Begin" - SqlTypeTXCommit SqlType = "TX.Commit" - SqlTypeTXRollback SqlType = "TX.Rollback" - SqlTypeExecContext SqlType = "DB.ExecContext" - SqlTypeQueryContext SqlType = "DB.QueryContext" - SqlTypePrepareContext SqlType = "DB.PrepareContext" - SqlTypeStmtExecContext SqlType = "DB.Statement.ExecContext" - SqlTypeStmtQueryContext SqlType = "DB.Statement.QueryContext" - SqlTypeStmtQueryRowContext SqlType = "DB.Statement.QueryRowContext" + SqlTypeBegin SqlType = "DB.Begin" + SqlTypeTXCommit SqlType = "TX.Commit" + SqlTypeTXRollback SqlType = "TX.Rollback" + SqlTypeExecContext SqlType = "DB.ExecContext" + SqlTypeQueryContext SqlType = "DB.QueryContext" + SqlTypePrepareContext SqlType = "DB.PrepareContext" + SqlTypeStmtExecContext SqlType = "DB.Statement.ExecContext" + SqlTypeStmtQueryContext SqlType = "DB.Statement.QueryContext" + SqlTypeStmtQueryRowContext SqlType = "DB.Statement.QueryRowContext" ) type LocalType = defines.LocalType const ( - LocalTypeUndefined = defines.LocalTypeUndefined - LocalTypeString = defines.LocalTypeString - LocalTypeTime = defines.LocalTypeTime - LocalTypeDate = defines.LocalTypeDate - LocalTypeDatetime = defines.LocalTypeDatetime - LocalTypeInt = defines.LocalTypeInt - LocalTypeUint = defines.LocalTypeUint - LocalTypeInt64 = defines.LocalTypeInt64 - LocalTypeUint64 = defines.LocalTypeUint64 - LocalTypeIntSlice = defines.LocalTypeIntSlice - LocalTypeInt64Slice = defines.LocalTypeInt64Slice - LocalTypeUint64Slice = defines.LocalTypeUint64Slice - LocalTypeStringSlice = defines.LocalTypeStringSlice - LocalTypeInt64Bytes = defines.LocalTypeInt64Bytes - LocalTypeUint64Bytes = defines.LocalTypeUint64Bytes - LocalTypeFloat32 = defines.LocalTypeFloat32 - LocalTypeFloat64 = defines.LocalTypeFloat64 - LocalTypeBytes = defines.LocalTypeBytes - LocalTypeBool = defines.LocalTypeBool - LocalTypeJson = defines.LocalTypeJson - LocalTypeJsonb = defines.LocalTypeJsonb + LocalTypeUndefined = defines.LocalTypeUndefined + LocalTypeString = defines.LocalTypeString + LocalTypeTime = defines.LocalTypeTime + LocalTypeDate = defines.LocalTypeDate + LocalTypeDatetime = defines.LocalTypeDatetime + LocalTypeInt = defines.LocalTypeInt + LocalTypeUint = defines.LocalTypeUint + LocalTypeInt64 = defines.LocalTypeInt64 + LocalTypeUint64 = defines.LocalTypeUint64 + LocalTypeIntSlice = defines.LocalTypeIntSlice + LocalTypeInt64Slice = defines.LocalTypeInt64Slice + LocalTypeUint64Slice = defines.LocalTypeUint64Slice + LocalTypeStringSlice = defines.LocalTypeStringSlice + LocalTypeInt64Bytes = defines.LocalTypeInt64Bytes + LocalTypeUint64Bytes = defines.LocalTypeUint64Bytes + LocalTypeFloat32 = defines.LocalTypeFloat32 + LocalTypeFloat64 = defines.LocalTypeFloat64 + LocalTypeBytes = defines.LocalTypeBytes + LocalTypeBool = defines.LocalTypeBool + LocalTypeJson = defines.LocalTypeJson + LocalTypeJsonb = defines.LocalTypeJsonb ) const ( - fieldTypeBinary = "binary" - fieldTypeVarbinary = "varbinary" - fieldTypeBlob = "blob" - fieldTypeTinyblob = "tinyblob" - fieldTypeMediumblob = "mediumblob" - fieldTypeLongblob = "longblob" - fieldTypeInt = "int" - fieldTypeTinyint = "tinyint" - fieldTypeSmallInt = "small_int" - fieldTypeSmallint = "smallint" - fieldTypeMediumInt = "medium_int" - fieldTypeMediumint = "mediumint" - fieldTypeSerial = "serial" - fieldTypeBigInt = "big_int" - fieldTypeBigint = "bigint" - fieldTypeBigserial = "bigserial" - fieldTypeReal = "real" - fieldTypeFloat = "float" - fieldTypeDouble = "double" - fieldTypeDecimal = "decimal" - fieldTypeMoney = "money" - fieldTypeNumeric = "numeric" - fieldTypeSmallmoney = "smallmoney" - fieldTypeBool = "bool" - fieldTypeBit = "bit" - fieldTypeYear = "year" // YYYY - fieldTypeDate = "date" // YYYY-MM-DD - fieldTypeTime = "time" // HH:MM:SS - fieldTypeDatetime = "datetime" // YYYY-MM-DD HH:MM:SS - fieldTypeTimestamp = "timestamp" // YYYYMMDD HHMMSS - fieldTypeTimestampz = "timestamptz" - fieldTypeJson = "json" - fieldTypeJsonb = "jsonb" + fieldTypeBinary = "binary" + fieldTypeVarbinary = "varbinary" + fieldTypeBlob = "blob" + fieldTypeTinyblob = "tinyblob" + fieldTypeMediumblob = "mediumblob" + fieldTypeLongblob = "longblob" + fieldTypeInt = "int" + fieldTypeTinyint = "tinyint" + fieldTypeSmallInt = "small_int" + fieldTypeSmallint = "smallint" + fieldTypeMediumInt = "medium_int" + fieldTypeMediumint = "mediumint" + fieldTypeSerial = "serial" + fieldTypeBigInt = "big_int" + fieldTypeBigint = "bigint" + fieldTypeBigserial = "bigserial" + fieldTypeReal = "real" + fieldTypeFloat = "float" + fieldTypeDouble = "double" + fieldTypeDecimal = "decimal" + fieldTypeMoney = "money" + fieldTypeNumeric = "numeric" + fieldTypeSmallmoney = "smallmoney" + fieldTypeBool = "bool" + fieldTypeBit = "bit" + fieldTypeYear = "year" // YYYY + fieldTypeDate = "date" // YYYY-MM-DD + fieldTypeTime = "time" // HH:MM:SS + fieldTypeDatetime = "datetime" // YYYY-MM-DD HH:MM:SS + fieldTypeTimestamp = "timestamp" // YYYYMMDD HHMMSS + fieldTypeTimestampz = "timestamptz" + fieldTypeJson = "json" + fieldTypeJsonb = "jsonb" ) var ( - // instances is the management map for instances. - instances = gmap.NewStrAnyMap(true) + // instances is the management map for instances. + instances = gmap.NewStrAnyMap(true) - // driverMap manages all custom registered driver. - driverMap = map[string]Driver{} + // driverMap manages all custom registered driver. + driverMap = map[string]Driver{} - // lastOperatorRegPattern is the regular expression pattern for a string - // which has operator at its tail. - lastOperatorRegPattern = `[<>=]+\s*$` + // lastOperatorRegPattern is the regular expression pattern for a string + // which has operator at its tail. + lastOperatorRegPattern = `[<>=]+\s*$` - // regularFieldNameRegPattern is the regular expression pattern for a string - // which is a regular field name of table. - regularFieldNameRegPattern = `^[\w\.\-]+$` + // regularFieldNameRegPattern is the regular expression pattern for a string + // which is a regular field name of table. + regularFieldNameRegPattern = `^[\w\.\-]+$` - // regularFieldNameWithCommaRegPattern is the regular expression pattern for one or more strings - // which are regular field names of table, multiple field names joined with char ','. - regularFieldNameWithCommaRegPattern = `^[\w\.\-,\s]+$` + // regularFieldNameWithCommaRegPattern is the regular expression pattern for one or more strings + // which are regular field names of table, multiple field names joined with char ','. + regularFieldNameWithCommaRegPattern = `^[\w\.\-,\s]+$` - // regularFieldNameWithoutDotRegPattern is similar to regularFieldNameRegPattern but not allows '.'. - // Note that, although some databases allow char '.' in the field name, but it here does not allow '.' - // in the field name as it conflicts with "db.table.field" pattern in SOME situations. - regularFieldNameWithoutDotRegPattern = `^[\w\-]+$` + // regularFieldNameWithoutDotRegPattern is similar to regularFieldNameRegPattern but not allows '.'. + // Note that, although some databases allow char '.' in the field name, but it here does not allow '.' + // in the field name as it conflicts with "db.table.field" pattern in SOME situations. + regularFieldNameWithoutDotRegPattern = `^[\w\-]+$` - // allDryRun sets dry-run feature for all database connections. - // It is commonly used for command options for convenience. - allDryRun = false + // allDryRun sets dry-run feature for all database connections. + // It is commonly used for command options for convenience. + allDryRun = false ) func init() { - // allDryRun is initialized from environment or command options. - allDryRun = gcmd.GetOptWithEnv(commandEnvKeyForDryRun, false).Bool() + // allDryRun is initialized from environment or command options. + allDryRun = gcmd.GetOptWithEnv(commandEnvKeyForDryRun, false).Bool() } // Register registers custom database driver to gdb. func Register(name string, driver Driver) error { - driverMap[name] = newDriverWrapper(driver) - return nil + driverMap[name] = newDriverWrapper(driver) + return nil } // New creates and returns an ORM object with given configuration node. func New(node ConfigNode) (db DB, err error) { - return newDBByConfigNode(&node, "") + return newDBByConfigNode(&node, "") } // NewByGroup creates and returns an ORM object with global configurations. // The parameter `name` specifies the configuration group name, // which is DefaultGroupName in default. func NewByGroup(group ...string) (db DB, err error) { - groupName := configs.group - if len(group) > 0 && group[0] != "" { - groupName = group[0] - } - configs.RLock() - defer configs.RUnlock() - - if len(configs.config) < 1 { - return nil, gerror.NewCode( - gcode.CodeInvalidConfiguration, - "database configuration is empty, please set the database configuration before using", - ) - } - if _, ok := configs.config[groupName]; ok { - var node *ConfigNode - if node, err = getConfigNodeByGroup(groupName, true); err == nil { - return newDBByConfigNode(node, groupName) - } - return nil, err - } - return nil, gerror.NewCodef( - gcode.CodeInvalidConfiguration, - `database configuration node "%s" is not found, did you misspell group name "%s" or miss the database configuration?`, - groupName, groupName, - ) + groupName := configs.group + if len(group) > 0 && group[0] != "" { + groupName = group[0] + } + configs.RLock() + defer configs.RUnlock() + + if len(configs.config) < 1 { + return nil, gerror.NewCode( + gcode.CodeInvalidConfiguration, + "database configuration is empty, please set the database configuration before using", + ) + } + if _, ok := configs.config[groupName]; ok { + var node *ConfigNode + if node, err = getConfigNodeByGroup(groupName, true); err == nil { + return newDBByConfigNode(node, groupName) + } + return nil, err + } + return nil, gerror.NewCodef( + gcode.CodeInvalidConfiguration, + `database configuration node "%s" is not found, did you misspell group name "%s" or miss the database configuration?`, + groupName, groupName, + ) } // newDBByConfigNode creates and returns an ORM object with given configuration node and group name. @@ -913,54 +913,54 @@ func NewByGroup(group ...string) (db DB, err error) { // The parameter `node` is used for DB creation, not for underlying connection creation. // So all db type configurations in the same group should be the same. func newDBByConfigNode(node *ConfigNode, group string) (db DB, err error) { - if node.Link != "" { - node, err = parseConfigNodeLink(node) - if err != nil { - return - } - } - c := &Core{ - group: group, - debug: gtype.NewBool(), - cache: gcache.New(), - links: gmap.New(true), - logger: glog.New(), - config: node, - innerMemCache: gcache.New(), - dynamicConfig: dynamicConfig{ - MaxIdleConnCount: node.MaxIdleConnCount, - MaxOpenConnCount: node.MaxOpenConnCount, - MaxConnLifeTime: node.MaxConnLifeTime, - }, - } - if v, ok := driverMap[node.Type]; ok { - if c.db, err = v.New(c, node); err != nil { - return nil, err - } - return c.db, nil - } - errorMsg := `cannot find database driver for specified database type "%s"` - errorMsg += `, did you misspell type name "%s" or forget importing the database driver? ` - errorMsg += `possible reference: https://github.com/gogf/gf/tree/master/contrib/drivers` - return nil, gerror.NewCodef(gcode.CodeInvalidConfiguration, errorMsg, node.Type, node.Type) + if node.Link != "" { + node, err = parseConfigNodeLink(node) + if err != nil { + return + } + } + c := &Core{ + group: group, + debug: gtype.NewBool(), + cache: gcache.New(), + links: gmap.New(true), + logger: glog.New(), + config: node, + innerMemCache: gcache.New(), + dynamicConfig: dynamicConfig{ + MaxIdleConnCount: node.MaxIdleConnCount, + MaxOpenConnCount: node.MaxOpenConnCount, + MaxConnLifeTime: node.MaxConnLifeTime, + }, + } + if v, ok := driverMap[node.Type]; ok { + if c.db, err = v.New(c, node); err != nil { + return nil, err + } + return c.db, nil + } + errorMsg := `cannot find database driver for specified database type "%s"` + errorMsg += `, did you misspell type name "%s" or forget importing the database driver? ` + errorMsg += `possible reference: https://github.com/gogf/gf/tree/master/contrib/drivers` + return nil, gerror.NewCodef(gcode.CodeInvalidConfiguration, errorMsg, node.Type, node.Type) } // Instance returns an instance for DB operations. // The parameter `name` specifies the configuration group name, // which is DefaultGroupName in default. func Instance(name ...string) (db DB, err error) { - group := configs.group - if len(name) > 0 && name[0] != "" { - group = name[0] - } - v := instances.GetOrSetFuncLock(group, func() interface{} { - db, err = NewByGroup(group) - return db - }) - if v != nil { - return v.(DB), nil - } - return + group := configs.group + if len(name) > 0 && name[0] != "" { + group = name[0] + } + v := instances.GetOrSetFuncLock(group, func() interface{} { + db, err = NewByGroup(group) + return db + }) + if v != nil { + return v.(DB), nil + } + return } // getConfigNodeByGroup calculates and returns a configuration node of given group. It @@ -971,39 +971,39 @@ func Instance(name ...string) (db DB, err error) { // The parameter `master` specifies whether retrieving a master node, or else a slave node // if master-slave nodes are configured. func getConfigNodeByGroup(group string, master bool) (*ConfigNode, error) { - if list, ok := configs.config[group]; ok { - // Separates master and slave configuration nodes array. - var ( - masterList = make(ConfigGroup, 0) - slaveList = make(ConfigGroup, 0) - ) - for i := 0; i < len(list); i++ { - if list[i].Role == dbRoleSlave { - slaveList = append(slaveList, list[i]) - } else { - masterList = append(masterList, list[i]) - } - } - if len(masterList) < 1 { - return nil, gerror.NewCode( - gcode.CodeInvalidConfiguration, - "at least one master node configuration's need to make sense", - ) - } - if len(slaveList) < 1 { - slaveList = masterList - } - if master { - return getConfigNodeByWeight(masterList), nil - } else { - return getConfigNodeByWeight(slaveList), nil - } - } - return nil, gerror.NewCodef( - gcode.CodeInvalidConfiguration, - "empty database configuration for item name '%s'", - group, - ) + if list, ok := configs.config[group]; ok { + // Separates master and slave configuration nodes array. + var ( + masterList = make(ConfigGroup, 0) + slaveList = make(ConfigGroup, 0) + ) + for i := 0; i < len(list); i++ { + if list[i].Role == dbRoleSlave { + slaveList = append(slaveList, list[i]) + } else { + masterList = append(masterList, list[i]) + } + } + if len(masterList) < 1 { + return nil, gerror.NewCode( + gcode.CodeInvalidConfiguration, + "at least one master node configuration's need to make sense", + ) + } + if len(slaveList) < 1 { + slaveList = masterList + } + if master { + return getConfigNodeByWeight(masterList), nil + } else { + return getConfigNodeByWeight(slaveList), nil + } + } + return nil, gerror.NewCodef( + gcode.CodeInvalidConfiguration, + "empty database configuration for item name '%s'", + group, + ) } // getConfigNodeByWeight calculates the configuration weights and randomly returns a node. @@ -1014,116 +1014,116 @@ func getConfigNodeByGroup(group string, master bool) (*ConfigNode, error) { // 2. Node1 weight range is [0, 99], and node2 weight range is [100, 199], ratio is 1:1; // 3. If the random number is 99, it then chooses and returns node1;. func getConfigNodeByWeight(cg ConfigGroup) *ConfigNode { - if len(cg) < 2 { - return &cg[0] - } - var total int - for i := 0; i < len(cg); i++ { - total += cg[i].Weight * 100 - } - // If total is 0 means all the nodes have no weight attribute configured. - // It then defaults each node's weight attribute to 1. - if total == 0 { - for i := 0; i < len(cg); i++ { - cg[i].Weight = 1 - total += cg[i].Weight * 100 - } - } - // Exclude the right border value. - var ( - minWeight = 0 - maxWeight = 0 - random = grand.N(0, total-1) - ) - for i := 0; i < len(cg); i++ { - maxWeight = minWeight + cg[i].Weight*100 - if random >= minWeight && random < maxWeight { - // ==================================================== - // Return a COPY of the ConfigNode. - // ==================================================== - node := ConfigNode{} - node = cg[i] - return &node - } - minWeight = maxWeight - } - return nil + if len(cg) < 2 { + return &cg[0] + } + var total int + for i := 0; i < len(cg); i++ { + total += cg[i].Weight * 100 + } + // If total is 0 means all the nodes have no weight attribute configured. + // It then defaults each node's weight attribute to 1. + if total == 0 { + for i := 0; i < len(cg); i++ { + cg[i].Weight = 1 + total += cg[i].Weight * 100 + } + } + // Exclude the right border value. + var ( + minWeight = 0 + maxWeight = 0 + random = grand.N(0, total-1) + ) + for i := 0; i < len(cg); i++ { + maxWeight = minWeight + cg[i].Weight*100 + if random >= minWeight && random < maxWeight { + // ==================================================== + // Return a COPY of the ConfigNode. + // ==================================================== + node := ConfigNode{} + node = cg[i] + return &node + } + minWeight = maxWeight + } + return nil } // getSqlDb retrieves and returns an underlying database connection object. // The parameter `master` specifies whether retrieves master node connection if // master-slave nodes are configured. func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error) { - var ( - node *ConfigNode - ctx = c.db.GetCtx() - ) - if c.group != "" { - // Load balance. - configs.RLock() - defer configs.RUnlock() - // Value COPY for node. - // The returned node is a clone of configuration node, which is safe for later modification. - node, err = getConfigNodeByGroup(c.group, master) - if err != nil { - return nil, err - } - } else { - // Value COPY for node. - n := *c.db.GetConfig() - node = &n - } - if node.Charset == "" { - node.Charset = defaultCharset - } - // Changes the schema. - nodeSchema := gutil.GetOrDefaultStr(c.schema, schema...) - if nodeSchema != "" { - node.Name = nodeSchema - } - // Update the configuration object in internal data. - if err = c.setConfigNodeToCtx(ctx, node); err != nil { - return - } - - // Cache the underlying connection pool object by node. - var ( - instanceCacheFunc = func() interface{} { - if sqlDb, err = c.db.Open(node); err != nil { - return nil - } - if sqlDb == nil { - return nil - } - if c.dynamicConfig.MaxIdleConnCount > 0 { - sqlDb.SetMaxIdleConns(c.dynamicConfig.MaxIdleConnCount) - } else { - sqlDb.SetMaxIdleConns(defaultMaxIdleConnCount) - } - if c.dynamicConfig.MaxOpenConnCount > 0 { - sqlDb.SetMaxOpenConns(c.dynamicConfig.MaxOpenConnCount) - } else { - sqlDb.SetMaxOpenConns(defaultMaxOpenConnCount) - } - if c.dynamicConfig.MaxConnLifeTime > 0 { - sqlDb.SetConnMaxLifetime(c.dynamicConfig.MaxConnLifeTime) - } else { - sqlDb.SetConnMaxLifetime(defaultMaxConnLifeTime) - } - return sqlDb - } - // it here uses NODE VALUE not pointer as the cache key, in case of oracle ORA-12516 error. - instanceValue = c.links.GetOrSetFuncLock(*node, instanceCacheFunc) - ) - if instanceValue != nil && sqlDb == nil { - // It reads from instance map. - sqlDb = instanceValue.(*sql.DB) - } - if node.Debug { - c.db.SetDebug(node.Debug) - } - if node.DryRun { - c.db.SetDryRun(node.DryRun) - } - return + var ( + node *ConfigNode + ctx = c.db.GetCtx() + ) + if c.group != "" { + // Load balance. + configs.RLock() + defer configs.RUnlock() + // Value COPY for node. + // The returned node is a clone of configuration node, which is safe for later modification. + node, err = getConfigNodeByGroup(c.group, master) + if err != nil { + return nil, err + } + } else { + // Value COPY for node. + n := *c.db.GetConfig() + node = &n + } + if node.Charset == "" { + node.Charset = defaultCharset + } + // Changes the schema. + nodeSchema := gutil.GetOrDefaultStr(c.schema, schema...) + if nodeSchema != "" { + node.Name = nodeSchema + } + // Update the configuration object in internal data. + if err = c.setConfigNodeToCtx(ctx, node); err != nil { + return + } + + // Cache the underlying connection pool object by node. + var ( + instanceCacheFunc = func() interface{} { + if sqlDb, err = c.db.Open(node); err != nil { + return nil + } + if sqlDb == nil { + return nil + } + if c.dynamicConfig.MaxIdleConnCount > 0 { + sqlDb.SetMaxIdleConns(c.dynamicConfig.MaxIdleConnCount) + } else { + sqlDb.SetMaxIdleConns(defaultMaxIdleConnCount) + } + if c.dynamicConfig.MaxOpenConnCount > 0 { + sqlDb.SetMaxOpenConns(c.dynamicConfig.MaxOpenConnCount) + } else { + sqlDb.SetMaxOpenConns(defaultMaxOpenConnCount) + } + if c.dynamicConfig.MaxConnLifeTime > 0 { + sqlDb.SetConnMaxLifetime(c.dynamicConfig.MaxConnLifeTime) + } else { + sqlDb.SetConnMaxLifetime(defaultMaxConnLifeTime) + } + return sqlDb + } + // it here uses NODE VALUE not pointer as the cache key, in case of oracle ORA-12516 error. + instanceValue = c.links.GetOrSetFuncLock(*node, instanceCacheFunc) + ) + if instanceValue != nil && sqlDb == nil { + // It reads from instance map. + sqlDb = instanceValue.(*sql.DB) + } + if node.Debug { + c.db.SetDebug(node.Debug) + } + if node.DryRun { + c.db.SetDryRun(node.DryRun) + } + return } diff --git a/database/gdb/gdb_core.go b/database/gdb/gdb_core.go index f1cd226eaa6..12ff302fb6f 100644 --- a/database/gdb/gdb_core.go +++ b/database/gdb/gdb_core.go @@ -8,29 +8,29 @@ package gdb import ( - "context" - "database/sql" - "fmt" - "reflect" - "strings" - - "github.com/gogf/gf/v2/container/gmap" - "github.com/gogf/gf/v2/container/gset" - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/intlog" - "github.com/gogf/gf/v2/internal/reflection" - "github.com/gogf/gf/v2/internal/utils" - "github.com/gogf/gf/v2/os/gcache" - "github.com/gogf/gf/v2/text/gregex" - "github.com/gogf/gf/v2/text/gstr" - "github.com/gogf/gf/v2/util/gconv" - "github.com/gogf/gf/v2/util/gutil" + "context" + "database/sql" + "fmt" + "reflect" + "strings" + + "github.com/gogf/gf/v2/container/gmap" + "github.com/gogf/gf/v2/container/gset" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/intlog" + "github.com/gogf/gf/v2/internal/reflection" + "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/os/gcache" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/gutil" ) // GetCore returns the underlying *Core object. func (c *Core) GetCore() *Core { - return c + return c } // Ctx is a chaining function, which creates and returns a new DB that is a shallow copy @@ -38,67 +38,67 @@ func (c *Core) GetCore() *Core { // Note that this returned DB object can be used only once, so do not assign it to // a global or package variable for long using. func (c *Core) Ctx(ctx context.Context) DB { - if ctx == nil { - return c.db - } - // It makes a shallow copy of current db and changes its context for next chaining operation. - var ( - err error - newCore = &Core{} - configNode = c.db.GetConfig() - ) - *newCore = *c - // It creates a new DB object(NOT NEW CONNECTION), which is commonly a wrapper for object `Core`. - newCore.db, err = driverMap[configNode.Type].New(newCore, configNode) - if err != nil { - // It is really a serious error here. - // Do not let it continue. - panic(err) - } - newCore.ctx = WithDB(ctx, newCore.db) - newCore.ctx = c.injectInternalCtxData(newCore.ctx) - return newCore.db + if ctx == nil { + return c.db + } + // It makes a shallow copy of current db and changes its context for next chaining operation. + var ( + err error + newCore = &Core{} + configNode = c.db.GetConfig() + ) + *newCore = *c + // It creates a new DB object(NOT NEW CONNECTION), which is commonly a wrapper for object `Core`. + newCore.db, err = driverMap[configNode.Type].New(newCore, configNode) + if err != nil { + // It is really a serious error here. + // Do not let it continue. + panic(err) + } + newCore.ctx = WithDB(ctx, newCore.db) + newCore.ctx = c.injectInternalCtxData(newCore.ctx) + return newCore.db } // GetCtx returns the context for current DB. // It returns `context.Background()` is there's no context previously set. func (c *Core) GetCtx() context.Context { - ctx := c.ctx - if ctx == nil { - ctx = context.TODO() - } - return c.injectInternalCtxData(ctx) + ctx := c.ctx + if ctx == nil { + ctx = context.TODO() + } + return c.injectInternalCtxData(ctx) } // GetCtxTimeout returns the context and cancel function for specified timeout type. func (c *Core) GetCtxTimeout(ctx context.Context, timeoutType ctxTimeoutType) (context.Context, context.CancelFunc) { - if ctx == nil { - ctx = c.db.GetCtx() - } else { - ctx = context.WithValue(ctx, "WrappedByGetCtxTimeout", nil) - } - var config = c.db.GetConfig() - switch timeoutType { - case ctxTimeoutTypeExec: - if c.db.GetConfig().ExecTimeout > 0 { - return context.WithTimeout(ctx, config.ExecTimeout) - } - case ctxTimeoutTypeQuery: - if c.db.GetConfig().QueryTimeout > 0 { - return context.WithTimeout(ctx, config.QueryTimeout) - } - case ctxTimeoutTypePrepare: - if c.db.GetConfig().PrepareTimeout > 0 { - return context.WithTimeout(ctx, config.PrepareTimeout) - } - case ctxTimeoutTypeTrans: - if c.db.GetConfig().TranTimeout > 0 { - return context.WithTimeout(ctx, config.TranTimeout) - } - default: - panic(gerror.NewCodef(gcode.CodeInvalidParameter, "invalid context timeout type: %d", timeoutType)) - } - return ctx, func() {} + if ctx == nil { + ctx = c.db.GetCtx() + } else { + ctx = context.WithValue(ctx, "WrappedByGetCtxTimeout", nil) + } + var config = c.db.GetConfig() + switch timeoutType { + case ctxTimeoutTypeExec: + if c.db.GetConfig().ExecTimeout > 0 { + return context.WithTimeout(ctx, config.ExecTimeout) + } + case ctxTimeoutTypeQuery: + if c.db.GetConfig().QueryTimeout > 0 { + return context.WithTimeout(ctx, config.QueryTimeout) + } + case ctxTimeoutTypePrepare: + if c.db.GetConfig().PrepareTimeout > 0 { + return context.WithTimeout(ctx, config.PrepareTimeout) + } + case ctxTimeoutTypeTrans: + if c.db.GetConfig().TranTimeout > 0 { + return context.WithTimeout(ctx, config.TranTimeout) + } + default: + panic(gerror.NewCodef(gcode.CodeInvalidParameter, "invalid context timeout type: %d", timeoutType)) + } + return ctx, func() {} } // Close closes the database and prevents new queries from starting. @@ -108,97 +108,97 @@ func (c *Core) GetCtxTimeout(ctx context.Context, timeoutType ctxTimeoutType) (c // It is rare to Close a DB, as the DB handle is meant to be // long-lived and shared between many goroutines. func (c *Core) Close(ctx context.Context) (err error) { - if err = c.cache.Close(ctx); err != nil { - return err - } - c.links.LockFunc(func(m map[any]any) { - for k, v := range m { - if db, ok := v.(*sql.DB); ok { - err = db.Close() - if err != nil { - err = gerror.WrapCode(gcode.CodeDbOperationError, err, `db.Close failed`) - } - intlog.Printf(ctx, `close link: %s, err: %v`, k, err) - if err != nil { - return - } - delete(m, k) - } - } - }) - return + if err = c.cache.Close(ctx); err != nil { + return err + } + c.links.LockFunc(func(m map[any]any) { + for k, v := range m { + if db, ok := v.(*sql.DB); ok { + err = db.Close() + if err != nil { + err = gerror.WrapCode(gcode.CodeDbOperationError, err, `db.Close failed`) + } + intlog.Printf(ctx, `close link: %s, err: %v`, k, err) + if err != nil { + return + } + delete(m, k) + } + } + }) + return } // Master creates and returns a connection from master node if master-slave configured. // It returns the default connection if master-slave not configured. func (c *Core) Master(schema ...string) (*sql.DB, error) { - var ( - usedSchema = gutil.GetOrDefaultStr(c.schema, schema...) - charL, charR = c.db.GetChars() - ) - return c.getSqlDb(true, gstr.Trim(usedSchema, charL+charR)) + var ( + usedSchema = gutil.GetOrDefaultStr(c.schema, schema...) + charL, charR = c.db.GetChars() + ) + return c.getSqlDb(true, gstr.Trim(usedSchema, charL+charR)) } // Slave creates and returns a connection from slave node if master-slave configured. // It returns the default connection if master-slave not configured. func (c *Core) Slave(schema ...string) (*sql.DB, error) { - var ( - usedSchema = gutil.GetOrDefaultStr(c.schema, schema...) - charL, charR = c.db.GetChars() - ) - return c.getSqlDb(false, gstr.Trim(usedSchema, charL+charR)) + var ( + usedSchema = gutil.GetOrDefaultStr(c.schema, schema...) + charL, charR = c.db.GetChars() + ) + return c.getSqlDb(false, gstr.Trim(usedSchema, charL+charR)) } // GetAll queries and returns data records from database. func (c *Core) GetAll(ctx context.Context, sql string, args ...interface{}) (Result, error) { - return c.db.DoSelect(ctx, nil, sql, args...) + return c.db.DoSelect(ctx, nil, sql, args...) } // DoSelect queries and returns data records from database. func (c *Core) DoSelect(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) { - return c.db.DoQuery(ctx, link, sql, args...) + return c.db.DoQuery(ctx, link, sql, args...) } // GetOne queries and returns one record from database. func (c *Core) GetOne(ctx context.Context, sql string, args ...interface{}) (Record, error) { - list, err := c.db.GetAll(ctx, sql, args...) - if err != nil { - return nil, err - } - if len(list) > 0 { - return list[0], nil - } - return nil, nil + list, err := c.db.GetAll(ctx, sql, args...) + if err != nil { + return nil, err + } + if len(list) > 0 { + return list[0], nil + } + return nil, nil } // GetArray queries and returns data values as slice from database. // Note that if there are multiple columns in the result, it returns just one column values randomly. func (c *Core) GetArray(ctx context.Context, sql string, args ...interface{}) ([]Value, error) { - all, err := c.db.DoSelect(ctx, nil, sql, args...) - if err != nil { - return nil, err - } - return all.Array(), nil + all, err := c.db.DoSelect(ctx, nil, sql, args...) + if err != nil { + return nil, err + } + return all.Array(), nil } // doGetStruct queries one record from database and converts it to given struct. // The parameter `pointer` should be a pointer to struct. func (c *Core) doGetStruct(ctx context.Context, pointer interface{}, sql string, args ...interface{}) error { - one, err := c.db.GetOne(ctx, sql, args...) - if err != nil { - return err - } - return one.Struct(pointer) + one, err := c.db.GetOne(ctx, sql, args...) + if err != nil { + return err + } + return one.Struct(pointer) } // doGetStructs queries records from database and converts them to given struct. // The parameter `pointer` should be type of struct slice: []struct/[]*struct. func (c *Core) doGetStructs(ctx context.Context, pointer interface{}, sql string, args ...interface{}) error { - all, err := c.db.GetAll(ctx, sql, args...) - if err != nil { - return err - } - return all.Structs(pointer) + all, err := c.db.GetAll(ctx, sql, args...) + if err != nil { + return err + } + return all.Structs(pointer) } // GetScan queries one or more records from database and converts them to given struct or @@ -208,115 +208,115 @@ func (c *Core) doGetStructs(ctx context.Context, pointer interface{}, sql string // the conversion. If parameter `pointer` is type of slice, it calls GetStructs internally // for conversion. func (c *Core) GetScan(ctx context.Context, pointer interface{}, sql string, args ...interface{}) error { - reflectInfo := reflection.OriginTypeAndKind(pointer) - if reflectInfo.InputKind != reflect.Ptr { - return gerror.NewCodef( - gcode.CodeInvalidParameter, - "params should be type of pointer, but got: %v", - reflectInfo.InputKind, - ) - } - switch reflectInfo.OriginKind { - case reflect.Array, reflect.Slice: - return c.db.GetCore().doGetStructs(ctx, pointer, sql, args...) - - case reflect.Struct: - return c.db.GetCore().doGetStruct(ctx, pointer, sql, args...) - } - return gerror.NewCodef( - gcode.CodeInvalidParameter, - `in valid parameter type "%v", of which element type should be type of struct/slice`, - reflectInfo.InputType, - ) + reflectInfo := reflection.OriginTypeAndKind(pointer) + if reflectInfo.InputKind != reflect.Ptr { + return gerror.NewCodef( + gcode.CodeInvalidParameter, + "params should be type of pointer, but got: %v", + reflectInfo.InputKind, + ) + } + switch reflectInfo.OriginKind { + case reflect.Array, reflect.Slice: + return c.db.GetCore().doGetStructs(ctx, pointer, sql, args...) + + case reflect.Struct: + return c.db.GetCore().doGetStruct(ctx, pointer, sql, args...) + } + return gerror.NewCodef( + gcode.CodeInvalidParameter, + `in valid parameter type "%v", of which element type should be type of struct/slice`, + reflectInfo.InputType, + ) } // GetValue queries and returns the field value from database. // The sql should query only one field from database, or else it returns only one // field of the result. func (c *Core) GetValue(ctx context.Context, sql string, args ...interface{}) (Value, error) { - one, err := c.db.GetOne(ctx, sql, args...) - if err != nil { - return nil, err - } - for _, v := range one { - return v, nil - } - return nil, nil + one, err := c.db.GetOne(ctx, sql, args...) + if err != nil { + return nil, err + } + for _, v := range one { + return v, nil + } + return nil, nil } // GetCount queries and returns the count from database. func (c *Core) GetCount(ctx context.Context, sql string, args ...interface{}) (int, error) { - // If the query fields do not contain function "COUNT", - // it replaces the sql string and adds the "COUNT" function to the fields. - if !gregex.IsMatchString(`(?i)SELECT\s+COUNT\(.+\)\s+FROM`, sql) { - sql, _ = gregex.ReplaceString(`(?i)(SELECT)\s+(.+)\s+(FROM)`, `$1 COUNT($2) $3`, sql) - } - value, err := c.db.GetValue(ctx, sql, args...) - if err != nil { - return 0, err - } - return value.Int(), nil + // If the query fields do not contain function "COUNT", + // it replaces the sql string and adds the "COUNT" function to the fields. + if !gregex.IsMatchString(`(?i)SELECT\s+COUNT\(.+\)\s+FROM`, sql) { + sql, _ = gregex.ReplaceString(`(?i)(SELECT)\s+(.+)\s+(FROM)`, `$1 COUNT($2) $3`, sql) + } + value, err := c.db.GetValue(ctx, sql, args...) + if err != nil { + return 0, err + } + return value.Int(), nil } // Union does "(SELECT xxx FROM xxx) UNION (SELECT xxx FROM xxx) ..." statement. func (c *Core) Union(unions ...*Model) *Model { - var ctx = c.db.GetCtx() - return c.doUnion(ctx, unionTypeNormal, unions...) + var ctx = c.db.GetCtx() + return c.doUnion(ctx, unionTypeNormal, unions...) } // UnionAll does "(SELECT xxx FROM xxx) UNION ALL (SELECT xxx FROM xxx) ..." statement. func (c *Core) UnionAll(unions ...*Model) *Model { - var ctx = c.db.GetCtx() - return c.doUnion(ctx, unionTypeAll, unions...) + var ctx = c.db.GetCtx() + return c.doUnion(ctx, unionTypeAll, unions...) } func (c *Core) doUnion(ctx context.Context, unionType int, unions ...*Model) *Model { - var ( - unionTypeStr string - composedSqlStr string - composedArgs = make([]interface{}, 0) - ) - if unionType == unionTypeAll { - unionTypeStr = "UNION ALL" - } else { - unionTypeStr = "UNION" - } - for _, v := range unions { - sqlWithHolder, holderArgs := v.getFormattedSqlAndArgs(ctx, SelectTypeDefault, false) - if composedSqlStr == "" { - composedSqlStr += fmt.Sprintf(`(%s)`, sqlWithHolder) - } else { - composedSqlStr += fmt.Sprintf(` %s (%s)`, unionTypeStr, sqlWithHolder) - } - composedArgs = append(composedArgs, holderArgs...) - } - return c.db.Raw(composedSqlStr, composedArgs...) + var ( + unionTypeStr string + composedSqlStr string + composedArgs = make([]interface{}, 0) + ) + if unionType == unionTypeAll { + unionTypeStr = "UNION ALL" + } else { + unionTypeStr = "UNION" + } + for _, v := range unions { + sqlWithHolder, holderArgs := v.getFormattedSqlAndArgs(ctx, SelectTypeDefault, false) + if composedSqlStr == "" { + composedSqlStr += fmt.Sprintf(`(%s)`, sqlWithHolder) + } else { + composedSqlStr += fmt.Sprintf(` %s (%s)`, unionTypeStr, sqlWithHolder) + } + composedArgs = append(composedArgs, holderArgs...) + } + return c.db.Raw(composedSqlStr, composedArgs...) } // PingMaster pings the master node to check authentication or keeps the connection alive. func (c *Core) PingMaster() error { - var ctx = c.db.GetCtx() - if master, err := c.db.Master(); err != nil { - return err - } else { - if err = master.PingContext(ctx); err != nil { - err = gerror.WrapCode(gcode.CodeDbOperationError, err, `master.Ping failed`) - } - return err - } + var ctx = c.db.GetCtx() + if master, err := c.db.Master(); err != nil { + return err + } else { + if err = master.PingContext(ctx); err != nil { + err = gerror.WrapCode(gcode.CodeDbOperationError, err, `master.Ping failed`) + } + return err + } } // PingSlave pings the slave node to check authentication or keeps the connection alive. func (c *Core) PingSlave() error { - var ctx = c.db.GetCtx() - if slave, err := c.db.Slave(); err != nil { - return err - } else { - if err = slave.PingContext(ctx); err != nil { - err = gerror.WrapCode(gcode.CodeDbOperationError, err, `slave.Ping failed`) - } - return err - } + var ctx = c.db.GetCtx() + if slave, err := c.db.Slave(); err != nil { + return err + } else { + if err = slave.PingContext(ctx); err != nil { + err = gerror.WrapCode(gcode.CodeDbOperationError, err, `slave.Ping failed`) + } + return err + } } // Insert does "INSERT INTO ..." statement for the table. @@ -329,10 +329,10 @@ func (c *Core) PingSlave() error { // // The parameter `batch` specifies the batch operation count when given data is slice. func (c *Core) Insert(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) { - if len(batch) > 0 { - return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Insert() - } - return c.Model(table).Ctx(ctx).Data(data).Insert() + if len(batch) > 0 { + return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Insert() + } + return c.Model(table).Ctx(ctx).Data(data).Insert() } // InsertIgnore does "INSERT IGNORE INTO ..." statement for the table. @@ -345,18 +345,18 @@ func (c *Core) Insert(ctx context.Context, table string, data interface{}, batch // // The parameter `batch` specifies the batch operation count when given data is slice. func (c *Core) InsertIgnore(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) { - if len(batch) > 0 { - return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).InsertIgnore() - } - return c.Model(table).Ctx(ctx).Data(data).InsertIgnore() + if len(batch) > 0 { + return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).InsertIgnore() + } + return c.Model(table).Ctx(ctx).Data(data).InsertIgnore() } // InsertAndGetId performs action Insert and returns the last insert id that automatically generated. func (c *Core) InsertAndGetId(ctx context.Context, table string, data interface{}, batch ...int) (int64, error) { - if len(batch) > 0 { - return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).InsertAndGetId() - } - return c.Model(table).Ctx(ctx).Data(data).InsertAndGetId() + if len(batch) > 0 { + return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).InsertAndGetId() + } + return c.Model(table).Ctx(ctx).Data(data).InsertAndGetId() } // Replace does "REPLACE INTO ..." statement for the table. @@ -372,10 +372,10 @@ func (c *Core) InsertAndGetId(ctx context.Context, table string, data interface{ // If given data is type of slice, it then does batch replacing, and the optional parameter // `batch` specifies the batch operation count. func (c *Core) Replace(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) { - if len(batch) > 0 { - return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Replace() - } - return c.Model(table).Ctx(ctx).Data(data).Replace() + if len(batch) > 0 { + return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Replace() + } + return c.Model(table).Ctx(ctx).Data(data).Replace() } // Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the table. @@ -390,33 +390,33 @@ func (c *Core) Replace(ctx context.Context, table string, data interface{}, batc // If given data is type of slice, it then does batch saving, and the optional parameter // `batch` specifies the batch operation count. func (c *Core) Save(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) { - if len(batch) > 0 { - return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Save() - } - return c.Model(table).Ctx(ctx).Data(data).Save() + if len(batch) > 0 { + return c.Model(table).Ctx(ctx).Data(data).Batch(batch[0]).Save() + } + return c.Model(table).Ctx(ctx).Data(data).Save() } func (c *Core) fieldsToSequence(ctx context.Context, table string, fields []string) ([]string, error) { - var ( - fieldSet = gset.NewStrSetFrom(fields) - fieldsResultInSequence = make([]string, 0) - tableFields, err = c.db.TableFields(ctx, table) - ) - if err != nil { - return nil, err - } - // Sort the fields in order. - var fieldsOfTableInSequence = make([]string, len(tableFields)) - for _, field := range tableFields { - fieldsOfTableInSequence[field.Index] = field.Name - } - // Sort the input fields. - for _, fieldName := range fieldsOfTableInSequence { - if fieldSet.Contains(fieldName) { - fieldsResultInSequence = append(fieldsResultInSequence, fieldName) - } - } - return fieldsResultInSequence, nil + var ( + fieldSet = gset.NewStrSetFrom(fields) + fieldsResultInSequence = make([]string, 0) + tableFields, err = c.db.TableFields(ctx, table) + ) + if err != nil { + return nil, err + } + // Sort the fields in order. + var fieldsOfTableInSequence = make([]string, len(tableFields)) + for _, field := range tableFields { + fieldsOfTableInSequence[field.Index] = field.Name + } + // Sort the input fields. + for _, fieldName := range fieldsOfTableInSequence { + if fieldSet.Contains(fieldName) { + fieldsResultInSequence = append(fieldsResultInSequence, fieldName) + } + } + return fieldsResultInSequence, nil } // DoInsert inserts or updates data for given table. @@ -432,117 +432,117 @@ func (c *Core) fieldsToSequence(ctx context.Context, table string, fields []stri // InsertOptionSave: if there's unique/primary key in the data, it updates it or else inserts a new one; // InsertOptionIgnore: if there's unique/primary key in the data, it ignores the inserting; func (c *Core) DoInsert(ctx context.Context, link Link, table string, list List, option DoInsertOption) (result sql.Result, err error) { - var ( - keys []string // Field names. - values []string // Value holder string array, like: (?,?,?) - params []interface{} // Values that will be committed to underlying database driver. - onDuplicateStr string // onDuplicateStr is used in "ON DUPLICATE KEY UPDATE" statement. - ) - // ============================================================================================ - // Group the list by fields. Different fields to different list. - // It here uses ListMap to keep sequence for data inserting. - // ============================================================================================ - var keyListMap = gmap.NewListMap() - for _, item := range list { - var ( - tmpKeys = make([]string, 0) - tmpKeysInSequenceStr string - ) - for k := range item { - tmpKeys = append(tmpKeys, k) - } - keys, err = c.fieldsToSequence(ctx, table, tmpKeys) - if err != nil { - return nil, err - } - tmpKeysInSequenceStr = gstr.Join(keys, ",") - if !keyListMap.Contains(tmpKeysInSequenceStr) { - keyListMap.Set(tmpKeysInSequenceStr, make(List, 0)) - } - tmpKeysInSequenceList := keyListMap.Get(tmpKeysInSequenceStr).(List) - tmpKeysInSequenceList = append(tmpKeysInSequenceList, item) - keyListMap.Set(tmpKeysInSequenceStr, tmpKeysInSequenceList) - } - if keyListMap.Size() > 1 { - var ( - tmpResult sql.Result - sqlResult SqlResult - rowsAffected int64 - ) - keyListMap.Iterator(func(key, value interface{}) bool { - tmpResult, err = c.DoInsert(ctx, link, table, value.(List), option) - if err != nil { - return false - } - rowsAffected, err = tmpResult.RowsAffected() - if err != nil { - return false - } - sqlResult.Result = tmpResult - sqlResult.Affected += rowsAffected - return true - }) - return &sqlResult, err - } - - // Prepare the batch result pointer. - var ( - charL, charR = c.db.GetChars() - batchResult = new(SqlResult) - keysStr = charL + strings.Join(keys, charR+","+charL) + charR - operation = GetInsertOperationByOption(option.InsertOption) - ) - // Upsert clause only takes effect on Save operation. - if option.InsertOption == InsertOptionSave { - onDuplicateStr, err = c.db.FormatUpsert(keys, list, option) - if err != nil { - return nil, err - } - } - var ( - listLength = len(list) - valueHolders = make([]string, 0) - ) - for i := 0; i < listLength; i++ { - values = values[:0] - // Note that the map type is unordered, - // so it should use slice+key to retrieve the value. - for _, k := range keys { - if s, ok := list[i][k].(Raw); ok { - values = append(values, gconv.String(s)) - } else { - values = append(values, "?") - params = append(params, list[i][k]) - } - } - valueHolders = append(valueHolders, "("+gstr.Join(values, ",")+")") - // Batch package checks: It meets the batch number, or it is the last element. - if len(valueHolders) == option.BatchCount || (i == listLength-1 && len(valueHolders) > 0) { - var ( - stdSqlResult sql.Result - affectedRows int64 - ) - stdSqlResult, err = c.db.DoExec(ctx, link, fmt.Sprintf( - "%s INTO %s(%s) VALUES%s %s", - operation, c.QuotePrefixTableName(table), keysStr, - gstr.Join(valueHolders, ","), - onDuplicateStr, - ), params...) - if err != nil { - return stdSqlResult, err - } - if affectedRows, err = stdSqlResult.RowsAffected(); err != nil { - err = gerror.WrapCode(gcode.CodeDbOperationError, err, `sql.Result.RowsAffected failed`) - return stdSqlResult, err - } else { - batchResult.Result = stdSqlResult - batchResult.Affected += affectedRows - } - params = params[:0] - valueHolders = valueHolders[:0] - } - } - return batchResult, nil + var ( + keys []string // Field names. + values []string // Value holder string array, like: (?,?,?) + params []interface{} // Values that will be committed to underlying database driver. + onDuplicateStr string // onDuplicateStr is used in "ON DUPLICATE KEY UPDATE" statement. + ) + // ============================================================================================ + // Group the list by fields. Different fields to different list. + // It here uses ListMap to keep sequence for data inserting. + // ============================================================================================ + var keyListMap = gmap.NewListMap() + for _, item := range list { + var ( + tmpKeys = make([]string, 0) + tmpKeysInSequenceStr string + ) + for k := range item { + tmpKeys = append(tmpKeys, k) + } + keys, err = c.fieldsToSequence(ctx, table, tmpKeys) + if err != nil { + return nil, err + } + tmpKeysInSequenceStr = gstr.Join(keys, ",") + if !keyListMap.Contains(tmpKeysInSequenceStr) { + keyListMap.Set(tmpKeysInSequenceStr, make(List, 0)) + } + tmpKeysInSequenceList := keyListMap.Get(tmpKeysInSequenceStr).(List) + tmpKeysInSequenceList = append(tmpKeysInSequenceList, item) + keyListMap.Set(tmpKeysInSequenceStr, tmpKeysInSequenceList) + } + if keyListMap.Size() > 1 { + var ( + tmpResult sql.Result + sqlResult SqlResult + rowsAffected int64 + ) + keyListMap.Iterator(func(key, value interface{}) bool { + tmpResult, err = c.DoInsert(ctx, link, table, value.(List), option) + if err != nil { + return false + } + rowsAffected, err = tmpResult.RowsAffected() + if err != nil { + return false + } + sqlResult.Result = tmpResult + sqlResult.Affected += rowsAffected + return true + }) + return &sqlResult, err + } + + // Prepare the batch result pointer. + var ( + charL, charR = c.db.GetChars() + batchResult = new(SqlResult) + keysStr = charL + strings.Join(keys, charR+","+charL) + charR + operation = GetInsertOperationByOption(option.InsertOption) + ) + // Upsert clause only takes effect on Save operation. + if option.InsertOption == InsertOptionSave { + onDuplicateStr, err = c.db.FormatUpsert(keys, list, option) + if err != nil { + return nil, err + } + } + var ( + listLength = len(list) + valueHolders = make([]string, 0) + ) + for i := 0; i < listLength; i++ { + values = values[:0] + // Note that the map type is unordered, + // so it should use slice+key to retrieve the value. + for _, k := range keys { + if s, ok := list[i][k].(Raw); ok { + values = append(values, gconv.String(s)) + } else { + values = append(values, "?") + params = append(params, list[i][k]) + } + } + valueHolders = append(valueHolders, "("+gstr.Join(values, ",")+")") + // Batch package checks: It meets the batch number, or it is the last element. + if len(valueHolders) == option.BatchCount || (i == listLength-1 && len(valueHolders) > 0) { + var ( + stdSqlResult sql.Result + affectedRows int64 + ) + stdSqlResult, err = c.db.DoExec(ctx, link, fmt.Sprintf( + "%s INTO %s(%s) VALUES%s %s", + operation, c.QuotePrefixTableName(table), keysStr, + gstr.Join(valueHolders, ","), + onDuplicateStr, + ), params...) + if err != nil { + return stdSqlResult, err + } + if affectedRows, err = stdSqlResult.RowsAffected(); err != nil { + err = gerror.WrapCode(gcode.CodeDbOperationError, err, `sql.Result.RowsAffected failed`) + return stdSqlResult, err + } else { + batchResult.Result = stdSqlResult + batchResult.Affected += affectedRows + } + params = params[:0] + valueHolders = valueHolders[:0] + } + } + return batchResult, nil } // Update does "UPDATE ... " statement for the table. @@ -560,104 +560,104 @@ func (c *Core) DoInsert(ctx context.Context, link Link, table string, list List, // "age IN(?,?)", 18, 50 // User{ Id : 1, UserName : "john"}. func (c *Core) Update(ctx context.Context, table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) { - return c.Model(table).Ctx(ctx).Data(data).Where(condition, args...).Update() + return c.Model(table).Ctx(ctx).Data(data).Where(condition, args...).Update() } // DoUpdate does "UPDATE ... " statement for the table. // This function is usually used for custom interface definition, you do not need to call it manually. func (c *Core) DoUpdate(ctx context.Context, link Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) { - table = c.QuotePrefixTableName(table) - var ( - rv = reflect.ValueOf(data) - kind = rv.Kind() - ) - if kind == reflect.Ptr { - rv = rv.Elem() - kind = rv.Kind() - } - var ( - params []interface{} - updates string - ) - switch kind { - case reflect.Map, reflect.Struct: - var ( - fields []string - dataMap map[string]interface{} - counterHandler = func(column string, counter Counter) { - if counter.Value != 0 { - column = c.QuoteWord(column) - var ( - columnRef = c.QuoteWord(counter.Field) - columnVal = counter.Value - operator = "+" - ) - if columnVal < 0 { - operator = "-" - columnVal = -columnVal - } - fields = append(fields, fmt.Sprintf("%s=%s%s?", column, columnRef, operator)) - params = append(params, columnVal) - } - } - ) - dataMap, err = c.ConvertDataForRecord(ctx, data, table) - if err != nil { - return nil, err - } - // Sort the data keys in sequence of table fields. - var ( - dataKeys = make([]string, 0) - keysInSequence = make([]string, 0) - ) - for k := range dataMap { - dataKeys = append(dataKeys, k) - } - keysInSequence, err = c.fieldsToSequence(ctx, table, dataKeys) - if err != nil { - return nil, err - } - for _, k := range keysInSequence { - v := dataMap[k] - switch value := v.(type) { - case *Counter: - counterHandler(k, *value) - - case Counter: - counterHandler(k, value) - - default: - if s, ok := v.(Raw); ok { - fields = append(fields, c.QuoteWord(k)+"="+gconv.String(s)) - } else { - fields = append(fields, c.QuoteWord(k)+"=?") - params = append(params, v) - } - } - } - updates = strings.Join(fields, ",") - - default: - updates = gconv.String(data) - } - if len(updates) == 0 { - return nil, gerror.NewCode(gcode.CodeMissingParameter, "data cannot be empty") - } - if len(params) > 0 { - args = append(params, args...) - } - // If no link passed, it then uses the master link. - if link == nil { - if link, err = c.MasterLink(); err != nil { - return nil, err - } - } - return c.db.DoExec(ctx, link, fmt.Sprintf( - "UPDATE %s SET %s%s", - table, updates, condition, - ), - args..., - ) + table = c.QuotePrefixTableName(table) + var ( + rv = reflect.ValueOf(data) + kind = rv.Kind() + ) + if kind == reflect.Ptr { + rv = rv.Elem() + kind = rv.Kind() + } + var ( + params []interface{} + updates string + ) + switch kind { + case reflect.Map, reflect.Struct: + var ( + fields []string + dataMap map[string]interface{} + counterHandler = func(column string, counter Counter) { + if counter.Value != 0 { + column = c.QuoteWord(column) + var ( + columnRef = c.QuoteWord(counter.Field) + columnVal = counter.Value + operator = "+" + ) + if columnVal < 0 { + operator = "-" + columnVal = -columnVal + } + fields = append(fields, fmt.Sprintf("%s=%s%s?", column, columnRef, operator)) + params = append(params, columnVal) + } + } + ) + dataMap, err = c.ConvertDataForRecord(ctx, data, table) + if err != nil { + return nil, err + } + // Sort the data keys in sequence of table fields. + var ( + dataKeys = make([]string, 0) + keysInSequence = make([]string, 0) + ) + for k := range dataMap { + dataKeys = append(dataKeys, k) + } + keysInSequence, err = c.fieldsToSequence(ctx, table, dataKeys) + if err != nil { + return nil, err + } + for _, k := range keysInSequence { + v := dataMap[k] + switch value := v.(type) { + case *Counter: + counterHandler(k, *value) + + case Counter: + counterHandler(k, value) + + default: + if s, ok := v.(Raw); ok { + fields = append(fields, c.QuoteWord(k)+"="+gconv.String(s)) + } else { + fields = append(fields, c.QuoteWord(k)+"=?") + params = append(params, v) + } + } + } + updates = strings.Join(fields, ",") + + default: + updates = gconv.String(data) + } + if len(updates) == 0 { + return nil, gerror.NewCode(gcode.CodeMissingParameter, "data cannot be empty") + } + if len(params) > 0 { + args = append(params, args...) + } + // If no link passed, it then uses the master link. + if link == nil { + if link, err = c.MasterLink(); err != nil { + return nil, err + } + } + return c.db.DoExec(ctx, link, fmt.Sprintf( + "UPDATE %s SET %s%s", + table, updates, condition, + ), + args..., + ) } // Delete does "DELETE FROM ... " statement for the table. @@ -672,28 +672,28 @@ func (c *Core) DoUpdate(ctx context.Context, link Link, table string, data inter // "age IN(?,?)", 18, 50 // User{ Id : 1, UserName : "john"}. func (c *Core) Delete(ctx context.Context, table string, condition interface{}, args ...interface{}) (result sql.Result, err error) { - return c.Model(table).Ctx(ctx).Where(condition, args...).Delete() + return c.Model(table).Ctx(ctx).Where(condition, args...).Delete() } // DoDelete does "DELETE FROM ... " statement for the table. // This function is usually used for custom interface definition, you do not need call it manually. func (c *Core) DoDelete(ctx context.Context, link Link, table string, condition string, args ...interface{}) (result sql.Result, err error) { - if link == nil { - if link, err = c.MasterLink(); err != nil { - return nil, err - } - } - table = c.QuotePrefixTableName(table) - return c.db.DoExec(ctx, link, fmt.Sprintf("DELETE FROM %s%s", table, condition), args...) + if link == nil { + if link, err = c.MasterLink(); err != nil { + return nil, err + } + } + table = c.QuotePrefixTableName(table) + return c.db.DoExec(ctx, link, fmt.Sprintf("DELETE FROM %s%s", table, condition), args...) } // FilteredLink retrieves and returns filtered `linkInfo` that can be using for // logging or tracing purpose. func (c *Core) FilteredLink() string { - return fmt.Sprintf( - `%s@%s(%s:%s)/%s`, - c.config.User, c.config.Protocol, c.config.Host, c.config.Port, c.config.Name, - ) + return fmt.Sprintf( + `%s@%s(%s:%s)/%s`, + c.config.User, c.config.Protocol, c.config.Host, c.config.Port, c.config.Name, + ) } // MarshalJSON implements the interface MarshalJSON for json.Marshal. @@ -702,97 +702,97 @@ func (c *Core) FilteredLink() string { // Note that this interface implements mainly for workaround for a json infinite loop bug // of Golang version < v1.14. func (c *Core) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf(`%+v`, c)), nil + return []byte(fmt.Sprintf(`%+v`, c)), nil } // writeSqlToLogger outputs the Sql object to logger. // It is enabled only if configuration "debug" is true. func (c *Core) writeSqlToLogger(ctx context.Context, sql *Sql) { - var transactionIdStr string - if sql.IsTransaction { - if v := ctx.Value(transactionIdForLoggerCtx); v != nil { - transactionIdStr = fmt.Sprintf(`[txid:%d] `, v.(uint64)) - } - } - s := fmt.Sprintf( - "[%3d ms] [%s] [%s] [rows:%-3d] %s%s", - sql.End-sql.Start, sql.Group, sql.Schema, sql.RowsAffected, transactionIdStr, sql.Format, - ) - if sql.Error != nil { - s += "\nError: " + sql.Error.Error() - c.logger.Error(ctx, s) - } else { - c.logger.Debug(ctx, s) - } + var transactionIdStr string + if sql.IsTransaction { + if v := ctx.Value(transactionIdForLoggerCtx); v != nil { + transactionIdStr = fmt.Sprintf(`[txid:%d] `, v.(uint64)) + } + } + s := fmt.Sprintf( + "[%3d ms] [%s] [%s] [rows:%-3d] %s%s", + sql.End-sql.Start, sql.Group, sql.Schema, sql.RowsAffected, transactionIdStr, sql.Format, + ) + if sql.Error != nil { + s += "\nError: " + sql.Error.Error() + c.logger.Error(ctx, s) + } else { + c.logger.Debug(ctx, s) + } } // HasTable determine whether the table name exists in the database. func (c *Core) HasTable(name string) (bool, error) { - tables, err := c.GetTablesWithCache() - if err != nil { - return false, err - } - charL, charR := c.db.GetChars() - name = gstr.Trim(name, charL+charR) - for _, table := range tables { - if table == name { - return true, nil - } - } - return false, nil + tables, err := c.GetTablesWithCache() + if err != nil { + return false, err + } + charL, charR := c.db.GetChars() + name = gstr.Trim(name, charL+charR) + for _, table := range tables { + if table == name { + return true, nil + } + } + return false, nil } // GetInnerMemCache retrieves and returns the inner memory cache object. func (c *Core) GetInnerMemCache() *gcache.Cache { - return c.innerMemCache + return c.innerMemCache } // GetTablesWithCache retrieves and returns the table names of current database with cache. func (c *Core) GetTablesWithCache() ([]string, error) { - var ( - ctx = c.db.GetCtx() - cacheKey = fmt.Sprintf(`Tables:%s`, c.db.GetGroup()) - cacheDuration = gcache.DurationNoExpire - innerMemCache = c.GetInnerMemCache() - ) - result, err := innerMemCache.GetOrSetFuncLock( - ctx, cacheKey, - func(ctx context.Context) (interface{}, error) { - tableList, err := c.db.Tables(ctx) - if err != nil { - return nil, err - } - return tableList, nil - }, cacheDuration, - ) - if err != nil { - return nil, err - } - return result.Strings(), nil + var ( + ctx = c.db.GetCtx() + cacheKey = fmt.Sprintf(`Tables:%s`, c.db.GetGroup()) + cacheDuration = gcache.DurationNoExpire + innerMemCache = c.GetInnerMemCache() + ) + result, err := innerMemCache.GetOrSetFuncLock( + ctx, cacheKey, + func(ctx context.Context) (interface{}, error) { + tableList, err := c.db.Tables(ctx) + if err != nil { + return nil, err + } + return tableList, nil + }, cacheDuration, + ) + if err != nil { + return nil, err + } + return result.Strings(), nil } // IsSoftCreatedFieldName checks and returns whether given field name is an automatic-filled created time. func (c *Core) IsSoftCreatedFieldName(fieldName string) bool { - if fieldName == "" { - return false - } - if config := c.db.GetConfig(); config.CreatedAt != "" { - if utils.EqualFoldWithoutChars(fieldName, config.CreatedAt) { - return true - } - return gstr.InArray(append([]string{config.CreatedAt}, createdFieldNames...), fieldName) - } - for _, v := range createdFieldNames { - if utils.EqualFoldWithoutChars(fieldName, v) { - return true - } - } - return false + if fieldName == "" { + return false + } + if config := c.db.GetConfig(); config.CreatedAt != "" { + if utils.EqualFoldWithoutChars(fieldName, config.CreatedAt) { + return true + } + return gstr.InArray(append([]string{config.CreatedAt}, createdFieldNames...), fieldName) + } + for _, v := range createdFieldNames { + if utils.EqualFoldWithoutChars(fieldName, v) { + return true + } + } + return false } // FormatSqlBeforeExecuting formats the sql string and its arguments before executing. // The internal handleArguments function might be called twice during the SQL procedure, // but do not worry about it, it's safe and efficient. func (c *Core) FormatSqlBeforeExecuting(sql string, args []interface{}) (newSql string, newArgs []interface{}) { - return handleSliceAndStructArgsForSql(sql, args) + return handleSliceAndStructArgsForSql(sql, args) } diff --git a/database/gdb/gdb_core_structure.go b/database/gdb/gdb_core_structure.go index 25f90ebd1e9..65b385a0215 100644 --- a/database/gdb/gdb_core_structure.go +++ b/database/gdb/gdb_core_structure.go @@ -7,61 +7,61 @@ package gdb import ( - "context" - "database/sql/driver" - "reflect" - "strings" - "time" - - "github.com/gogf/gf/v2/encoding/gbinary" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/intlog" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/text/gregex" - "github.com/gogf/gf/v2/text/gstr" - "github.com/gogf/gf/v2/util/gconv" - "github.com/gogf/gf/v2/util/gutil" + "context" + "database/sql/driver" + "reflect" + "strings" + "time" + + "github.com/gogf/gf/v2/encoding/gbinary" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/intlog" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/gutil" ) // GetFieldTypeStr retrieves and returns the field type string for certain field by name. func (c *Core) GetFieldTypeStr(ctx context.Context, fieldName, table, schema string) string { - field := c.GetFieldType(ctx, fieldName, table, schema) - if field != nil { - // Kinds of data type examples: - // year(4) - // datetime - // varchar(64) - // bigint(20) - // int(10) unsigned - typeName := gstr.StrTillEx(field.Type, "(") // int(10) unsigned -> int - if typeName != "" { - typeName = gstr.Trim(typeName) - } else { - typeName = field.Type - } - return typeName - } - return "" + field := c.GetFieldType(ctx, fieldName, table, schema) + if field != nil { + // Kinds of data type examples: + // year(4) + // datetime + // varchar(64) + // bigint(20) + // int(10) unsigned + typeName := gstr.StrTillEx(field.Type, "(") // int(10) unsigned -> int + if typeName != "" { + typeName = gstr.Trim(typeName) + } else { + typeName = field.Type + } + return typeName + } + return "" } // GetFieldType retrieves and returns the field type object for certain field by name. func (c *Core) GetFieldType(ctx context.Context, fieldName, table, schema string) *TableField { - fieldsMap, err := c.db.TableFields(ctx, table, schema) - if err != nil { - intlog.Errorf( - ctx, - `TableFields failed for table "%s", schema "%s": %+v`, - table, schema, err, - ) - return nil - } - for tableFieldName, tableField := range fieldsMap { - if tableFieldName == fieldName { - return tableField - } - } - return nil + fieldsMap, err := c.db.TableFields(ctx, table, schema) + if err != nil { + intlog.Errorf( + ctx, + `TableFields failed for table "%s", schema "%s": %+v`, + table, schema, err, + ) + return nil + } + for tableFieldName, tableField := range fieldsMap { + if tableFieldName == fieldName { + return tableField + } + } + return nil } // ConvertDataForRecord is a very important function, which does converting for any data that @@ -70,420 +70,420 @@ func (c *Core) GetFieldType(ctx context.Context, fieldName, table, schema string // 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{}, table string) (map[string]interface{}, error) { - var ( - err error - data = MapOrStructToMapDeep(value, true) - ) - for fieldName, fieldValue := range data { - var fieldType = c.GetFieldTypeStr(ctx, fieldName, table, c.GetSchema()) - data[fieldName], err = c.db.ConvertValueForField( - ctx, - fieldType, - fieldValue, - ) - if err != nil { - return nil, gerror.Wrapf(err, `ConvertDataForRecord failed for value: %#v`, fieldValue) - } - } - return data, nil + var ( + err error + data = MapOrStructToMapDeep(value, true) + ) + for fieldName, fieldValue := range data { + var fieldType = c.GetFieldTypeStr(ctx, fieldName, table, c.GetSchema()) + data[fieldName], err = c.db.ConvertValueForField( + ctx, + fieldType, + fieldValue, + ) + if err != nil { + return nil, gerror.Wrapf(err, `ConvertDataForRecord failed for value: %#v`, fieldValue) + } + } + return data, nil } // ConvertValueForField converts value to the type of the record field. // The parameter `fieldType` is the target record field. // The parameter `fieldValue` is the value that to be committed to record field. func (c *Core) ConvertValueForField(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) { - var ( - err error - convertedValue = fieldValue - ) - switch fieldValue.(type) { - case time.Time, *time.Time, gtime.Time, *gtime.Time: - goto Default - } - // If `value` implements interface `driver.Valuer`, it then uses the interface for value converting. - if valuer, ok := fieldValue.(driver.Valuer); ok { - if convertedValue, err = valuer.Value(); err != nil { - return nil, err - } - return convertedValue, nil - } + var ( + err error + convertedValue = fieldValue + ) + switch fieldValue.(type) { + case time.Time, *time.Time, gtime.Time, *gtime.Time: + goto Default + } + // If `value` implements interface `driver.Valuer`, it then uses the interface for value converting. + if valuer, ok := fieldValue.(driver.Valuer); ok { + if convertedValue, err = valuer.Value(); err != nil { + return nil, err + } + return convertedValue, nil + } Default: - // Default value converting. - var ( - rvValue = reflect.ValueOf(fieldValue) - rvKind = rvValue.Kind() - ) - for rvKind == reflect.Ptr { - rvValue = rvValue.Elem() - rvKind = rvValue.Kind() - } - switch rvKind { - case reflect.Invalid: - convertedValue = nil - - case reflect.Slice, reflect.Array, reflect.Map: - // It should ignore the bytes type. - if _, ok := fieldValue.([]byte); !ok { - // Convert the value to JSON. - convertedValue, err = json.Marshal(fieldValue) - if err != nil { - return nil, err - } - } - case reflect.Struct: - switch r := fieldValue.(type) { - // If the time is zero, it then updates it to nil, - // which will insert/update the value to database as "null". - case time.Time: - if r.IsZero() { - convertedValue = nil - } else { - switch fieldType { - case fieldTypeYear: - convertedValue = r.Format("2006") - case fieldTypeDate: - convertedValue = r.Format("2006-01-02") - case fieldTypeTime: - convertedValue = r.Format("15:04:05") - default: - } - } - - case *time.Time: - if r == nil { - // Nothing to do. - } else { - switch fieldType { - case fieldTypeYear: - convertedValue = r.Format("2006") - case fieldTypeDate: - convertedValue = r.Format("2006-01-02") - case fieldTypeTime: - convertedValue = r.Format("15:04:05") - default: - } - } - - case gtime.Time: - if r.IsZero() { - convertedValue = nil - } else { - switch fieldType { - case fieldTypeYear: - convertedValue = r.Layout("2006") - case fieldTypeDate: - convertedValue = r.Layout("2006-01-02") - case fieldTypeTime: - convertedValue = r.Layout("15:04:05") - default: - convertedValue = r.Time - } - } - - case *gtime.Time: - if r.IsZero() { - convertedValue = nil - } else { - switch fieldType { - case fieldTypeYear: - convertedValue = r.Layout("2006") - case fieldTypeDate: - convertedValue = r.Layout("2006-01-02") - case fieldTypeTime: - convertedValue = r.Layout("15:04:05") - default: - convertedValue = r.Time - } - } - - case Counter, *Counter: - // Nothing to do. - - default: - // If `value` implements interface iNil, - // check its IsNil() function, if got ture, - // which will insert/update the value to database as "null". - if v, ok := fieldValue.(iNil); ok && v.IsNil() { - convertedValue = nil - } else if s, ok := fieldValue.(iString); ok { - // Use string conversion in default. - convertedValue = s.String() - } else { - // Convert the value to JSON. - convertedValue, err = json.Marshal(fieldValue) - if err != nil { - return nil, err - } - } - } - default: - } - - return convertedValue, nil + // Default value converting. + var ( + rvValue = reflect.ValueOf(fieldValue) + rvKind = rvValue.Kind() + ) + for rvKind == reflect.Ptr { + rvValue = rvValue.Elem() + rvKind = rvValue.Kind() + } + switch rvKind { + case reflect.Invalid: + convertedValue = nil + + case reflect.Slice, reflect.Array, reflect.Map: + // It should ignore the bytes type. + if _, ok := fieldValue.([]byte); !ok { + // Convert the value to JSON. + convertedValue, err = json.Marshal(fieldValue) + if err != nil { + return nil, err + } + } + case reflect.Struct: + switch r := fieldValue.(type) { + // If the time is zero, it then updates it to nil, + // which will insert/update the value to database as "null". + case time.Time: + if r.IsZero() { + convertedValue = nil + } else { + switch fieldType { + case fieldTypeYear: + convertedValue = r.Format("2006") + case fieldTypeDate: + convertedValue = r.Format("2006-01-02") + case fieldTypeTime: + convertedValue = r.Format("15:04:05") + default: + } + } + + case *time.Time: + if r == nil { + // Nothing to do. + } else { + switch fieldType { + case fieldTypeYear: + convertedValue = r.Format("2006") + case fieldTypeDate: + convertedValue = r.Format("2006-01-02") + case fieldTypeTime: + convertedValue = r.Format("15:04:05") + default: + } + } + + case gtime.Time: + if r.IsZero() { + convertedValue = nil + } else { + switch fieldType { + case fieldTypeYear: + convertedValue = r.Layout("2006") + case fieldTypeDate: + convertedValue = r.Layout("2006-01-02") + case fieldTypeTime: + convertedValue = r.Layout("15:04:05") + default: + convertedValue = r.Time + } + } + + case *gtime.Time: + if r.IsZero() { + convertedValue = nil + } else { + switch fieldType { + case fieldTypeYear: + convertedValue = r.Layout("2006") + case fieldTypeDate: + convertedValue = r.Layout("2006-01-02") + case fieldTypeTime: + convertedValue = r.Layout("15:04:05") + default: + convertedValue = r.Time + } + } + + case Counter, *Counter: + // Nothing to do. + + default: + // If `value` implements interface iNil, + // check its IsNil() function, if got ture, + // which will insert/update the value to database as "null". + if v, ok := fieldValue.(iNil); ok && v.IsNil() { + convertedValue = nil + } else if s, ok := fieldValue.(iString); ok { + // Use string conversion in default. + convertedValue = s.String() + } else { + // Convert the value to JSON. + convertedValue, err = json.Marshal(fieldValue) + if err != nil { + return nil, err + } + } + } + default: + } + + return convertedValue, nil } // CheckLocalTypeForField checks and returns corresponding type for given db type. // The `fieldType` is retrieved from ColumnTypes of db driver, example: // UNSIGNED INT func (c *Core) CheckLocalTypeForField(ctx context.Context, fieldType string, _ interface{}) (LocalType, error) { - var ( - typeName string - typePattern string - ) - match, _ := gregex.MatchString(`(.+?)\((.+)\)`, fieldType) - if len(match) == 3 { - typeName = gstr.Trim(match[1]) - typePattern = gstr.Trim(match[2]) - } else { - var array = gstr.SplitAndTrim(fieldType, " ") - if gstr.Equal(array[0], "unsigned") { - typeName = array[1] - } else { - typeName = array[0] - } - } - - typeName = strings.ToLower(typeName) - - switch typeName { - case - fieldTypeBinary, - fieldTypeVarbinary, - fieldTypeBlob, - fieldTypeTinyblob, - fieldTypeMediumblob, - fieldTypeLongblob: - return LocalTypeBytes, nil - - case - fieldTypeInt, - fieldTypeTinyint, - fieldTypeSmallInt, - fieldTypeSmallint, - fieldTypeMediumInt, - fieldTypeMediumint, - fieldTypeSerial: - if gstr.ContainsI(fieldType, "unsigned") { - return LocalTypeUint, nil - } - return LocalTypeInt, nil - - case - fieldTypeBigInt, - fieldTypeBigint, - fieldTypeBigserial: - if gstr.ContainsI(fieldType, "unsigned") { - return LocalTypeUint64, nil - } - return LocalTypeInt64, nil - - case - fieldTypeReal: - return LocalTypeFloat32, nil - - case - fieldTypeDecimal, - fieldTypeMoney, - fieldTypeNumeric, - fieldTypeSmallmoney: - return LocalTypeString, nil - case - fieldTypeFloat, - fieldTypeDouble: - return LocalTypeFloat64, nil - - case - fieldTypeBit: - // It is suggested using bit(1) as boolean. - if typePattern == "1" { - return LocalTypeBool, nil - } - if gstr.ContainsI(fieldType, "unsigned") { - return LocalTypeUint64Bytes, nil - } - return LocalTypeInt64Bytes, nil - - case - fieldTypeBool: - return LocalTypeBool, nil - - case - fieldTypeDate: - return LocalTypeDate, nil - - case - fieldTypeTime: - return LocalTypeTime, nil - - case - fieldTypeDatetime, - fieldTypeTimestamp, - fieldTypeTimestampz: - return LocalTypeDatetime, nil - - case - fieldTypeJson: - return LocalTypeJson, nil - - case - fieldTypeJsonb: - return LocalTypeJsonb, nil - - default: - // Auto-detect field type, using key match. - switch { - case strings.Contains(typeName, "text") || strings.Contains(typeName, "char") || strings.Contains(typeName, "character"): - return LocalTypeString, nil - - case strings.Contains(typeName, "float") || strings.Contains(typeName, "double") || strings.Contains(typeName, "numeric"): - return LocalTypeFloat64, nil - - case strings.Contains(typeName, "bool"): - return LocalTypeBool, nil - - case strings.Contains(typeName, "binary") || strings.Contains(typeName, "blob"): - return LocalTypeBytes, nil - - case strings.Contains(typeName, "int"): - if gstr.ContainsI(fieldType, "unsigned") { - return LocalTypeUint, nil - } - return LocalTypeInt, nil - - case strings.Contains(typeName, "time"): - return LocalTypeDatetime, nil - - case strings.Contains(typeName, "date"): - return LocalTypeDatetime, nil - - default: - return LocalTypeString, nil - } - } + var ( + typeName string + typePattern string + ) + match, _ := gregex.MatchString(`(.+?)\((.+)\)`, fieldType) + if len(match) == 3 { + typeName = gstr.Trim(match[1]) + typePattern = gstr.Trim(match[2]) + } else { + var array = gstr.SplitAndTrim(fieldType, " ") + if gstr.Equal(array[0], "unsigned") { + typeName = array[1] + } else { + typeName = array[0] + } + } + + typeName = strings.ToLower(typeName) + + switch typeName { + case + fieldTypeBinary, + fieldTypeVarbinary, + fieldTypeBlob, + fieldTypeTinyblob, + fieldTypeMediumblob, + fieldTypeLongblob: + return LocalTypeBytes, nil + + case + fieldTypeInt, + fieldTypeTinyint, + fieldTypeSmallInt, + fieldTypeSmallint, + fieldTypeMediumInt, + fieldTypeMediumint, + fieldTypeSerial: + if gstr.ContainsI(fieldType, "unsigned") { + return LocalTypeUint, nil + } + return LocalTypeInt, nil + + case + fieldTypeBigInt, + fieldTypeBigint, + fieldTypeBigserial: + if gstr.ContainsI(fieldType, "unsigned") { + return LocalTypeUint64, nil + } + return LocalTypeInt64, nil + + case + fieldTypeReal: + return LocalTypeFloat32, nil + + case + fieldTypeDecimal, + fieldTypeMoney, + fieldTypeNumeric, + fieldTypeSmallmoney: + return LocalTypeString, nil + case + fieldTypeFloat, + fieldTypeDouble: + return LocalTypeFloat64, nil + + case + fieldTypeBit: + // It is suggested using bit(1) as boolean. + if typePattern == "1" { + return LocalTypeBool, nil + } + if gstr.ContainsI(fieldType, "unsigned") { + return LocalTypeUint64Bytes, nil + } + return LocalTypeInt64Bytes, nil + + case + fieldTypeBool: + return LocalTypeBool, nil + + case + fieldTypeDate: + return LocalTypeDate, nil + + case + fieldTypeTime: + return LocalTypeTime, nil + + case + fieldTypeDatetime, + fieldTypeTimestamp, + fieldTypeTimestampz: + return LocalTypeDatetime, nil + + case + fieldTypeJson: + return LocalTypeJson, nil + + case + fieldTypeJsonb: + return LocalTypeJsonb, nil + + default: + // Auto-detect field type, using key match. + switch { + case strings.Contains(typeName, "text") || strings.Contains(typeName, "char") || strings.Contains(typeName, "character"): + return LocalTypeString, nil + + case strings.Contains(typeName, "float") || strings.Contains(typeName, "double") || strings.Contains(typeName, "numeric"): + return LocalTypeFloat64, nil + + case strings.Contains(typeName, "bool"): + return LocalTypeBool, nil + + case strings.Contains(typeName, "binary") || strings.Contains(typeName, "blob"): + return LocalTypeBytes, nil + + case strings.Contains(typeName, "int"): + if gstr.ContainsI(fieldType, "unsigned") { + return LocalTypeUint, nil + } + return LocalTypeInt, nil + + case strings.Contains(typeName, "time"): + return LocalTypeDatetime, nil + + case strings.Contains(typeName, "date"): + return LocalTypeDatetime, nil + + default: + return LocalTypeString, nil + } + } } // ConvertValueForLocal converts value to local Golang type of value according field type name from database. // The parameter `fieldType` is in lower case, like: // `float(5,2)`, `unsigned double(5,2)`, `decimal(10,2)`, `char(45)`, `varchar(100)`, etc. func (c *Core) ConvertValueForLocal( - ctx context.Context, fieldType string, fieldValue interface{}, + ctx context.Context, fieldType string, fieldValue interface{}, ) (interface{}, error) { - // If there's no type retrieved, it returns the `fieldValue` directly - // to use its original data type, as `fieldValue` is type of interface{}. - if fieldType == "" { - return fieldValue, nil - } - typeName, err := c.db.CheckLocalTypeForField(ctx, fieldType, fieldValue) - if err != nil { - return nil, err - } - switch typeName { - case LocalTypeBytes: - var typeNameStr = string(typeName) - if strings.Contains(typeNameStr, "binary") || strings.Contains(typeNameStr, "blob") { - return fieldValue, nil - } - return gconv.Bytes(fieldValue), nil - - case LocalTypeInt: - return gconv.Int(gconv.String(fieldValue)), nil - - case LocalTypeUint: - return gconv.Uint(gconv.String(fieldValue)), nil - - case LocalTypeInt64: - return gconv.Int64(gconv.String(fieldValue)), nil - - case LocalTypeUint64: - return gconv.Uint64(gconv.String(fieldValue)), nil - - case LocalTypeInt64Bytes: - return gbinary.BeDecodeToInt64(gconv.Bytes(fieldValue)), nil - - case LocalTypeUint64Bytes: - return gbinary.BeDecodeToUint64(gconv.Bytes(fieldValue)), nil - - case LocalTypeFloat32: - return gconv.Float32(gconv.String(fieldValue)), nil - - case LocalTypeFloat64: - return gconv.Float64(gconv.String(fieldValue)), nil - - case LocalTypeBool: - s := gconv.String(fieldValue) - // mssql is true|false string. - if strings.EqualFold(s, "true") { - return 1, nil - } - if strings.EqualFold(s, "false") { - return 0, nil - } - return gconv.Bool(fieldValue), nil - - case LocalTypeDate: - if t, ok := fieldValue.(time.Time); ok { - return gtime.NewFromTime(t).Format("Y-m-d"), nil - } - t, _ := gtime.StrToTime(gconv.String(fieldValue)) - return t.Format("Y-m-d"), nil - - case LocalTypeTime: - if t, ok := fieldValue.(time.Time); ok { - return gtime.NewFromTime(t).Format("H:i:s"), nil - } - t, _ := gtime.StrToTime(gconv.String(fieldValue)) - return t.Format("H:i:s"), nil - - case LocalTypeDatetime: - if t, ok := fieldValue.(time.Time); ok { - return gtime.NewFromTime(t), nil - } - t, _ := gtime.StrToTime(gconv.String(fieldValue)) - return t, nil - - default: - return gconv.String(fieldValue), nil - } + // If there's no type retrieved, it returns the `fieldValue` directly + // to use its original data type, as `fieldValue` is type of interface{}. + if fieldType == "" { + return fieldValue, nil + } + typeName, err := c.db.CheckLocalTypeForField(ctx, fieldType, fieldValue) + if err != nil { + return nil, err + } + switch typeName { + case LocalTypeBytes: + var typeNameStr = string(typeName) + if strings.Contains(typeNameStr, "binary") || strings.Contains(typeNameStr, "blob") { + return fieldValue, nil + } + return gconv.Bytes(fieldValue), nil + + case LocalTypeInt: + return gconv.Int(gconv.String(fieldValue)), nil + + case LocalTypeUint: + return gconv.Uint(gconv.String(fieldValue)), nil + + case LocalTypeInt64: + return gconv.Int64(gconv.String(fieldValue)), nil + + case LocalTypeUint64: + return gconv.Uint64(gconv.String(fieldValue)), nil + + case LocalTypeInt64Bytes: + return gbinary.BeDecodeToInt64(gconv.Bytes(fieldValue)), nil + + case LocalTypeUint64Bytes: + return gbinary.BeDecodeToUint64(gconv.Bytes(fieldValue)), nil + + case LocalTypeFloat32: + return gconv.Float32(gconv.String(fieldValue)), nil + + case LocalTypeFloat64: + return gconv.Float64(gconv.String(fieldValue)), nil + + case LocalTypeBool: + s := gconv.String(fieldValue) + // mssql is true|false string. + if strings.EqualFold(s, "true") { + return 1, nil + } + if strings.EqualFold(s, "false") { + return 0, nil + } + return gconv.Bool(fieldValue), nil + + case LocalTypeDate: + if t, ok := fieldValue.(time.Time); ok { + return gtime.NewFromTime(t).Format("Y-m-d"), nil + } + t, _ := gtime.StrToTime(gconv.String(fieldValue)) + return t.Format("Y-m-d"), nil + + case LocalTypeTime: + if t, ok := fieldValue.(time.Time); ok { + return gtime.NewFromTime(t).Format("H:i:s"), nil + } + t, _ := gtime.StrToTime(gconv.String(fieldValue)) + return t.Format("H:i:s"), nil + + case LocalTypeDatetime: + if t, ok := fieldValue.(time.Time); ok { + return gtime.NewFromTime(t), nil + } + t, _ := gtime.StrToTime(gconv.String(fieldValue)) + return t, nil + + default: + return gconv.String(fieldValue), nil + } } // mappingAndFilterData automatically mappings the map key to table field and removes // all key-value pairs that are not the field of given table. func (c *Core) mappingAndFilterData(ctx context.Context, schema, table string, data map[string]interface{}, filter bool) (map[string]interface{}, error) { - fieldsMap, err := c.db.TableFields(ctx, c.guessPrimaryTableName(table), schema) - if err != nil { - return nil, err - } - if len(fieldsMap) == 0 { - return nil, gerror.Newf(`The table %s may not exist, or the table contains no fields`, table) - } - fieldsKeyMap := make(map[string]interface{}, len(fieldsMap)) - for k := range fieldsMap { - fieldsKeyMap[k] = nil - } - // Automatic data key to table field name mapping. - var foundKey string - for dataKey, dataValue := range data { - if _, ok := fieldsKeyMap[dataKey]; !ok { - foundKey, _ = gutil.MapPossibleItemByKey(fieldsKeyMap, dataKey) - if foundKey != "" { - if _, ok = data[foundKey]; !ok { - data[foundKey] = dataValue - } - delete(data, dataKey) - } - } - } - // Data filtering. - // It deletes all key-value pairs that has incorrect field name. - if filter { - for dataKey := range data { - if _, ok := fieldsMap[dataKey]; !ok { - delete(data, dataKey) - } - } - if len(data) == 0 { - return nil, gerror.Newf(`input data match no fields in table %s`, table) - } - } - return data, nil + fieldsMap, err := c.db.TableFields(ctx, c.guessPrimaryTableName(table), schema) + if err != nil { + return nil, err + } + if len(fieldsMap) == 0 { + return nil, gerror.Newf(`The table %s may not exist, or the table contains no fields`, table) + } + fieldsKeyMap := make(map[string]interface{}, len(fieldsMap)) + for k := range fieldsMap { + fieldsKeyMap[k] = nil + } + // Automatic data key to table field name mapping. + var foundKey string + for dataKey, dataValue := range data { + if _, ok := fieldsKeyMap[dataKey]; !ok { + foundKey, _ = gutil.MapPossibleItemByKey(fieldsKeyMap, dataKey) + if foundKey != "" { + if _, ok = data[foundKey]; !ok { + data[foundKey] = dataValue + } + delete(data, dataKey) + } + } + } + // Data filtering. + // It deletes all key-value pairs that has incorrect field name. + if filter { + for dataKey := range data { + if _, ok := fieldsMap[dataKey]; !ok { + delete(data, dataKey) + } + } + if len(data) == 0 { + return nil, gerror.Newf(`input data match no fields in table %s`, table) + } + } + return data, nil } diff --git a/database/gdb/gdb_core_underlying.go b/database/gdb/gdb_core_underlying.go index bc380a335df..8150765835f 100644 --- a/database/gdb/gdb_core_underlying.go +++ b/database/gdb/gdb_core_underlying.go @@ -8,298 +8,298 @@ package gdb import ( - "context" - "database/sql" - "fmt" - "reflect" - - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/trace" - - "github.com/gogf/gf/v2" - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/intlog" - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/util/gconv" - "github.com/gogf/gf/v2/util/guid" + "context" + "database/sql" + "fmt" + "reflect" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" + + "github.com/gogf/gf/v2" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/intlog" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/guid" ) // Query commits one query SQL to underlying driver and returns the execution result. // It is most commonly used for data querying. func (c *Core) Query(ctx context.Context, sql string, args ...interface{}) (result Result, err error) { - return c.db.DoQuery(ctx, nil, sql, args...) + return c.db.DoQuery(ctx, nil, sql, args...) } // DoQuery commits the sql string and its arguments to underlying driver // through given link object and returns the execution result. func (c *Core) DoQuery(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) { - // Transaction checks. - if link == nil { - if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { - // Firstly, check and retrieve transaction link from context. - link = &txLink{tx.GetSqlTX()} - } else if link, err = c.SlaveLink(); err != nil { - // Or else it creates one from master node. - return nil, err - } - } else if !link.IsTransaction() { - // If current link is not transaction link, it checks and retrieves transaction from context. - if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { - link = &txLink{tx.GetSqlTX()} - } - } - - // Sql filtering. - sql, args = c.FormatSqlBeforeExecuting(sql, args) - sql, args, err = c.db.DoFilter(ctx, link, sql, args) - if err != nil { - return nil, err - } - // SQL format and retrieve. - if v := ctx.Value(ctxKeyCatchSQL); v != nil { - var ( - manager = v.(*CatchSQLManager) - formattedSql = FormatSqlWithArgs(sql, args) - ) - manager.SQLArray.Append(formattedSql) - if !manager.DoCommit && ctx.Value(ctxKeyInternalProducedSQL) == nil { - return nil, nil - } - } - // Link execution. - var out DoCommitOutput - out, err = c.db.DoCommit(ctx, DoCommitInput{ - Link: link, - Sql: sql, - Args: args, - Stmt: nil, - Type: SqlTypeQueryContext, - IsTransaction: link.IsTransaction(), - }) - if err != nil { - return nil, err - } - return out.Records, err + // Transaction checks. + if link == nil { + if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { + // Firstly, check and retrieve transaction link from context. + link = &txLink{tx.GetSqlTX()} + } else if link, err = c.SlaveLink(); err != nil { + // Or else it creates one from master node. + return nil, err + } + } else if !link.IsTransaction() { + // If current link is not transaction link, it checks and retrieves transaction from context. + if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { + link = &txLink{tx.GetSqlTX()} + } + } + + // Sql filtering. + sql, args = c.FormatSqlBeforeExecuting(sql, args) + sql, args, err = c.db.DoFilter(ctx, link, sql, args) + if err != nil { + return nil, err + } + // SQL format and retrieve. + if v := ctx.Value(ctxKeyCatchSQL); v != nil { + var ( + manager = v.(*CatchSQLManager) + formattedSql = FormatSqlWithArgs(sql, args) + ) + manager.SQLArray.Append(formattedSql) + if !manager.DoCommit && ctx.Value(ctxKeyInternalProducedSQL) == nil { + return nil, nil + } + } + // Link execution. + var out DoCommitOutput + out, err = c.db.DoCommit(ctx, DoCommitInput{ + Link: link, + Sql: sql, + Args: args, + Stmt: nil, + Type: SqlTypeQueryContext, + IsTransaction: link.IsTransaction(), + }) + if err != nil { + return nil, err + } + return out.Records, err } // Exec commits one query SQL to underlying driver and returns the execution result. // It is most commonly used for data inserting and updating. func (c *Core) Exec(ctx context.Context, sql string, args ...interface{}) (result sql.Result, err error) { - return c.db.DoExec(ctx, nil, sql, args...) + return c.db.DoExec(ctx, nil, sql, args...) } // DoExec commits the sql string and its arguments to underlying driver // through given link object and returns the execution result. func (c *Core) DoExec(ctx context.Context, link Link, sql string, args ...interface{}) (result sql.Result, err error) { - // Transaction checks. - if link == nil { - if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { - // Firstly, check and retrieve transaction link from context. - link = &txLink{tx.GetSqlTX()} - } else if link, err = c.MasterLink(); err != nil { - // Or else it creates one from master node. - return nil, err - } - } else if !link.IsTransaction() { - // If current link is not transaction link, it checks and retrieves transaction from context. - if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { - link = &txLink{tx.GetSqlTX()} - } - } - - // SQL filtering. - sql, args = c.FormatSqlBeforeExecuting(sql, args) - sql, args, err = c.db.DoFilter(ctx, link, sql, args) - if err != nil { - return nil, err - } - // SQL format and retrieve. - if v := ctx.Value(ctxKeyCatchSQL); v != nil { - var ( - manager = v.(*CatchSQLManager) - formattedSql = FormatSqlWithArgs(sql, args) - ) - manager.SQLArray.Append(formattedSql) - if !manager.DoCommit && ctx.Value(ctxKeyInternalProducedSQL) == nil { - return new(SqlResult), nil - } - } - // Link execution. - var out DoCommitOutput - out, err = c.db.DoCommit(ctx, DoCommitInput{ - Link: link, - Sql: sql, - Args: args, - Stmt: nil, - Type: SqlTypeExecContext, - IsTransaction: link.IsTransaction(), - }) - if err != nil { - return nil, err - } - return out.Result, err + // Transaction checks. + if link == nil { + if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { + // Firstly, check and retrieve transaction link from context. + link = &txLink{tx.GetSqlTX()} + } else if link, err = c.MasterLink(); err != nil { + // Or else it creates one from master node. + return nil, err + } + } else if !link.IsTransaction() { + // If current link is not transaction link, it checks and retrieves transaction from context. + if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { + link = &txLink{tx.GetSqlTX()} + } + } + + // SQL filtering. + sql, args = c.FormatSqlBeforeExecuting(sql, args) + sql, args, err = c.db.DoFilter(ctx, link, sql, args) + if err != nil { + return nil, err + } + // SQL format and retrieve. + if v := ctx.Value(ctxKeyCatchSQL); v != nil { + var ( + manager = v.(*CatchSQLManager) + formattedSql = FormatSqlWithArgs(sql, args) + ) + manager.SQLArray.Append(formattedSql) + if !manager.DoCommit && ctx.Value(ctxKeyInternalProducedSQL) == nil { + return new(SqlResult), nil + } + } + // Link execution. + var out DoCommitOutput + out, err = c.db.DoCommit(ctx, DoCommitInput{ + Link: link, + Sql: sql, + Args: args, + Stmt: nil, + Type: SqlTypeExecContext, + IsTransaction: link.IsTransaction(), + }) + if err != nil { + return nil, err + } + return out.Result, err } // DoFilter is a hook function, which filters the sql and its arguments before it's committed to underlying driver. // The parameter `link` specifies the current database connection operation object. You can modify the sql // string `sql` and its arguments `args` as you wish before they're committed to driver. func (c *Core) DoFilter( - ctx context.Context, link Link, sql string, args []interface{}, + ctx context.Context, link Link, sql string, args []interface{}, ) (newSql string, newArgs []interface{}, err error) { - return sql, args, nil + return sql, args, nil } // DoCommit commits current sql and arguments to underlying sql driver. func (c *Core) DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutput, err error) { - var ( - sqlTx *sql.Tx - sqlStmt *sql.Stmt - sqlRows *sql.Rows - sqlResult sql.Result - stmtSqlRows *sql.Rows - stmtSqlRow *sql.Row - rowsAffected int64 - cancelFuncForTimeout context.CancelFunc - formattedSql = FormatSqlWithArgs(in.Sql, in.Args) - timestampMilli1 = gtime.TimestampMilli() - ) - - // Trace span start. - tr := otel.GetTracerProvider().Tracer(traceInstrumentName, trace.WithInstrumentationVersion(gf.VERSION)) - ctx, span := tr.Start(ctx, string(in.Type), trace.WithSpanKind(trace.SpanKindInternal)) - defer span.End() - - // Execution by type. - switch in.Type { - case SqlTypeBegin: - ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeTrans) - formattedSql = fmt.Sprintf( - `%s (IosolationLevel: %s, ReadOnly: %t)`, - formattedSql, in.TxOptions.Isolation.String(), in.TxOptions.ReadOnly, - ) - if sqlTx, err = in.Db.BeginTx(ctx, &in.TxOptions); err == nil { - out.Tx = &TXCore{ - db: c.db, - tx: sqlTx, - ctx: context.WithValue(ctx, transactionIdForLoggerCtx, transactionIdGenerator.Add(1)), - master: in.Db, - transactionId: guid.S(), - cancelFunc: cancelFuncForTimeout, - } - ctx = out.Tx.GetCtx() - } - out.RawResult = sqlTx - - case SqlTypeTXCommit: - if in.TxCancelFunc != nil { - defer in.TxCancelFunc() - } - err = in.Tx.Commit() - - case SqlTypeTXRollback: - if in.TxCancelFunc != nil { - defer in.TxCancelFunc() - } - err = in.Tx.Rollback() - - case SqlTypeExecContext: - ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeExec) - defer cancelFuncForTimeout() - if c.db.GetDryRun() { - sqlResult = new(SqlResult) - } else { - sqlResult, err = in.Link.ExecContext(ctx, in.Sql, in.Args...) - } - out.RawResult = sqlResult - - case SqlTypeQueryContext: - ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery) - defer cancelFuncForTimeout() - sqlRows, err = in.Link.QueryContext(ctx, in.Sql, in.Args...) - out.RawResult = sqlRows - - case SqlTypePrepareContext: - ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypePrepare) - defer cancelFuncForTimeout() - sqlStmt, err = in.Link.PrepareContext(ctx, in.Sql) - out.RawResult = sqlStmt - - case SqlTypeStmtExecContext: - ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeExec) - defer cancelFuncForTimeout() - if c.db.GetDryRun() { - sqlResult = new(SqlResult) - } else { - sqlResult, err = in.Stmt.ExecContext(ctx, in.Args...) - } - out.RawResult = sqlResult - - case SqlTypeStmtQueryContext: - ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery) - defer cancelFuncForTimeout() - stmtSqlRows, err = in.Stmt.QueryContext(ctx, in.Args...) - out.RawResult = stmtSqlRows - - case SqlTypeStmtQueryRowContext: - ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery) - defer cancelFuncForTimeout() - stmtSqlRow = in.Stmt.QueryRowContext(ctx, in.Args...) - out.RawResult = stmtSqlRow - - default: - panic(gerror.NewCodef(gcode.CodeInvalidParameter, `invalid SqlType "%s"`, in.Type)) - } - // Result handling. - switch { - case sqlResult != nil && !c.GetIgnoreResultFromCtx(ctx): - rowsAffected, err = sqlResult.RowsAffected() - out.Result = sqlResult - - case sqlRows != nil: - out.Records, err = c.RowsToResult(ctx, sqlRows) - rowsAffected = int64(len(out.Records)) - - case sqlStmt != nil: - out.Stmt = &Stmt{ - Stmt: sqlStmt, - core: c, - link: in.Link, - sql: in.Sql, - } - } - var ( - timestampMilli2 = gtime.TimestampMilli() - sqlObj = &Sql{ - Sql: in.Sql, - Type: in.Type, - Args: in.Args, - Format: formattedSql, - Error: err, - Start: timestampMilli1, - End: timestampMilli2, - Group: c.db.GetGroup(), - Schema: c.db.GetSchema(), - RowsAffected: rowsAffected, - IsTransaction: in.IsTransaction, - } - ) - - // Tracing. - c.traceSpanEnd(ctx, span, sqlObj) - - // Logging. - if c.db.GetDebug() { - c.writeSqlToLogger(ctx, sqlObj) - } - if err != nil && err != sql.ErrNoRows { - err = gerror.WrapCode( - gcode.CodeDbOperationError, - err, - FormatSqlWithArgs(in.Sql, in.Args), - ) - } - return out, err + var ( + sqlTx *sql.Tx + sqlStmt *sql.Stmt + sqlRows *sql.Rows + sqlResult sql.Result + stmtSqlRows *sql.Rows + stmtSqlRow *sql.Row + rowsAffected int64 + cancelFuncForTimeout context.CancelFunc + formattedSql = FormatSqlWithArgs(in.Sql, in.Args) + timestampMilli1 = gtime.TimestampMilli() + ) + + // Trace span start. + tr := otel.GetTracerProvider().Tracer(traceInstrumentName, trace.WithInstrumentationVersion(gf.VERSION)) + ctx, span := tr.Start(ctx, string(in.Type), trace.WithSpanKind(trace.SpanKindInternal)) + defer span.End() + + // Execution by type. + switch in.Type { + case SqlTypeBegin: + ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeTrans) + formattedSql = fmt.Sprintf( + `%s (IosolationLevel: %s, ReadOnly: %t)`, + formattedSql, in.TxOptions.Isolation.String(), in.TxOptions.ReadOnly, + ) + if sqlTx, err = in.Db.BeginTx(ctx, &in.TxOptions); err == nil { + out.Tx = &TXCore{ + db: c.db, + tx: sqlTx, + ctx: context.WithValue(ctx, transactionIdForLoggerCtx, transactionIdGenerator.Add(1)), + master: in.Db, + transactionId: guid.S(), + cancelFunc: cancelFuncForTimeout, + } + ctx = out.Tx.GetCtx() + } + out.RawResult = sqlTx + + case SqlTypeTXCommit: + if in.TxCancelFunc != nil { + defer in.TxCancelFunc() + } + err = in.Tx.Commit() + + case SqlTypeTXRollback: + if in.TxCancelFunc != nil { + defer in.TxCancelFunc() + } + err = in.Tx.Rollback() + + case SqlTypeExecContext: + ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeExec) + defer cancelFuncForTimeout() + if c.db.GetDryRun() { + sqlResult = new(SqlResult) + } else { + sqlResult, err = in.Link.ExecContext(ctx, in.Sql, in.Args...) + } + out.RawResult = sqlResult + + case SqlTypeQueryContext: + ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery) + defer cancelFuncForTimeout() + sqlRows, err = in.Link.QueryContext(ctx, in.Sql, in.Args...) + out.RawResult = sqlRows + + case SqlTypePrepareContext: + ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypePrepare) + defer cancelFuncForTimeout() + sqlStmt, err = in.Link.PrepareContext(ctx, in.Sql) + out.RawResult = sqlStmt + + case SqlTypeStmtExecContext: + ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeExec) + defer cancelFuncForTimeout() + if c.db.GetDryRun() { + sqlResult = new(SqlResult) + } else { + sqlResult, err = in.Stmt.ExecContext(ctx, in.Args...) + } + out.RawResult = sqlResult + + case SqlTypeStmtQueryContext: + ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery) + defer cancelFuncForTimeout() + stmtSqlRows, err = in.Stmt.QueryContext(ctx, in.Args...) + out.RawResult = stmtSqlRows + + case SqlTypeStmtQueryRowContext: + ctx, cancelFuncForTimeout = c.GetCtxTimeout(ctx, ctxTimeoutTypeQuery) + defer cancelFuncForTimeout() + stmtSqlRow = in.Stmt.QueryRowContext(ctx, in.Args...) + out.RawResult = stmtSqlRow + + default: + panic(gerror.NewCodef(gcode.CodeInvalidParameter, `invalid SqlType "%s"`, in.Type)) + } + // Result handling. + switch { + case sqlResult != nil && !c.GetIgnoreResultFromCtx(ctx): + rowsAffected, err = sqlResult.RowsAffected() + out.Result = sqlResult + + case sqlRows != nil: + out.Records, err = c.RowsToResult(ctx, sqlRows) + rowsAffected = int64(len(out.Records)) + + case sqlStmt != nil: + out.Stmt = &Stmt{ + Stmt: sqlStmt, + core: c, + link: in.Link, + sql: in.Sql, + } + } + var ( + timestampMilli2 = gtime.TimestampMilli() + sqlObj = &Sql{ + Sql: in.Sql, + Type: in.Type, + Args: in.Args, + Format: formattedSql, + Error: err, + Start: timestampMilli1, + End: timestampMilli2, + Group: c.db.GetGroup(), + Schema: c.db.GetSchema(), + RowsAffected: rowsAffected, + IsTransaction: in.IsTransaction, + } + ) + + // Tracing. + c.traceSpanEnd(ctx, span, sqlObj) + + // Logging. + if c.db.GetDebug() { + c.writeSqlToLogger(ctx, sqlObj) + } + if err != nil && err != sql.ErrNoRows { + err = gerror.WrapCode( + gcode.CodeDbOperationError, + err, + FormatSqlWithArgs(in.Sql, in.Args), + ) + } + return out, err } // Prepare creates a prepared statement for later queries or executions. @@ -311,200 +311,200 @@ func (c *Core) DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutp // The parameter `execOnMaster` specifies whether executing the sql on master node, // or else it executes the sql on slave node if master-slave configured. func (c *Core) Prepare(ctx context.Context, sql string, execOnMaster ...bool) (*Stmt, error) { - var ( - err error - link Link - ) - if len(execOnMaster) > 0 && execOnMaster[0] { - if link, err = c.MasterLink(); err != nil { - return nil, err - } - } else { - if link, err = c.SlaveLink(); err != nil { - return nil, err - } - } - return c.db.DoPrepare(ctx, link, sql) + var ( + err error + link Link + ) + if len(execOnMaster) > 0 && execOnMaster[0] { + if link, err = c.MasterLink(); err != nil { + return nil, err + } + } else { + if link, err = c.SlaveLink(); err != nil { + return nil, err + } + } + return c.db.DoPrepare(ctx, link, sql) } // DoPrepare calls prepare function on given link object and returns the statement object. func (c *Core) DoPrepare(ctx context.Context, link Link, sql string) (stmt *Stmt, err error) { - // Transaction checks. - if link == nil { - if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { - // Firstly, check and retrieve transaction link from context. - link = &txLink{tx.GetSqlTX()} - } else { - // Or else it creates one from master node. - if link, err = c.MasterLink(); err != nil { - return nil, err - } - } - } else if !link.IsTransaction() { - // If current link is not transaction link, it checks and retrieves transaction from context. - if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { - link = &txLink{tx.GetSqlTX()} - } - } - - if c.db.GetConfig().PrepareTimeout > 0 { - // DO NOT USE cancel function in prepare statement. - var cancelFunc context.CancelFunc - ctx, cancelFunc = context.WithTimeout(ctx, c.db.GetConfig().PrepareTimeout) - defer cancelFunc() - } - - // Link execution. - var out DoCommitOutput - out, err = c.db.DoCommit(ctx, DoCommitInput{ - Link: link, - Sql: sql, - Type: SqlTypePrepareContext, - IsTransaction: link.IsTransaction(), - }) - if err != nil { - return nil, err - } - return out.Stmt, err + // Transaction checks. + if link == nil { + if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { + // Firstly, check and retrieve transaction link from context. + link = &txLink{tx.GetSqlTX()} + } else { + // Or else it creates one from master node. + if link, err = c.MasterLink(); err != nil { + return nil, err + } + } + } else if !link.IsTransaction() { + // If current link is not transaction link, it checks and retrieves transaction from context. + if tx := TXFromCtx(ctx, c.db.GetGroup()); tx != nil { + link = &txLink{tx.GetSqlTX()} + } + } + + if c.db.GetConfig().PrepareTimeout > 0 { + // DO NOT USE cancel function in prepare statement. + var cancelFunc context.CancelFunc + ctx, cancelFunc = context.WithTimeout(ctx, c.db.GetConfig().PrepareTimeout) + defer cancelFunc() + } + + // Link execution. + var out DoCommitOutput + out, err = c.db.DoCommit(ctx, DoCommitInput{ + Link: link, + Sql: sql, + Type: SqlTypePrepareContext, + IsTransaction: link.IsTransaction(), + }) + if err != nil { + return nil, err + } + return out.Stmt, err } // FormatUpsert formats and returns SQL clause part for upsert statement. // In default implements, this function performs upsert statement for MySQL like: // `INSERT INTO ... ON DUPLICATE KEY UPDATE x=VALUES(z),m=VALUES(y)...` func (c *Core) FormatUpsert(columns []string, list List, option DoInsertOption) (string, error) { - var onDuplicateStr string - if option.OnDuplicateStr != "" { - onDuplicateStr = option.OnDuplicateStr - } else if len(option.OnDuplicateMap) > 0 { - for k, v := range option.OnDuplicateMap { - if len(onDuplicateStr) > 0 { - onDuplicateStr += "," - } - switch v.(type) { - case Raw, *Raw: - onDuplicateStr += fmt.Sprintf( - "%s=%s", - c.QuoteWord(k), - v, - ) - default: - onDuplicateStr += fmt.Sprintf( - "%s=VALUES(%s)", - c.QuoteWord(k), - c.QuoteWord(gconv.String(v)), - ) - } - } - } else { - for _, column := range columns { - // If it's `SAVE` operation, do not automatically update the creating time. - if c.IsSoftCreatedFieldName(column) { - continue - } - if len(onDuplicateStr) > 0 { - onDuplicateStr += "," - } - onDuplicateStr += fmt.Sprintf( - "%s=VALUES(%s)", - c.QuoteWord(column), - c.QuoteWord(column), - ) - } - } - - return InsertOnDuplicateKeyUpdate + " " + onDuplicateStr, nil + var onDuplicateStr string + if option.OnDuplicateStr != "" { + onDuplicateStr = option.OnDuplicateStr + } else if len(option.OnDuplicateMap) > 0 { + for k, v := range option.OnDuplicateMap { + if len(onDuplicateStr) > 0 { + onDuplicateStr += "," + } + switch v.(type) { + case Raw, *Raw: + onDuplicateStr += fmt.Sprintf( + "%s=%s", + c.QuoteWord(k), + v, + ) + default: + onDuplicateStr += fmt.Sprintf( + "%s=VALUES(%s)", + c.QuoteWord(k), + c.QuoteWord(gconv.String(v)), + ) + } + } + } else { + for _, column := range columns { + // If it's `SAVE` operation, do not automatically update the creating time. + if c.IsSoftCreatedFieldName(column) { + continue + } + if len(onDuplicateStr) > 0 { + onDuplicateStr += "," + } + onDuplicateStr += fmt.Sprintf( + "%s=VALUES(%s)", + c.QuoteWord(column), + c.QuoteWord(column), + ) + } + } + + return InsertOnDuplicateKeyUpdate + " " + onDuplicateStr, nil } // RowsToResult converts underlying data record type sql.Rows to Result type. func (c *Core) RowsToResult(ctx context.Context, rows *sql.Rows) (Result, error) { - if rows == nil { - return nil, nil - } - defer func() { - if err := rows.Close(); err != nil { - intlog.Errorf(ctx, `%+v`, err) - } - }() - if !rows.Next() { - return nil, nil - } - // Column names and types. - columnTypes, err := rows.ColumnTypes() - if err != nil { - return nil, err - } - - if len(columnTypes) > 0 { - if internalData := c.getInternalColumnFromCtx(ctx); internalData != nil { - internalData.FirstResultColumn = columnTypes[0].Name() - } - } - var ( - values = make([]interface{}, len(columnTypes)) - result = make(Result, 0) - scanArgs = make([]interface{}, len(values)) - ) - for i := range values { - scanArgs[i] = &values[i] - } - for { - if err = rows.Scan(scanArgs...); err != nil { - return result, err - } - record := Record{} - for i, value := range values { - if value == nil { - // DO NOT use `gvar.New(nil)` here as it creates an initialized object - // which will cause struct converting issue. - record[columnTypes[i].Name()] = nil - } else { - var ( - convertedValue interface{} - columnType = columnTypes[i] - localType = LocalTypeUndefined - ) - if convertedValue, err = c.columnValueToLocalValue(ctx, value, columnType); err != nil { - return nil, err - } - localType, err = c.db.CheckLocalTypeForField(ctx, columnType.DatabaseTypeName(), value) - if err != nil { - return nil, err - } - record[columnTypes[i].Name()] = NewValueWithType(convertedValue, localType) - } - } - result = append(result, record) - if !rows.Next() { - break - } - } - return result, nil + if rows == nil { + return nil, nil + } + defer func() { + if err := rows.Close(); err != nil { + intlog.Errorf(ctx, `%+v`, err) + } + }() + if !rows.Next() { + return nil, nil + } + // Column names and types. + columnTypes, err := rows.ColumnTypes() + if err != nil { + return nil, err + } + + if len(columnTypes) > 0 { + if internalData := c.getInternalColumnFromCtx(ctx); internalData != nil { + internalData.FirstResultColumn = columnTypes[0].Name() + } + } + var ( + values = make([]interface{}, len(columnTypes)) + result = make(Result, 0) + scanArgs = make([]interface{}, len(values)) + ) + for i := range values { + scanArgs[i] = &values[i] + } + for { + if err = rows.Scan(scanArgs...); err != nil { + return result, err + } + record := Record{} + for i, value := range values { + if value == nil { + // DO NOT use `gvar.New(nil)` here as it creates an initialized object + // which will cause struct converting issue. + record[columnTypes[i].Name()] = nil + } else { + var ( + convertedValue interface{} + columnType = columnTypes[i] + localType = LocalTypeUndefined + ) + if convertedValue, err = c.columnValueToLocalValue(ctx, value, columnType); err != nil { + return nil, err + } + localType, err = c.db.CheckLocalTypeForField(ctx, columnType.DatabaseTypeName(), value) + if err != nil { + return nil, err + } + record[columnTypes[i].Name()] = NewValueWithType(convertedValue, localType) + } + } + result = append(result, record) + if !rows.Next() { + break + } + } + return result, nil } // OrderRandomFunction returns the SQL function for random ordering. func (c *Core) OrderRandomFunction() string { - return "RAND()" + return "RAND()" } func (c *Core) columnValueToLocalValue( - ctx context.Context, value interface{}, columnType *sql.ColumnType, + ctx context.Context, value interface{}, columnType *sql.ColumnType, ) (interface{}, error) { - var scanType = columnType.ScanType() - if scanType != nil { - // Common basic builtin types. - switch scanType.Kind() { - case - reflect.Bool, - reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, - reflect.Float32, reflect.Float64: - return gconv.Convert( - gconv.String(value), - columnType.ScanType().String(), - ), nil - default: - } - } - // Other complex types, especially custom types. - return c.db.ConvertValueForLocal(ctx, columnType.DatabaseTypeName(), value) + var scanType = columnType.ScanType() + if scanType != nil { + // Common basic builtin types. + switch scanType.Kind() { + case + reflect.Bool, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64: + return gconv.Convert( + gconv.String(value), + columnType.ScanType().String(), + ), nil + default: + } + } + // Other complex types, especially custom types. + return c.db.ConvertValueForLocal(ctx, columnType.DatabaseTypeName(), value) } diff --git a/database/gdb/gdb_type_result.go b/database/gdb/gdb_type_result.go index 5ebce52d2c1..48775759f5d 100644 --- a/database/gdb/gdb_type_result.go +++ b/database/gdb/gdb_type_result.go @@ -7,199 +7,199 @@ package gdb import ( - "database/sql" - "math" + "database/sql" + "math" - "github.com/gogf/gf/v2/encoding/gjson" - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/util/gconv" ) // IsEmpty checks and returns whether `r` is empty. func (r Result) IsEmpty() bool { - return r == nil || r.Len() == 0 + return r == nil || r.Len() == 0 } // Len returns the length of result list. func (r Result) Len() int { - return len(r) + return len(r) } // Size is alias of function Len. func (r Result) Size() int { - return r.Len() + return r.Len() } // Chunk splits a Result into multiple Results, // the size of each array is determined by `size`. // The last chunk may contain less than size elements. func (r Result) Chunk(size int) []Result { - if size < 1 { - return nil - } - length := len(r) - chunks := int(math.Ceil(float64(length) / float64(size))) - var n []Result - for i, end := 0, 0; chunks > 0; chunks-- { - end = (i + 1) * size - if end > length { - end = length - } - n = append(n, r[i*size:end]) - i++ - } - return n + if size < 1 { + return nil + } + length := len(r) + chunks := int(math.Ceil(float64(length) / float64(size))) + var n []Result + for i, end := 0, 0; chunks > 0; chunks-- { + end = (i + 1) * size + if end > length { + end = length + } + n = append(n, r[i*size:end]) + i++ + } + return n } // Json converts `r` to JSON format content. func (r Result) Json() string { - content, _ := gjson.New(r.List()).ToJsonString() - return content + content, _ := gjson.New(r.List()).ToJsonString() + return content } // Xml converts `r` to XML format content. func (r Result) Xml(rootTag ...string) string { - content, _ := gjson.New(r.List()).ToXmlString(rootTag...) - return content + content, _ := gjson.New(r.List()).ToXmlString(rootTag...) + return content } // List converts `r` to a List. func (r Result) List() List { - list := make(List, len(r)) - for k, v := range r { - list[k] = v.Map() - } - return list + list := make(List, len(r)) + for k, v := range r { + list[k] = v.Map() + } + return list } // Array retrieves and returns specified column values as slice. // The parameter `field` is optional is the column field is only one. // The default `field` is the first field name of the first item in `Result` if parameter `field` is not given. func (r Result) Array(field ...string) []Value { - array := make([]Value, len(r)) - if len(r) == 0 { - return array - } - key := "" - if len(field) > 0 && field[0] != "" { - key = field[0] - } else { - for k := range r[0] { - key = k - break - } - } - for k, v := range r { - array[k] = v[key] - } - return array + array := make([]Value, len(r)) + if len(r) == 0 { + return array + } + key := "" + if len(field) > 0 && field[0] != "" { + key = field[0] + } else { + for k := range r[0] { + key = k + break + } + } + for k, v := range r { + array[k] = v[key] + } + return array } // MapKeyValue converts `r` to a map[string]Value of which key is specified by `key`. // Note that the item value may be type of slice. func (r Result) MapKeyValue(key string) map[string]Value { - var ( - s string - m = make(map[string]Value) - tempMap = make(map[string][]interface{}) - localType LocalType - hasMultiValues bool - ) - for _, item := range r { - if k, ok := item[key]; ok { - s = k.String() - localType = k.LocalType() - tempMap[s] = append(tempMap[s], item) - if len(tempMap[s]) > 1 { - hasMultiValues = true - } - } - } - for k, v := range tempMap { - if hasMultiValues { - m[k] = NewValue(v) - } else { - m[k] = NewValueWithType(v[0], localType) - } - } - return m + var ( + s string + m = make(map[string]Value) + tempMap = make(map[string][]interface{}) + localType LocalType + hasMultiValues bool + ) + for _, item := range r { + if k, ok := item[key]; ok { + s = k.String() + localType = k.LocalType() + tempMap[s] = append(tempMap[s], item) + if len(tempMap[s]) > 1 { + hasMultiValues = true + } + } + } + for k, v := range tempMap { + if hasMultiValues { + m[k] = NewValue(v) + } else { + m[k] = NewValueWithType(v[0], localType) + } + } + return m } // MapKeyStr converts `r` to a map[string]Map of which key is specified by `key`. func (r Result) MapKeyStr(key string) map[string]Map { - m := make(map[string]Map) - for _, item := range r { - if v, ok := item[key]; ok { - m[v.String()] = item.Map() - } - } - return m + m := make(map[string]Map) + for _, item := range r { + if v, ok := item[key]; ok { + m[v.String()] = item.Map() + } + } + return m } // MapKeyInt converts `r` to a map[int]Map of which key is specified by `key`. func (r Result) MapKeyInt(key string) map[int]Map { - m := make(map[int]Map) - for _, item := range r { - if v, ok := item[key]; ok { - m[v.Int()] = item.Map() - } - } - return m + m := make(map[int]Map) + for _, item := range r { + if v, ok := item[key]; ok { + m[v.Int()] = item.Map() + } + } + return m } // MapKeyUint converts `r` to a map[uint]Map of which key is specified by `key`. func (r Result) MapKeyUint(key string) map[uint]Map { - m := make(map[uint]Map) - for _, item := range r { - if v, ok := item[key]; ok { - m[v.Uint()] = item.Map() - } - } - return m + m := make(map[uint]Map) + for _, item := range r { + if v, ok := item[key]; ok { + m[v.Uint()] = item.Map() + } + } + return m } // RecordKeyStr converts `r` to a map[string]Record of which key is specified by `key`. func (r Result) RecordKeyStr(key string) map[string]Record { - m := make(map[string]Record) - for _, item := range r { - if v, ok := item[key]; ok { - m[v.String()] = item - } - } - return m + m := make(map[string]Record) + for _, item := range r { + if v, ok := item[key]; ok { + m[v.String()] = item + } + } + return m } // RecordKeyInt converts `r` to a map[int]Record of which key is specified by `key`. func (r Result) RecordKeyInt(key string) map[int]Record { - m := make(map[int]Record) - for _, item := range r { - if v, ok := item[key]; ok { - m[v.Int()] = item - } - } - return m + m := make(map[int]Record) + for _, item := range r { + if v, ok := item[key]; ok { + m[v.Int()] = item + } + } + return m } // RecordKeyUint converts `r` to a map[uint]Record of which key is specified by `key`. func (r Result) RecordKeyUint(key string) map[uint]Record { - m := make(map[uint]Record) - for _, item := range r { - if v, ok := item[key]; ok { - m[v.Uint()] = item - } - } - return m + m := make(map[uint]Record) + for _, item := range r { + if v, ok := item[key]; ok { + m[v.Uint()] = item + } + } + return m } // Structs converts `r` to struct slice. // Note that the parameter `pointer` should be type of *[]struct/*[]*struct. func (r Result) Structs(pointer interface{}) (err error) { - // If the result is empty and the target pointer is not empty, it returns error. - if r.IsEmpty() { - if !empty.IsEmpty(pointer, true) { - return sql.ErrNoRows - } - return nil - } - return gconv.StructsTag(r, pointer, OrmTagForStruct) + // If the result is empty and the target pointer is not empty, it returns error. + if r.IsEmpty() { + if !empty.IsEmpty(pointer, true) { + return sql.ErrNoRows + } + return nil + } + return gconv.StructsTag(r, pointer, OrmTagForStruct) } diff --git a/database/gdb/gdb_type_value.go b/database/gdb/gdb_type_value.go index 4945e7c59d9..0a8f119b022 100644 --- a/database/gdb/gdb_type_value.go +++ b/database/gdb/gdb_type_value.go @@ -10,10 +10,10 @@ import "github.com/gogf/gf/v2/database/gdb/internal/fieldvar" // NewValue creates and returns a new Value object. func NewValue(value any) Value { - return fieldvar.New(value) + return fieldvar.New(value) } // NewValueWithType creates and returns a new Value object with specified local type. func NewValueWithType(value any, localType LocalType) Value { - return fieldvar.NewWithType(value, localType) + return fieldvar.NewWithType(value, localType) } diff --git a/database/gdb/internal/fieldvar/fieldvar_basic.go b/database/gdb/internal/fieldvar/fieldvar_basic.go index 75b91458176..a1750204dd3 100644 --- a/database/gdb/internal/fieldvar/fieldvar_basic.go +++ b/database/gdb/internal/fieldvar/fieldvar_basic.go @@ -7,93 +7,93 @@ package fieldvar import ( - "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/gconv" ) // Val returns the current value of `v`. func (v *Var) Val() interface{} { - if v == nil { - return nil - } - return v.value + if v == nil { + return nil + } + return v.value } // Interface is alias of Val. func (v *Var) Interface() interface{} { - return v.Val() + return v.Val() } // Bytes converts and returns `v` as []byte. func (v *Var) Bytes() []byte { - return gconv.Bytes(v.Val()) + return gconv.Bytes(v.Val()) } // String converts and returns `v` as string. func (v *Var) String() string { - return gconv.String(v.Val()) + return gconv.String(v.Val()) } // Bool converts and returns `v` as bool. func (v *Var) Bool() bool { - return gconv.Bool(v.Val()) + return gconv.Bool(v.Val()) } // Int converts and returns `v` as int. func (v *Var) Int() int { - return gconv.Int(v.Val()) + return gconv.Int(v.Val()) } // Int8 converts and returns `v` as int8. func (v *Var) Int8() int8 { - return gconv.Int8(v.Val()) + return gconv.Int8(v.Val()) } // Int16 converts and returns `v` as int16. func (v *Var) Int16() int16 { - return gconv.Int16(v.Val()) + return gconv.Int16(v.Val()) } // Int32 converts and returns `v` as int32. func (v *Var) Int32() int32 { - return gconv.Int32(v.Val()) + return gconv.Int32(v.Val()) } // Int64 converts and returns `v` as int64. func (v *Var) Int64() int64 { - return gconv.Int64(v.Val()) + return gconv.Int64(v.Val()) } // Uint converts and returns `v` as uint. func (v *Var) Uint() uint { - return gconv.Uint(v.Val()) + return gconv.Uint(v.Val()) } // Uint8 converts and returns `v` as uint8. func (v *Var) Uint8() uint8 { - return gconv.Uint8(v.Val()) + return gconv.Uint8(v.Val()) } // Uint16 converts and returns `v` as uint16. func (v *Var) Uint16() uint16 { - return gconv.Uint16(v.Val()) + return gconv.Uint16(v.Val()) } // Uint32 converts and returns `v` as uint32. func (v *Var) Uint32() uint32 { - return gconv.Uint32(v.Val()) + return gconv.Uint32(v.Val()) } // Uint64 converts and returns `v` as uint64. func (v *Var) Uint64() uint64 { - return gconv.Uint64(v.Val()) + return gconv.Uint64(v.Val()) } // Float32 converts and returns `v` as float32. func (v *Var) Float32() float32 { - return gconv.Float32(v.Val()) + return gconv.Float32(v.Val()) } // Float64 converts and returns `v` as float64. func (v *Var) Float64() float64 { - return gconv.Float64(v.Val()) + return gconv.Float64(v.Val()) } diff --git a/database/gdb/internal/fieldvar/fieldvar_copy.go b/database/gdb/internal/fieldvar/fieldvar_copy.go index 4698a9a881b..38bc00da3bc 100644 --- a/database/gdb/internal/fieldvar/fieldvar_copy.go +++ b/database/gdb/internal/fieldvar/fieldvar_copy.go @@ -7,24 +7,24 @@ package fieldvar import ( - "github.com/gogf/gf/v2/internal/deepcopy" - "github.com/gogf/gf/v2/util/gutil" + "github.com/gogf/gf/v2/internal/deepcopy" + "github.com/gogf/gf/v2/util/gutil" ) // Copy does a deep copy of current Var and returns a pointer to this Var. func (v *Var) Copy() *Var { - return NewWithType(gutil.Copy(v.Val()), v.localType) + return NewWithType(gutil.Copy(v.Val()), v.localType) } // Clone does a shallow copy of current Var and returns a pointer to this Var. func (v *Var) Clone() *Var { - return NewWithType(v.Val(), v.localType) + return NewWithType(v.Val(), v.localType) } // DeepCopy implements interface for deep copy of current type. func (v *Var) DeepCopy() interface{} { - if v == nil { - return nil - } - return NewWithType(deepcopy.Copy(v.Val()), v.localType) + if v == nil { + return nil + } + return NewWithType(deepcopy.Copy(v.Val()), v.localType) } diff --git a/database/gdb/internal/fieldvar/fieldvar_map.go b/database/gdb/internal/fieldvar/fieldvar_map.go index a70d6c84afa..ab96919da8a 100644 --- a/database/gdb/internal/fieldvar/fieldvar_map.go +++ b/database/gdb/internal/fieldvar/fieldvar_map.go @@ -13,53 +13,53 @@ type MapOption = gconv.MapOption // Map converts and returns `v` as map[string]interface{}. func (v *Var) Map(option ...MapOption) map[string]interface{} { - return gconv.Map(v.Val(), option...) + return gconv.Map(v.Val(), option...) } // MapStrAny is like function Map, but implements the interface of MapStrAny. func (v *Var) MapStrAny(option ...MapOption) map[string]interface{} { - return v.Map(option...) + return v.Map(option...) } // MapStrStr converts and returns `v` as map[string]string. func (v *Var) MapStrStr(option ...MapOption) map[string]string { - return gconv.MapStrStr(v.Val(), option...) + return gconv.MapStrStr(v.Val(), option...) } // MapStrVar converts and returns `v` as map[string]Var. func (v *Var) MapStrVar(option ...MapOption) map[string]*Var { - m := v.Map(option...) - if len(m) > 0 { - vMap := make(map[string]*Var, len(m)) - for k, v := range m { - vMap[k] = New(v) - } - return vMap - } - return nil + m := v.Map(option...) + if len(m) > 0 { + vMap := make(map[string]*Var, len(m)) + for k, v := range m { + vMap[k] = New(v) + } + return vMap + } + return nil } // Maps converts and returns `v` as map[string]string. // See gconv.Maps. func (v *Var) Maps(option ...MapOption) []map[string]interface{} { - return gconv.Maps(v.Val(), option...) + return gconv.Maps(v.Val(), option...) } // MapToMap converts any map type variable `params` to another map type variable `pointer`. // See gconv.MapToMap. func (v *Var) MapToMap(pointer interface{}, mapping ...map[string]string) (err error) { - return gconv.MapToMap(v.Val(), pointer, mapping...) + return gconv.MapToMap(v.Val(), pointer, mapping...) } // MapToMaps converts any map type variable `params` to another map type variable `pointer`. // See gconv.MapToMaps. func (v *Var) MapToMaps(pointer interface{}, mapping ...map[string]string) (err error) { - return gconv.MapToMaps(v.Val(), pointer, mapping...) + return gconv.MapToMaps(v.Val(), pointer, mapping...) } // MapToMapsDeep converts any map type variable `params` to another map type variable // `pointer` recursively. // See gconv.MapToMapsDeep. func (v *Var) MapToMapsDeep(pointer interface{}, mapping ...map[string]string) (err error) { - return gconv.MapToMaps(v.Val(), pointer, mapping...) + return gconv.MapToMaps(v.Val(), pointer, mapping...) } diff --git a/database/gdb/internal/fieldvar/fieldvar_slice.go b/database/gdb/internal/fieldvar/fieldvar_slice.go index 6659d7b9a8e..b418e27141c 100644 --- a/database/gdb/internal/fieldvar/fieldvar_slice.go +++ b/database/gdb/internal/fieldvar/fieldvar_slice.go @@ -7,80 +7,80 @@ package fieldvar import ( - "github.com/gogf/gf/v2/database/gdb/internal/defines" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/database/gdb/internal/defines" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/util/gconv" ) // Ints converts and returns `v` as []int. func (v *Var) Ints() []int { - return gconv.Ints(v.Val()) + return gconv.Ints(v.Val()) } // Int64s converts and returns `v` as []int64. func (v *Var) Int64s() []int64 { - return gconv.Int64s(v.Val()) + return gconv.Int64s(v.Val()) } // Uints converts and returns `v` as []uint. func (v *Var) Uints() []uint { - return gconv.Uints(v.Val()) + return gconv.Uints(v.Val()) } // Uint64s converts and returns `v` as []uint64. func (v *Var) Uint64s() []uint64 { - return gconv.Uint64s(v.Val()) + return gconv.Uint64s(v.Val()) } // Floats is alias of Float64s. func (v *Var) Floats() []float64 { - return gconv.Floats(v.Val()) + return gconv.Floats(v.Val()) } // Float32s converts and returns `v` as []float32. func (v *Var) Float32s() []float32 { - return gconv.Float32s(v.Val()) + return gconv.Float32s(v.Val()) } // Float64s converts and returns `v` as []float64. func (v *Var) Float64s() []float64 { - return gconv.Float64s(v.Val()) + return gconv.Float64s(v.Val()) } // Strings converts and returns `v` as []string. func (v *Var) Strings() []string { - if v.localType == defines.LocalTypeJson { - var s []string - _ = json.Unmarshal(v.Bytes(), &s) - return s - } - return gconv.Strings(v.Val()) + if v.localType == defines.LocalTypeJson { + var s []string + _ = json.Unmarshal(v.Bytes(), &s) + return s + } + return gconv.Strings(v.Val()) } // Interfaces converts and returns `v` as []interfaces{}. func (v *Var) Interfaces() []interface{} { - return gconv.Interfaces(v.Val()) + return gconv.Interfaces(v.Val()) } // Slice is alias of Interfaces. func (v *Var) Slice() []interface{} { - return v.Interfaces() + return v.Interfaces() } // Array is alias of Interfaces. func (v *Var) Array() []interface{} { - return v.Interfaces() + return v.Interfaces() } // Vars converts and returns `v` as []Var. func (v *Var) Vars() []*Var { - array := gconv.Interfaces(v.Val()) - if len(array) == 0 { - return nil - } - vars := make([]*Var, len(array)) - for k, v := range array { - vars[k] = New(v) - } - return vars + array := gconv.Interfaces(v.Val()) + if len(array) == 0 { + return nil + } + vars := make([]*Var, len(array)) + for k, v := range array { + vars[k] = New(v) + } + return vars } diff --git a/database/gdb/internal/fieldvar/fieldvar_struct.go b/database/gdb/internal/fieldvar/fieldvar_struct.go index 904f48e32fc..930cc474be2 100644 --- a/database/gdb/internal/fieldvar/fieldvar_struct.go +++ b/database/gdb/internal/fieldvar/fieldvar_struct.go @@ -7,17 +7,17 @@ package fieldvar import ( - "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/gconv" ) // Struct maps value of `v` to `pointer`. // The parameter `pointer` should be a pointer to a struct instance. // The parameter `mapping` is used to specify the key-to-attribute mapping rules. func (v *Var) Struct(pointer interface{}, mapping ...map[string]string) error { - return gconv.Struct(v.Val(), pointer, mapping...) + return gconv.Struct(v.Val(), pointer, mapping...) } // Structs converts and returns `v` as given struct slice. func (v *Var) Structs(pointer interface{}, mapping ...map[string]string) error { - return gconv.Structs(v.Val(), pointer, mapping...) + return gconv.Structs(v.Val(), pointer, mapping...) } diff --git a/database/gdb/internal/fieldvar/fieldvar_time.go b/database/gdb/internal/fieldvar/fieldvar_time.go index 4a8bf30c6d6..8939009c8d9 100644 --- a/database/gdb/internal/fieldvar/fieldvar_time.go +++ b/database/gdb/internal/fieldvar/fieldvar_time.go @@ -7,28 +7,28 @@ package fieldvar import ( - "time" + "time" - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv" ) // Time converts and returns `v` as time.Time. // The parameter `format` specifies the format of the time string using gtime, // Example: Y-m-d H:i:s. func (v *Var) Time(format ...string) time.Time { - return gconv.Time(v.Val(), format...) + return gconv.Time(v.Val(), format...) } // Duration converts and returns `v` as time.Duration. // If value of `v` is string, then it uses time.ParseDuration for conversion. func (v *Var) Duration() time.Duration { - return gconv.Duration(v.Val()) + return gconv.Duration(v.Val()) } // GTime converts and returns `v` as *gtime.Time. // The parameter `format` specifies the format of the time string using gtime, // Example: Y-m-d H:i:s. func (v *Var) GTime(format ...string) *gtime.Time { - return gconv.GTime(v.Val(), format...) + return gconv.GTime(v.Val(), format...) } From 5fd10645715d12a5264bc5654d20be52cd4076f0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 9 Jan 2025 04:07:31 +0000 Subject: [PATCH 03/48] Apply gci import order changes --- .../mysql/mysql_z_unit_feature_hook_test.go | 210 +- .../mysql_z_unit_feature_model_struct_test.go | 848 +- .../drivers/mysql/mysql_z_unit_issue_test.go | 3104 ++++---- .../drivers/mysql/mysql_z_unit_model_test.go | 6898 ++++++++--------- contrib/drivers/pgsql/pgsql_convert.go | 220 +- 5 files changed, 5640 insertions(+), 5640 deletions(-) diff --git a/contrib/drivers/mysql/mysql_z_unit_feature_hook_test.go b/contrib/drivers/mysql/mysql_z_unit_feature_hook_test.go index 4c97ab83c50..4d91ca8ae04 100644 --- a/contrib/drivers/mysql/mysql_z_unit_feature_hook_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_feature_hook_test.go @@ -7,129 +7,129 @@ package mysql_test import ( - "context" - "database/sql" - "fmt" - "testing" + "context" + "database/sql" + "fmt" + "testing" - "github.com/gogf/gf/v2/database/gdb" - "github.com/gogf/gf/v2/frame/g" - "github.com/gogf/gf/v2/test/gtest" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/test/gtest" ) func Test_Model_Hook_Select(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - m := db.Model(table).Hook(gdb.HookHandler{ - Select: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) { - result, err = in.Next(ctx) - if err != nil { - return - } - for i, record := range result { - record["test"] = gdb.NewValue(100 + record["id"].Int()) - result[i] = record - } - return - }, - }) - all, err := m.Where(`id > 6`).OrderAsc(`id`).All() - t.AssertNil(err) - t.Assert(len(all), 4) - t.Assert(all[0]["id"].Int(), 7) - t.Assert(all[0]["test"].Int(), 107) - t.Assert(all[1]["test"].Int(), 108) - t.Assert(all[2]["test"].Int(), 109) - t.Assert(all[3]["test"].Int(), 110) - }) + gtest.C(t, func(t *gtest.T) { + m := db.Model(table).Hook(gdb.HookHandler{ + Select: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) { + result, err = in.Next(ctx) + if err != nil { + return + } + for i, record := range result { + record["test"] = gdb.NewValue(100 + record["id"].Int()) + result[i] = record + } + return + }, + }) + all, err := m.Where(`id > 6`).OrderAsc(`id`).All() + t.AssertNil(err) + t.Assert(len(all), 4) + t.Assert(all[0]["id"].Int(), 7) + t.Assert(all[0]["test"].Int(), 107) + t.Assert(all[1]["test"].Int(), 108) + t.Assert(all[2]["test"].Int(), 109) + t.Assert(all[3]["test"].Int(), 110) + }) } func Test_Model_Hook_Insert(t *testing.T) { - table := createTable() - defer dropTable(table) + table := createTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - m := db.Model(table).Hook(gdb.HookHandler{ - Insert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) { - for i, item := range in.Data { - item["passport"] = fmt.Sprintf(`test_port_%d`, item["id"]) - item["nickname"] = fmt.Sprintf(`test_name_%d`, item["id"]) - in.Data[i] = item - } - return in.Next(ctx) - }, - }) - _, err := m.Insert(g.Map{ - "id": 1, - "nickname": "name_1", - }) - t.AssertNil(err) - one, err := m.One() - t.AssertNil(err) - t.Assert(one["id"].Int(), 1) - t.Assert(one["passport"], `test_port_1`) - t.Assert(one["nickname"], `test_name_1`) - }) + gtest.C(t, func(t *gtest.T) { + m := db.Model(table).Hook(gdb.HookHandler{ + Insert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) { + for i, item := range in.Data { + item["passport"] = fmt.Sprintf(`test_port_%d`, item["id"]) + item["nickname"] = fmt.Sprintf(`test_name_%d`, item["id"]) + in.Data[i] = item + } + return in.Next(ctx) + }, + }) + _, err := m.Insert(g.Map{ + "id": 1, + "nickname": "name_1", + }) + t.AssertNil(err) + one, err := m.One() + t.AssertNil(err) + t.Assert(one["id"].Int(), 1) + t.Assert(one["passport"], `test_port_1`) + t.Assert(one["nickname"], `test_name_1`) + }) } func Test_Model_Hook_Update(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - m := db.Model(table).Hook(gdb.HookHandler{ - Update: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) { - switch value := in.Data.(type) { - case gdb.List: - for i, data := range value { - data["passport"] = `port` - data["nickname"] = `name` - value[i] = data - } - in.Data = value + gtest.C(t, func(t *gtest.T) { + m := db.Model(table).Hook(gdb.HookHandler{ + Update: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) { + switch value := in.Data.(type) { + case gdb.List: + for i, data := range value { + data["passport"] = `port` + data["nickname"] = `name` + value[i] = data + } + in.Data = value - case gdb.Map: - value["passport"] = `port` - value["nickname"] = `name` - in.Data = value - } - return in.Next(ctx) - }, - }) - _, err := m.Data(g.Map{ - "nickname": "name_1", - }).WherePri(1).Update() - t.AssertNil(err) + case gdb.Map: + value["passport"] = `port` + value["nickname"] = `name` + in.Data = value + } + return in.Next(ctx) + }, + }) + _, err := m.Data(g.Map{ + "nickname": "name_1", + }).WherePri(1).Update() + t.AssertNil(err) - one, err := m.One() - t.AssertNil(err) - t.Assert(one["id"].Int(), 1) - t.Assert(one["passport"], `port`) - t.Assert(one["nickname"], `name`) - }) + one, err := m.One() + t.AssertNil(err) + t.Assert(one["id"].Int(), 1) + t.Assert(one["passport"], `port`) + t.Assert(one["nickname"], `name`) + }) } func Test_Model_Hook_Delete(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - m := db.Model(table).Hook(gdb.HookHandler{ - Delete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) { - return db.Model(table).Data(g.Map{ - "nickname": `deleted`, - }).Where(in.Condition).Update() - }, - }) - _, err := m.Where(1).Delete() - t.AssertNil(err) + gtest.C(t, func(t *gtest.T) { + m := db.Model(table).Hook(gdb.HookHandler{ + Delete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) { + return db.Model(table).Data(g.Map{ + "nickname": `deleted`, + }).Where(in.Condition).Update() + }, + }) + _, err := m.Where(1).Delete() + t.AssertNil(err) - all, err := m.All() - t.AssertNil(err) - for _, item := range all { - t.Assert(item["nickname"].String(), `deleted`) - } - }) + all, err := m.All() + t.AssertNil(err) + for _, item := range all { + t.Assert(item["nickname"].String(), `deleted`) + } + }) } diff --git a/contrib/drivers/mysql/mysql_z_unit_feature_model_struct_test.go b/contrib/drivers/mysql/mysql_z_unit_feature_model_struct_test.go index edf594d9674..1463c4080db 100644 --- a/contrib/drivers/mysql/mysql_z_unit_feature_model_struct_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_feature_model_struct_test.go @@ -7,476 +7,476 @@ package mysql_test import ( - "database/sql" - "reflect" - "testing" - - "github.com/gogf/gf/v2/database/gdb" - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/frame/g" - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/test/gtest" - "github.com/gogf/gf/v2/util/gconv" + "database/sql" + "reflect" + "testing" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/test/gtest" + "github.com/gogf/gf/v2/util/gconv" ) func Test_Model_Embedded_Insert(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type Base struct { - Id int `json:"id"` - Uid int `json:"uid"` - CreateTime string `json:"create_time"` - } - type User struct { - Base - Passport string `json:"passport"` - Password string `json:"password"` - Nickname string `json:"nickname"` - } - result, err := db.Model(table).Data(User{ - Passport: "john-test", - Password: "123456", - Nickname: "John", - Base: Base{ - Id: 100, - Uid: 100, - CreateTime: gtime.Now().String(), - }, - }).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - value, err := db.Model(table).Fields("passport").Where("id=100").Value() - t.AssertNil(err) - t.Assert(value.String(), "john-test") - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type Base struct { + Id int `json:"id"` + Uid int `json:"uid"` + CreateTime string `json:"create_time"` + } + type User struct { + Base + Passport string `json:"passport"` + Password string `json:"password"` + Nickname string `json:"nickname"` + } + result, err := db.Model(table).Data(User{ + Passport: "john-test", + Password: "123456", + Nickname: "John", + Base: Base{ + Id: 100, + Uid: 100, + CreateTime: gtime.Now().String(), + }, + }).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + value, err := db.Model(table).Fields("passport").Where("id=100").Value() + t.AssertNil(err) + t.Assert(value.String(), "john-test") + }) } func Test_Model_Embedded_MapToStruct(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type Ids struct { - Id int `json:"id"` - Uid int `json:"uid"` - } - type Base struct { - Ids - CreateTime string `json:"create_time"` - } - type User struct { - Base - Passport string `json:"passport"` - Password string `json:"password"` - Nickname string `json:"nickname"` - } - data := g.Map{ - "id": 100, - "uid": 101, - "passport": "t1", - "password": "123456", - "nickname": "T1", - "create_time": gtime.Now().String(), - } - result, err := db.Model(table).Data(data).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - - one, err := db.Model(table).Where("id=100").One() - t.AssertNil(err) - - user := new(User) - - t.Assert(one.Struct(user), nil) - t.Assert(user.Id, data["id"]) - t.Assert(user.Passport, data["passport"]) - t.Assert(user.Password, data["password"]) - t.Assert(user.Nickname, data["nickname"]) - t.Assert(user.CreateTime, data["create_time"]) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type Ids struct { + Id int `json:"id"` + Uid int `json:"uid"` + } + type Base struct { + Ids + CreateTime string `json:"create_time"` + } + type User struct { + Base + Passport string `json:"passport"` + Password string `json:"password"` + Nickname string `json:"nickname"` + } + data := g.Map{ + "id": 100, + "uid": 101, + "passport": "t1", + "password": "123456", + "nickname": "T1", + "create_time": gtime.Now().String(), + } + result, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + + one, err := db.Model(table).Where("id=100").One() + t.AssertNil(err) + + user := new(User) + + t.Assert(one.Struct(user), nil) + t.Assert(user.Id, data["id"]) + t.Assert(user.Passport, data["passport"]) + t.Assert(user.Password, data["password"]) + t.Assert(user.Nickname, data["nickname"]) + t.Assert(user.CreateTime, data["create_time"]) + }) } func Test_Struct_Pointer_Attribute(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - type User struct { - Id *int - Passport *string - Password *string - Nickname string - } - - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - user := new(User) - err = one.Struct(user) - t.AssertNil(err) - t.Assert(*user.Id, 1) - t.Assert(*user.Passport, "user_1") - t.Assert(*user.Password, "pass_1") - t.Assert(user.Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - user := new(User) - err := db.Model(table).Scan(user, "id=1") - t.AssertNil(err) - t.Assert(*user.Id, 1) - t.Assert(*user.Passport, "user_1") - t.Assert(*user.Password, "pass_1") - t.Assert(user.Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - var user *User - err := db.Model(table).Scan(&user, "id=1") - t.AssertNil(err) - t.Assert(*user.Id, 1) - t.Assert(*user.Passport, "user_1") - t.Assert(*user.Password, "pass_1") - t.Assert(user.Nickname, "name_1") - }) + table := createInitTable() + defer dropTable(table) + + type User struct { + Id *int + Passport *string + Password *string + Nickname string + } + + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + user := new(User) + err = one.Struct(user) + t.AssertNil(err) + t.Assert(*user.Id, 1) + t.Assert(*user.Passport, "user_1") + t.Assert(*user.Password, "pass_1") + t.Assert(user.Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + user := new(User) + err := db.Model(table).Scan(user, "id=1") + t.AssertNil(err) + t.Assert(*user.Id, 1) + t.Assert(*user.Passport, "user_1") + t.Assert(*user.Password, "pass_1") + t.Assert(user.Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + var user *User + err := db.Model(table).Scan(&user, "id=1") + t.AssertNil(err) + t.Assert(*user.Id, 1) + t.Assert(*user.Passport, "user_1") + t.Assert(*user.Password, "pass_1") + t.Assert(user.Nickname, "name_1") + }) } func Test_Structs_Pointer_Attribute(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - type User struct { - Id *int - Passport *string - Password *string - Nickname string - } - // All - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).All("id < 3") - t.AssertNil(err) - users := make([]User, 0) - err = one.Structs(&users) - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).All("id < 3") - t.AssertNil(err) - users := make([]*User, 0) - err = one.Structs(&users) - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - var users []User - one, err := db.Model(table).All("id < 3") - t.AssertNil(err) - err = one.Structs(&users) - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - var users []*User - one, err := db.Model(table).All("id < 3") - t.AssertNil(err) - err = one.Structs(&users) - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) - // Structs - gtest.C(t, func(t *gtest.T) { - users := make([]User, 0) - err := db.Model(table).Scan(&users, "id < 3") - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - users := make([]*User, 0) - err := db.Model(table).Scan(&users, "id < 3") - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - var users []User - err := db.Model(table).Scan(&users, "id < 3") - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) - gtest.C(t, func(t *gtest.T) { - var users []*User - err := db.Model(table).Scan(&users, "id < 3") - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(*users[0].Id, 1) - t.Assert(*users[0].Passport, "user_1") - t.Assert(*users[0].Password, "pass_1") - t.Assert(users[0].Nickname, "name_1") - }) + table := createInitTable() + defer dropTable(table) + + type User struct { + Id *int + Passport *string + Password *string + Nickname string + } + // All + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).All("id < 3") + t.AssertNil(err) + users := make([]User, 0) + err = one.Structs(&users) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).All("id < 3") + t.AssertNil(err) + users := make([]*User, 0) + err = one.Structs(&users) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + var users []User + one, err := db.Model(table).All("id < 3") + t.AssertNil(err) + err = one.Structs(&users) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + var users []*User + one, err := db.Model(table).All("id < 3") + t.AssertNil(err) + err = one.Structs(&users) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) + // Structs + gtest.C(t, func(t *gtest.T) { + users := make([]User, 0) + err := db.Model(table).Scan(&users, "id < 3") + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + users := make([]*User, 0) + err := db.Model(table).Scan(&users, "id < 3") + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + var users []User + err := db.Model(table).Scan(&users, "id < 3") + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) + gtest.C(t, func(t *gtest.T) { + var users []*User + err := db.Model(table).Scan(&users, "id < 3") + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(*users[0].Id, 1) + t.Assert(*users[0].Passport, "user_1") + t.Assert(*users[0].Password, "pass_1") + t.Assert(users[0].Nickname, "name_1") + }) } func Test_Struct_Empty(t *testing.T) { - table := createTable() - defer dropTable(table) - - type User struct { - Id int - Passport string - Password string - Nickname string - } - - gtest.C(t, func(t *gtest.T) { - user := new(User) - err := db.Model(table).Where("id=100").Scan(user) - t.Assert(err, sql.ErrNoRows) - t.AssertNE(user, nil) - }) - - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Where("id=100").One() - t.AssertNil(err) - var user *User - t.Assert(one.Struct(&user), nil) - t.Assert(user, nil) - }) - - gtest.C(t, func(t *gtest.T) { - var user *User - err := db.Model(table).Where("id=100").Scan(&user) - t.AssertNil(err) - t.Assert(user, nil) - }) + table := createTable() + defer dropTable(table) + + type User struct { + Id int + Passport string + Password string + Nickname string + } + + gtest.C(t, func(t *gtest.T) { + user := new(User) + err := db.Model(table).Where("id=100").Scan(user) + t.Assert(err, sql.ErrNoRows) + t.AssertNE(user, nil) + }) + + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Where("id=100").One() + t.AssertNil(err) + var user *User + t.Assert(one.Struct(&user), nil) + t.Assert(user, nil) + }) + + gtest.C(t, func(t *gtest.T) { + var user *User + err := db.Model(table).Where("id=100").Scan(&user) + t.AssertNil(err) + t.Assert(user, nil) + }) } func Test_Structs_Empty(t *testing.T) { - table := createTable() - defer dropTable(table) - - type User struct { - Id int - Passport string - Password string - Nickname string - } - - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id>100").All() - t.AssertNil(err) - users := make([]User, 0) - t.Assert(all.Structs(&users), nil) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id>100").All() - t.AssertNil(err) - users := make([]User, 10) - t.Assert(all.Structs(&users), sql.ErrNoRows) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id>100").All() - t.AssertNil(err) - var users []User - t.Assert(all.Structs(&users), nil) - }) - - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id>100").All() - t.AssertNil(err) - users := make([]*User, 0) - t.Assert(all.Structs(&users), nil) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id>100").All() - t.AssertNil(err) - users := make([]*User, 10) - t.Assert(all.Structs(&users), sql.ErrNoRows) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id>100").All() - t.AssertNil(err) - var users []*User - t.Assert(all.Structs(&users), nil) - }) + table := createTable() + defer dropTable(table) + + type User struct { + Id int + Passport string + Password string + Nickname string + } + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id>100").All() + t.AssertNil(err) + users := make([]User, 0) + t.Assert(all.Structs(&users), nil) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id>100").All() + t.AssertNil(err) + users := make([]User, 10) + t.Assert(all.Structs(&users), sql.ErrNoRows) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id>100").All() + t.AssertNil(err) + var users []User + t.Assert(all.Structs(&users), nil) + }) + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id>100").All() + t.AssertNil(err) + users := make([]*User, 0) + t.Assert(all.Structs(&users), nil) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id>100").All() + t.AssertNil(err) + users := make([]*User, 10) + t.Assert(all.Structs(&users), sql.ErrNoRows) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id>100").All() + t.AssertNil(err) + var users []*User + t.Assert(all.Structs(&users), nil) + }) } type MyTime struct { - gtime.Time + gtime.Time } type MyTimeSt struct { - CreateTime MyTime + CreateTime MyTime } func (st *MyTimeSt) UnmarshalValue(v interface{}) error { - m := gconv.Map(v) - t, err := gtime.StrToTime(gconv.String(m["create_time"])) - if err != nil { - return err - } - st.CreateTime = MyTime{*t} - return nil + m := gconv.Map(v) + t, err := gtime.StrToTime(gconv.String(m["create_time"])) + if err != nil { + return err + } + st.CreateTime = MyTime{*t} + return nil } func Test_Model_Scan_CustomType_Time(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - st := new(MyTimeSt) - err := db.Model(table).Fields("create_time").Scan(st) - t.AssertNil(err) - t.Assert(st.CreateTime.String(), "2018-10-24 10:00:00") - }) - gtest.C(t, func(t *gtest.T) { - var stSlice []*MyTimeSt - err := db.Model(table).Fields("create_time").Scan(&stSlice) - t.AssertNil(err) - t.Assert(len(stSlice), TableSize) - t.Assert(stSlice[0].CreateTime.String(), "2018-10-24 10:00:00") - t.Assert(stSlice[9].CreateTime.String(), "2018-10-24 10:00:00") - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + st := new(MyTimeSt) + err := db.Model(table).Fields("create_time").Scan(st) + t.AssertNil(err) + t.Assert(st.CreateTime.String(), "2018-10-24 10:00:00") + }) + gtest.C(t, func(t *gtest.T) { + var stSlice []*MyTimeSt + err := db.Model(table).Fields("create_time").Scan(&stSlice) + t.AssertNil(err) + t.Assert(len(stSlice), TableSize) + t.Assert(stSlice[0].CreateTime.String(), "2018-10-24 10:00:00") + t.Assert(stSlice[9].CreateTime.String(), "2018-10-24 10:00:00") + }) } func Test_Model_Scan_CustomType_String(t *testing.T) { - type MyString string - - type MyStringSt struct { - Passport MyString - } - - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - st := new(MyStringSt) - err := db.Model(table).Fields("Passport").WherePri(1).Scan(st) - t.AssertNil(err) - t.Assert(st.Passport, "user_1") - }) - gtest.C(t, func(t *gtest.T) { - var sts []MyStringSt - err := db.Model(table).Fields("Passport").Order("id asc").Scan(&sts) - t.AssertNil(err) - t.Assert(len(sts), TableSize) - t.Assert(sts[0].Passport, "user_1") - }) + type MyString string + + type MyStringSt struct { + Passport MyString + } + + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + st := new(MyStringSt) + err := db.Model(table).Fields("Passport").WherePri(1).Scan(st) + t.AssertNil(err) + t.Assert(st.Passport, "user_1") + }) + gtest.C(t, func(t *gtest.T) { + var sts []MyStringSt + err := db.Model(table).Fields("Passport").Order("id asc").Scan(&sts) + t.AssertNil(err) + t.Assert(len(sts), TableSize) + t.Assert(sts[0].Passport, "user_1") + }) } type User struct { - Id int - Passport string - Password string - Nickname string - CreateTime *gtime.Time + Id int + Passport string + Password string + Nickname string + CreateTime *gtime.Time } func (user *User) UnmarshalValue(value interface{}) error { - if record, ok := value.(gdb.Record); ok { - *user = User{ - Id: record["id"].Int(), - Passport: record["passport"].String(), - Password: "", - Nickname: record["nickname"].String(), - CreateTime: record["create_time"].GTime(), - } - return nil - } - return gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported value type for UnmarshalValue: %v`, reflect.TypeOf(value)) + if record, ok := value.(gdb.Record); ok { + *user = User{ + Id: record["id"].Int(), + Passport: record["passport"].String(), + Password: "", + Nickname: record["nickname"].String(), + CreateTime: record["create_time"].GTime(), + } + return nil + } + return gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported value type for UnmarshalValue: %v`, reflect.TypeOf(value)) } func Test_Model_Scan_UnmarshalValue(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - var users []*User - err := db.Model(table).Order("id asc").Scan(&users) - t.AssertNil(err) - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - t.Assert(users[0].Passport, "user_1") - t.Assert(users[0].Password, "") - t.Assert(users[0].Nickname, "name_1") - t.Assert(users[0].CreateTime.String(), CreateTime) - - t.Assert(users[9].Id, 10) - t.Assert(users[9].Passport, "user_10") - t.Assert(users[9].Password, "") - t.Assert(users[9].Nickname, "name_10") - t.Assert(users[9].CreateTime.String(), CreateTime) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + var users []*User + err := db.Model(table).Order("id asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[0].Passport, "user_1") + t.Assert(users[0].Password, "") + t.Assert(users[0].Nickname, "name_1") + t.Assert(users[0].CreateTime.String(), CreateTime) + + t.Assert(users[9].Id, 10) + t.Assert(users[9].Passport, "user_10") + t.Assert(users[9].Password, "") + t.Assert(users[9].Nickname, "name_10") + t.Assert(users[9].CreateTime.String(), CreateTime) + }) } func Test_Model_Scan_Map(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - var users []*User - err := db.Model(table).Order("id asc").Scan(&users) - t.AssertNil(err) - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - t.Assert(users[0].Passport, "user_1") - t.Assert(users[0].Password, "") - t.Assert(users[0].Nickname, "name_1") - t.Assert(users[0].CreateTime.String(), CreateTime) - - t.Assert(users[9].Id, 10) - t.Assert(users[9].Passport, "user_10") - t.Assert(users[9].Password, "") - t.Assert(users[9].Nickname, "name_10") - t.Assert(users[9].CreateTime.String(), CreateTime) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + var users []*User + err := db.Model(table).Order("id asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[0].Passport, "user_1") + t.Assert(users[0].Password, "") + t.Assert(users[0].Nickname, "name_1") + t.Assert(users[0].CreateTime.String(), CreateTime) + + t.Assert(users[9].Id, 10) + t.Assert(users[9].Passport, "user_10") + t.Assert(users[9].Password, "") + t.Assert(users[9].Nickname, "name_10") + t.Assert(users[9].CreateTime.String(), CreateTime) + }) } func Test_Scan_AutoFilteringByStructAttributes(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - type User struct { - Id int - Passport string - } - // db.SetDebug(true) - gtest.C(t, func(t *gtest.T) { - var user *User - err := db.Model(table).OrderAsc("id").Scan(&user) - t.AssertNil(err) - t.Assert(user.Id, 1) - }) - gtest.C(t, func(t *gtest.T) { - var users []User - err := db.Model(table).OrderAsc("id").Scan(&users) - t.AssertNil(err) - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - }) + table := createInitTable() + defer dropTable(table) + + type User struct { + Id int + Passport string + } + // db.SetDebug(true) + gtest.C(t, func(t *gtest.T) { + var user *User + err := db.Model(table).OrderAsc("id").Scan(&user) + t.AssertNil(err) + t.Assert(user.Id, 1) + }) + gtest.C(t, func(t *gtest.T) { + var users []User + err := db.Model(table).OrderAsc("id").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + }) } diff --git a/contrib/drivers/mysql/mysql_z_unit_issue_test.go b/contrib/drivers/mysql/mysql_z_unit_issue_test.go index 2b909c85f28..68a23087f6f 100644 --- a/contrib/drivers/mysql/mysql_z_unit_issue_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_issue_test.go @@ -7,180 +7,180 @@ package mysql_test import ( - "context" - "encoding/json" - "fmt" - "sync" - "testing" - "time" - - "github.com/gogf/gf/v2/database/gdb" - "github.com/gogf/gf/v2/frame/g" - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/test/gtest" - "github.com/gogf/gf/v2/text/gregex" - "github.com/gogf/gf/v2/text/gstr" - "github.com/gogf/gf/v2/util/gmeta" - "github.com/gogf/gf/v2/util/guid" + "context" + "encoding/json" + "fmt" + "sync" + "testing" + "time" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/test/gtest" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gmeta" + "github.com/gogf/gf/v2/util/guid" ) // https://github.com/gogf/gf/issues/1380 func Test_Issue1380(t *testing.T) { - type GiftImage struct { - Uid string `json:"uid"` - Url string `json:"url"` - Status string `json:"status"` - Name string `json:"name"` - } - - type GiftComment struct { - Name string `json:"name"` - Field string `json:"field"` - Required bool `json:"required"` - } - - type Prop struct { - Name string `json:"name"` - Values []string `json:"values"` - } - - type Sku struct { - GiftId int64 `json:"gift_id"` - Name string `json:"name"` - ScorePrice int `json:"score_price"` - MarketPrice int `json:"market_price"` - CostPrice int `json:"cost_price"` - Stock int `json:"stock"` - } - - type Covers struct { - List []GiftImage `json:"list"` - } - - type GiftEntity struct { - Id int64 `json:"id"` - StoreId int64 `json:"store_id"` - GiftType int `json:"gift_type"` - GiftName string `json:"gift_name"` - Description string `json:"description"` - Covers Covers `json:"covers"` - Cover string `json:"cover"` - GiftCategoryId []int64 `json:"gift_category_id"` - HasProps bool `json:"has_props"` - OutSn string `json:"out_sn"` - IsLimitSell bool `json:"is_limit_sell"` - LimitSellType int `json:"limit_sell_type"` - LimitSellCycle string `json:"limit_sell_cycle"` - LimitSellCycleCount int `json:"limit_sell_cycle_count"` - LimitSellCustom bool `json:"limit_sell_custom"` // 只允许特定会员兑换 - LimitCustomerTags []int64 `json:"limit_customer_tags"` // 允许兑换的成员 - ScorePrice int `json:"score_price"` - MarketPrice float64 `json:"market_price"` - CostPrice int `json:"cost_price"` - Stock int `json:"stock"` - Props []Prop `json:"props"` - Skus []Sku `json:"skus"` - ExpressType []string `json:"express_type"` - Comments []GiftComment `json:"comments"` - Content string `json:"content"` - AtLeastRechargeCount int `json:"at_least_recharge_count"` - Status int `json:"status"` - } - - type User struct { - Id int - Passport string - } - - table := "jfy_gift" - array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `1380.sql`), ";") - for _, v := range array { - if _, err := db.Exec(ctx, v); err != nil { - gtest.Error(err) - } - } - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - var ( - entity = new(GiftEntity) - err = db.Model(table).Where("id", 17).Scan(entity) - ) - t.AssertNil(err) - t.Assert(len(entity.Skus), 2) - - t.Assert(entity.Skus[0].Name, "red") - t.Assert(entity.Skus[0].Stock, 10) - t.Assert(entity.Skus[0].GiftId, 1) - t.Assert(entity.Skus[0].CostPrice, 80) - t.Assert(entity.Skus[0].ScorePrice, 188) - t.Assert(entity.Skus[0].MarketPrice, 388) - - t.Assert(entity.Skus[1].Name, "blue") - t.Assert(entity.Skus[1].Stock, 100) - t.Assert(entity.Skus[1].GiftId, 2) - t.Assert(entity.Skus[1].CostPrice, 81) - t.Assert(entity.Skus[1].ScorePrice, 200) - t.Assert(entity.Skus[1].MarketPrice, 288) - - t.Assert(entity.Id, 17) - t.Assert(entity.StoreId, 100004) - t.Assert(entity.GiftType, 1) - t.Assert(entity.GiftName, "GIFT") - t.Assert(entity.Description, "支持个性定制的父亲节老师长辈的专属礼物") - t.Assert(len(entity.Covers.List), 3) - t.Assert(entity.OutSn, "259402") - t.Assert(entity.LimitCustomerTags, "[]") - t.Assert(entity.ScorePrice, 10) - t.Assert(len(entity.Props), 1) - t.Assert(len(entity.Comments), 2) - t.Assert(entity.Status, 99) - t.Assert(entity.Content, `

礼品详情

`) - }) + type GiftImage struct { + Uid string `json:"uid"` + Url string `json:"url"` + Status string `json:"status"` + Name string `json:"name"` + } + + type GiftComment struct { + Name string `json:"name"` + Field string `json:"field"` + Required bool `json:"required"` + } + + type Prop struct { + Name string `json:"name"` + Values []string `json:"values"` + } + + type Sku struct { + GiftId int64 `json:"gift_id"` + Name string `json:"name"` + ScorePrice int `json:"score_price"` + MarketPrice int `json:"market_price"` + CostPrice int `json:"cost_price"` + Stock int `json:"stock"` + } + + type Covers struct { + List []GiftImage `json:"list"` + } + + type GiftEntity struct { + Id int64 `json:"id"` + StoreId int64 `json:"store_id"` + GiftType int `json:"gift_type"` + GiftName string `json:"gift_name"` + Description string `json:"description"` + Covers Covers `json:"covers"` + Cover string `json:"cover"` + GiftCategoryId []int64 `json:"gift_category_id"` + HasProps bool `json:"has_props"` + OutSn string `json:"out_sn"` + IsLimitSell bool `json:"is_limit_sell"` + LimitSellType int `json:"limit_sell_type"` + LimitSellCycle string `json:"limit_sell_cycle"` + LimitSellCycleCount int `json:"limit_sell_cycle_count"` + LimitSellCustom bool `json:"limit_sell_custom"` // 只允许特定会员兑换 + LimitCustomerTags []int64 `json:"limit_customer_tags"` // 允许兑换的成员 + ScorePrice int `json:"score_price"` + MarketPrice float64 `json:"market_price"` + CostPrice int `json:"cost_price"` + Stock int `json:"stock"` + Props []Prop `json:"props"` + Skus []Sku `json:"skus"` + ExpressType []string `json:"express_type"` + Comments []GiftComment `json:"comments"` + Content string `json:"content"` + AtLeastRechargeCount int `json:"at_least_recharge_count"` + Status int `json:"status"` + } + + type User struct { + Id int + Passport string + } + + table := "jfy_gift" + array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `1380.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + var ( + entity = new(GiftEntity) + err = db.Model(table).Where("id", 17).Scan(entity) + ) + t.AssertNil(err) + t.Assert(len(entity.Skus), 2) + + t.Assert(entity.Skus[0].Name, "red") + t.Assert(entity.Skus[0].Stock, 10) + t.Assert(entity.Skus[0].GiftId, 1) + t.Assert(entity.Skus[0].CostPrice, 80) + t.Assert(entity.Skus[0].ScorePrice, 188) + t.Assert(entity.Skus[0].MarketPrice, 388) + + t.Assert(entity.Skus[1].Name, "blue") + t.Assert(entity.Skus[1].Stock, 100) + t.Assert(entity.Skus[1].GiftId, 2) + t.Assert(entity.Skus[1].CostPrice, 81) + t.Assert(entity.Skus[1].ScorePrice, 200) + t.Assert(entity.Skus[1].MarketPrice, 288) + + t.Assert(entity.Id, 17) + t.Assert(entity.StoreId, 100004) + t.Assert(entity.GiftType, 1) + t.Assert(entity.GiftName, "GIFT") + t.Assert(entity.Description, "支持个性定制的父亲节老师长辈的专属礼物") + t.Assert(len(entity.Covers.List), 3) + t.Assert(entity.OutSn, "259402") + t.Assert(entity.LimitCustomerTags, "[]") + t.Assert(entity.ScorePrice, 10) + t.Assert(len(entity.Props), 1) + t.Assert(len(entity.Comments), 2) + t.Assert(entity.Status, 99) + t.Assert(entity.Content, `

礼品详情

`) + }) } // https://github.com/gogf/gf/issues/1934 func Test_Issue1934(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Where(" id ", 1).One() - t.AssertNil(err) - t.Assert(one["id"], 1) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Where(" id ", 1).One() + t.AssertNil(err) + t.Assert(one["id"], 1) + }) } // https://github.com/gogf/gf/issues/1570 func Test_Issue1570(t *testing.T) { - var ( - tableUser = "user_" + gtime.TimestampMicroStr() - tableUserDetail = "user_detail_" + gtime.TimestampMicroStr() - tableUserScores = "user_scores_" + gtime.TimestampMicroStr() - ) - if _, err := db.Exec(ctx, fmt.Sprintf(` + var ( + tableUser = "user_" + gtime.TimestampMicroStr() + tableUserDetail = "user_detail_" + gtime.TimestampMicroStr() + tableUserScores = "user_scores_" + gtime.TimestampMicroStr() + ) + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE %s ( uid int(10) unsigned NOT NULL AUTO_INCREMENT, name varchar(45) NOT NULL, PRIMARY KEY (uid) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; `, tableUser)); err != nil { - gtest.Error(err) - } - defer dropTable(tableUser) + gtest.Error(err) + } + defer dropTable(tableUser) - if _, err := db.Exec(ctx, fmt.Sprintf(` + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE %s ( uid int(10) unsigned NOT NULL AUTO_INCREMENT, address varchar(45) NOT NULL, PRIMARY KEY (uid) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; `, tableUserDetail)); err != nil { - gtest.Error(err) - } - defer dropTable(tableUserDetail) + gtest.Error(err) + } + defer dropTable(tableUserDetail) - if _, err := db.Exec(ctx, fmt.Sprintf(` + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE %s ( id int(10) unsigned NOT NULL AUTO_INCREMENT, uid int(10) unsigned NOT NULL, @@ -188,279 +188,279 @@ CREATE TABLE %s ( PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; `, tableUserScores)); err != nil { - gtest.Error(err) - } - defer dropTable(tableUserScores) - - type EntityUser struct { - Uid int `json:"uid"` - Name string `json:"name"` - } - type EntityUserDetail struct { - Uid int `json:"uid"` - Address string `json:"address"` - } - type EntityUserScores struct { - Id int `json:"id"` - Uid int `json:"uid"` - Score int `json:"score"` - } - type Entity struct { - User *EntityUser - UserDetail *EntityUserDetail - UserScores []*EntityUserScores - } - - // Initialize the data. - gtest.C(t, func(t *gtest.T) { - var err error - for i := 1; i <= 5; i++ { - // User. - _, err = db.Insert(ctx, tableUser, g.Map{ - "uid": i, - "name": fmt.Sprintf(`name_%d`, i), - }) - t.AssertNil(err) - // Detail. - _, err = db.Insert(ctx, tableUserDetail, g.Map{ - "uid": i, - "address": fmt.Sprintf(`address_%d`, i), - }) - t.AssertNil(err) - // Scores. - for j := 1; j <= 5; j++ { - _, err = db.Insert(ctx, tableUserScores, g.Map{ - "uid": i, - "score": j, - }) - t.AssertNil(err) - } - } - }) - - // Result ScanList with struct elements and pointer attributes. - gtest.C(t, func(t *gtest.T) { - var users []Entity - // User - err := db.Model(tableUser). - Where("uid", g.Slice{3, 4}). - Fields("uid"). - Order("uid asc"). - ScanList(&users, "User") - t.AssertNil(err) - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(users[0].User, &EntityUser{3, ""}) - t.Assert(users[1].User, &EntityUser{4, ""}) - // Detail - err = db.Model(tableUserDetail). - Where("uid", gdb.ListItemValues(users, "User", "Uid")). - Order("uid asc"). - ScanList(&users, "UserDetail", "User", "uid:Uid") - t.AssertNil(err) - t.AssertNil(err) - t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"}) - t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"}) - // Scores - err = db.Model(tableUserScores). - Where("uid", gdb.ListItemValues(users, "User", "Uid")). - Order("id asc"). - ScanList(&users, "UserScores", "User", "uid:Uid") - t.AssertNil(err) - t.AssertNil(err) - t.Assert(len(users[0].UserScores), 5) - t.Assert(len(users[1].UserScores), 5) - t.Assert(users[0].UserScores[0].Uid, 3) - t.Assert(users[0].UserScores[0].Score, 1) - t.Assert(users[0].UserScores[4].Score, 5) - t.Assert(users[1].UserScores[0].Uid, 4) - t.Assert(users[1].UserScores[0].Score, 1) - t.Assert(users[1].UserScores[4].Score, 5) - }) + gtest.Error(err) + } + defer dropTable(tableUserScores) + + type EntityUser struct { + Uid int `json:"uid"` + Name string `json:"name"` + } + type EntityUserDetail struct { + Uid int `json:"uid"` + Address string `json:"address"` + } + type EntityUserScores struct { + Id int `json:"id"` + Uid int `json:"uid"` + Score int `json:"score"` + } + type Entity struct { + User *EntityUser + UserDetail *EntityUserDetail + UserScores []*EntityUserScores + } + + // Initialize the data. + gtest.C(t, func(t *gtest.T) { + var err error + for i := 1; i <= 5; i++ { + // User. + _, err = db.Insert(ctx, tableUser, g.Map{ + "uid": i, + "name": fmt.Sprintf(`name_%d`, i), + }) + t.AssertNil(err) + // Detail. + _, err = db.Insert(ctx, tableUserDetail, g.Map{ + "uid": i, + "address": fmt.Sprintf(`address_%d`, i), + }) + t.AssertNil(err) + // Scores. + for j := 1; j <= 5; j++ { + _, err = db.Insert(ctx, tableUserScores, g.Map{ + "uid": i, + "score": j, + }) + t.AssertNil(err) + } + } + }) + + // Result ScanList with struct elements and pointer attributes. + gtest.C(t, func(t *gtest.T) { + var users []Entity + // User + err := db.Model(tableUser). + Where("uid", g.Slice{3, 4}). + Fields("uid"). + Order("uid asc"). + ScanList(&users, "User") + t.AssertNil(err) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(users[0].User, &EntityUser{3, ""}) + t.Assert(users[1].User, &EntityUser{4, ""}) + // Detail + err = db.Model(tableUserDetail). + Where("uid", gdb.ListItemValues(users, "User", "Uid")). + Order("uid asc"). + ScanList(&users, "UserDetail", "User", "uid:Uid") + t.AssertNil(err) + t.AssertNil(err) + t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"}) + t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"}) + // Scores + err = db.Model(tableUserScores). + Where("uid", gdb.ListItemValues(users, "User", "Uid")). + Order("id asc"). + ScanList(&users, "UserScores", "User", "uid:Uid") + t.AssertNil(err) + t.AssertNil(err) + t.Assert(len(users[0].UserScores), 5) + t.Assert(len(users[1].UserScores), 5) + t.Assert(users[0].UserScores[0].Uid, 3) + t.Assert(users[0].UserScores[0].Score, 1) + t.Assert(users[0].UserScores[4].Score, 5) + t.Assert(users[1].UserScores[0].Uid, 4) + t.Assert(users[1].UserScores[0].Score, 1) + t.Assert(users[1].UserScores[4].Score, 5) + }) } // https://github.com/gogf/gf/issues/1401 func Test_Issue1401(t *testing.T) { - var ( - table1 = "parcels" - table2 = "parcel_items" - ) - array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `1401.sql`), ";") - for _, v := range array { - if _, err := db.Exec(ctx, v); err != nil { - gtest.Error(err) - } - } - defer dropTable(table1) - defer dropTable(table2) - - gtest.C(t, func(t *gtest.T) { - type NItem struct { - Id int `json:"id"` - ParcelId int `json:"parcel_id"` - } - - type ParcelItem struct { - gmeta.Meta `orm:"table:parcel_items"` - NItem - } - - type ParcelRsp struct { - gmeta.Meta `orm:"table:parcels"` - Id int `json:"id"` - Items []*ParcelItem `json:"items" orm:"with:parcel_id=Id"` - } - - parcelDetail := &ParcelRsp{} - err := db.Model(table1).With(parcelDetail.Items).Where("id", 3).Scan(&parcelDetail) - t.AssertNil(err) - t.Assert(parcelDetail.Id, 3) - t.Assert(len(parcelDetail.Items), 1) - t.Assert(parcelDetail.Items[0].Id, 2) - t.Assert(parcelDetail.Items[0].ParcelId, 3) - }) + var ( + table1 = "parcels" + table2 = "parcel_items" + ) + array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `1401.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable(table1) + defer dropTable(table2) + + gtest.C(t, func(t *gtest.T) { + type NItem struct { + Id int `json:"id"` + ParcelId int `json:"parcel_id"` + } + + type ParcelItem struct { + gmeta.Meta `orm:"table:parcel_items"` + NItem + } + + type ParcelRsp struct { + gmeta.Meta `orm:"table:parcels"` + Id int `json:"id"` + Items []*ParcelItem `json:"items" orm:"with:parcel_id=Id"` + } + + parcelDetail := &ParcelRsp{} + err := db.Model(table1).With(parcelDetail.Items).Where("id", 3).Scan(&parcelDetail) + t.AssertNil(err) + t.Assert(parcelDetail.Id, 3) + t.Assert(len(parcelDetail.Items), 1) + t.Assert(parcelDetail.Items[0].Id, 2) + t.Assert(parcelDetail.Items[0].ParcelId, 3) + }) } // https://github.com/gogf/gf/issues/1412 func Test_Issue1412(t *testing.T) { - var ( - table1 = "parcels" - table2 = "items" - ) - array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `1412.sql`), ";") - for _, v := range array { - if _, err := db.Exec(ctx, v); err != nil { - gtest.Error(err) - } - } - defer dropTable(table1) - defer dropTable(table2) - - gtest.C(t, func(t *gtest.T) { - type Items struct { - gmeta.Meta `orm:"table:items"` - Id int `json:"id"` - Name string `json:"name"` - } - - type ParcelRsp struct { - gmeta.Meta `orm:"table:parcels"` - Id int `json:"id"` - ItemId int `json:"item_id"` - Items Items `json:"items" orm:"with:Id=ItemId"` - } - - entity := &ParcelRsp{} - err := db.Model("parcels").With(Items{}).Where("id=3").Scan(&entity) - t.AssertNil(err) - t.Assert(entity.Id, 3) - t.Assert(entity.ItemId, 0) - t.Assert(entity.Items.Id, 0) - t.Assert(entity.Items.Name, "") - }) - - gtest.C(t, func(t *gtest.T) { - type Items struct { - gmeta.Meta `orm:"table:items"` - Id int `json:"id"` - Name string `json:"name"` - } - - type ParcelRsp struct { - gmeta.Meta `orm:"table:parcels"` - Id int `json:"id"` - ItemId int `json:"item_id"` - Items Items `json:"items" orm:"with:Id=ItemId"` - } - - entity := &ParcelRsp{} - err := db.Model("parcels").With(Items{}).Where("id=30000").Scan(&entity) - t.AssertNE(err, nil) - t.Assert(entity.Id, 0) - t.Assert(entity.ItemId, 0) - t.Assert(entity.Items.Id, 0) - t.Assert(entity.Items.Name, "") - }) + var ( + table1 = "parcels" + table2 = "items" + ) + array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `1412.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable(table1) + defer dropTable(table2) + + gtest.C(t, func(t *gtest.T) { + type Items struct { + gmeta.Meta `orm:"table:items"` + Id int `json:"id"` + Name string `json:"name"` + } + + type ParcelRsp struct { + gmeta.Meta `orm:"table:parcels"` + Id int `json:"id"` + ItemId int `json:"item_id"` + Items Items `json:"items" orm:"with:Id=ItemId"` + } + + entity := &ParcelRsp{} + err := db.Model("parcels").With(Items{}).Where("id=3").Scan(&entity) + t.AssertNil(err) + t.Assert(entity.Id, 3) + t.Assert(entity.ItemId, 0) + t.Assert(entity.Items.Id, 0) + t.Assert(entity.Items.Name, "") + }) + + gtest.C(t, func(t *gtest.T) { + type Items struct { + gmeta.Meta `orm:"table:items"` + Id int `json:"id"` + Name string `json:"name"` + } + + type ParcelRsp struct { + gmeta.Meta `orm:"table:parcels"` + Id int `json:"id"` + ItemId int `json:"item_id"` + Items Items `json:"items" orm:"with:Id=ItemId"` + } + + entity := &ParcelRsp{} + err := db.Model("parcels").With(Items{}).Where("id=30000").Scan(&entity) + t.AssertNE(err, nil) + t.Assert(entity.Id, 0) + t.Assert(entity.ItemId, 0) + t.Assert(entity.Items.Id, 0) + t.Assert(entity.Items.Name, "") + }) } // https://github.com/gogf/gf/issues/1002 func Test_Issue1002(t *testing.T) { - table := createTable() - defer dropTable(table) - - result, err := db.Model(table).Data(g.Map{ - "id": 1, - "passport": "port_1", - "password": "pass_1", - "nickname": "name_2", - "create_time": "2020-10-27 19:03:33", - }).Insert() - gtest.AssertNil(err) - n, _ := result.RowsAffected() - gtest.Assert(n, 1) - - // where + string. - gtest.C(t, func(t *gtest.T) { - v, err := db.Model(table).Fields("id").Where("create_time>'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'").Value() - t.AssertNil(err) - t.Assert(v.Int(), 1) - }) - gtest.C(t, func(t *gtest.T) { - v, err := db.Model(table).Fields("id").Where("create_time>'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'").Value() - t.AssertNil(err) - t.Assert(v.Int(), 1) - }) - // where + string arguments. - gtest.C(t, func(t *gtest.T) { - v, err := db.Model(table).Fields("id").Where("create_time>? and create_time? and create_time? and create_time? and create_time? and create_time? and create_time'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'").Value() + t.AssertNil(err) + t.Assert(v.Int(), 1) + }) + gtest.C(t, func(t *gtest.T) { + v, err := db.Model(table).Fields("id").Where("create_time>'2020-10-27 19:03:32' and create_time<'2020-10-27 19:03:34'").Value() + t.AssertNil(err) + t.Assert(v.Int(), 1) + }) + // where + string arguments. + gtest.C(t, func(t *gtest.T) { + v, err := db.Model(table).Fields("id").Where("create_time>? and create_time? and create_time? and create_time? and create_time? and create_time? and create_time b").All() - t.AssertNil(err) - t.Assert(len(all), 1) - t.Assert(all[0]["id"], 2) - - all, err = db.Model(table).Where(gdb.Raw("a > b")).All() - t.AssertNil(err) - t.Assert(len(all), 1) - t.Assert(all[0]["id"], 2) - - all, err = db.Model(table).WhereGT("a", gdb.Raw("`b`")).All() - t.AssertNil(err) - t.Assert(len(all), 1) - t.Assert(all[0]["id"], 2) - }) + table := "issue3915" + array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `3915.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + //db.SetDebug(true) + all, err := db.Model(table).Where("a < b").All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(all[0]["id"], 1) + + all, err = db.Model(table).Where(gdb.Raw("a < b")).All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(all[0]["id"], 1) + + all, err = db.Model(table).WhereLT("a", gdb.Raw("`b`")).All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(all[0]["id"], 1) + }) + + gtest.C(t, func(t *gtest.T) { + //db.SetDebug(true) + all, err := db.Model(table).Where("a > b").All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(all[0]["id"], 2) + + all, err = db.Model(table).Where(gdb.Raw("a > b")).All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(all[0]["id"], 2) + + all, err = db.Model(table).WhereGT("a", gdb.Raw("`b`")).All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(all[0]["id"], 2) + }) } type RoleBase struct { - gmeta.Meta `orm:"table:sys_role"` - Name string `json:"name" description:"角色名称" ` - Code string `json:"code" description:"角色 code" ` - Description string `json:"description" description:"描述信息" ` - Weight int `json:"weight" description:"排序" ` - StatusId int `json:"statusId" description:"发布状态" ` - CreatedAt *gtime.Time `json:"createdAt" description:"" ` - UpdatedAt *gtime.Time `json:"updatedAt" description:"" ` + gmeta.Meta `orm:"table:sys_role"` + Name string `json:"name" description:"角色名称" ` + Code string `json:"code" description:"角色 code" ` + Description string `json:"description" description:"描述信息" ` + Weight int `json:"weight" description:"排序" ` + StatusId int `json:"statusId" description:"发布状态" ` + CreatedAt *gtime.Time `json:"createdAt" description:"" ` + UpdatedAt *gtime.Time `json:"updatedAt" description:"" ` } type Role struct { - gmeta.Meta `orm:"table:sys_role"` - RoleBase - Id uint `json:"id" description:""` - Status *Status `json:"status" description:"发布状态" orm:"with:id=status_id" ` + gmeta.Meta `orm:"table:sys_role"` + RoleBase + Id uint `json:"id" description:""` + Status *Status `json:"status" description:"发布状态" orm:"with:id=status_id" ` } type StatusBase struct { - gmeta.Meta `orm:"table:sys_status"` - En string `json:"en" description:"英文名称" ` - Cn string `json:"cn" description:"中文名称" ` - Weight int `json:"weight" description:"排序权重" ` + gmeta.Meta `orm:"table:sys_status"` + En string `json:"en" description:"英文名称" ` + Cn string `json:"cn" description:"中文名称" ` + Weight int `json:"weight" description:"排序权重" ` } type Status struct { - gmeta.Meta `orm:"table:sys_status"` - StatusBase - Id uint `json:"id" description:""` + gmeta.Meta `orm:"table:sys_status"` + StatusBase + Id uint `json:"id" description:""` } // https://github.com/gogf/gf/issues/2119 func Test_Issue2119(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - tables := []string{ - "sys_role", - "sys_status", - } - - defer dropTable(tables[0]) - defer dropTable(tables[1]) - _ = tables - array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `2119.sql`), ";") - for _, v := range array { - _, err := db.Exec(ctx, v) - t.AssertNil(err) - } - roles := make([]*Role, 0) - err := db.Ctx(context.Background()).Model(&Role{}).WithAll().Scan(&roles) - t.AssertNil(err) - expectStatus := []*Status{ - { - StatusBase: StatusBase{ - En: "undecided", - Cn: "未决定", - Weight: 800, - }, - Id: 2, - }, - { - StatusBase: StatusBase{ - En: "on line", - Cn: "上线", - Weight: 900, - }, - Id: 1, - }, - { - StatusBase: StatusBase{ - En: "on line", - Cn: "上线", - Weight: 900, - }, - Id: 1, - }, - { - StatusBase: StatusBase{ - En: "on line", - Cn: "上线", - Weight: 900, - }, - Id: 1, - }, - { - StatusBase: StatusBase{ - En: "on line", - Cn: "上线", - Weight: 900, - }, - Id: 1, - }, - } - - for i := 0; i < len(roles); i++ { - t.Assert(roles[i].Status, expectStatus[i]) - } - }) + gtest.C(t, func(t *gtest.T) { + tables := []string{ + "sys_role", + "sys_status", + } + + defer dropTable(tables[0]) + defer dropTable(tables[1]) + _ = tables + array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `2119.sql`), ";") + for _, v := range array { + _, err := db.Exec(ctx, v) + t.AssertNil(err) + } + roles := make([]*Role, 0) + err := db.Ctx(context.Background()).Model(&Role{}).WithAll().Scan(&roles) + t.AssertNil(err) + expectStatus := []*Status{ + { + StatusBase: StatusBase{ + En: "undecided", + Cn: "未决定", + Weight: 800, + }, + Id: 2, + }, + { + StatusBase: StatusBase{ + En: "on line", + Cn: "上线", + Weight: 900, + }, + Id: 1, + }, + { + StatusBase: StatusBase{ + En: "on line", + Cn: "上线", + Weight: 900, + }, + Id: 1, + }, + { + StatusBase: StatusBase{ + En: "on line", + Cn: "上线", + Weight: 900, + }, + Id: 1, + }, + { + StatusBase: StatusBase{ + En: "on line", + Cn: "上线", + Weight: 900, + }, + Id: 1, + }, + } + + for i := 0; i < len(roles); i++ { + t.Assert(roles[i].Status, expectStatus[i]) + } + }) } // https://github.com/gogf/gf/issues/4034 func Test_Issue4034(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - table := "issue4034" - array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `4034.sql`), ";") - for _, v := range array { - _, err := db.Exec(ctx, v) - t.AssertNil(err) - } - defer dropTable(table) - - err := issue4034SaveDeviceAndToken(ctx, table) - t.AssertNil(err) - }) + gtest.C(t, func(t *gtest.T) { + table := "issue4034" + array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `4034.sql`), ";") + for _, v := range array { + _, err := db.Exec(ctx, v) + t.AssertNil(err) + } + defer dropTable(table) + + err := issue4034SaveDeviceAndToken(ctx, table) + t.AssertNil(err) + }) } func issue4034SaveDeviceAndToken(ctx context.Context, table string) error { - return db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { - if err := issue4034SaveAppDevice(ctx, table, tx); err != nil { - return err - } - return nil - }) + return db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { + if err := issue4034SaveAppDevice(ctx, table, tx); err != nil { + return err + } + return nil + }) } func issue4034SaveAppDevice(ctx context.Context, table string, tx gdb.TX) error { - _, err := db.Model(table).Safe().Ctx(ctx).TX(tx).Data(g.Map{ - "passport": "111", - "password": "222", - "nickname": "333", - }).Save() - return err + _, err := db.Model(table).Safe().Ctx(ctx).TX(tx).Data(g.Map{ + "passport": "111", + "password": "222", + "nickname": "333", + }).Save() + return err } // https://github.com/gogf/gf/issues/4086 func Test_Issue4086(t *testing.T) { - table := "issue4086" - defer dropTable(table) - array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `4086.sql`), ";") - for _, v := range array { - _, err := db.Exec(ctx, v) - gtest.AssertNil(err) - } - - gtest.C(t, func(t *gtest.T) { - type ProxyParam struct { - ProxyId int64 `json:"proxyId" orm:"proxy_id"` - RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` - Photos []string `json:"photos" orm:"photos"` - } - - var proxyParamList []*ProxyParam - err := db.Model(table).Ctx(ctx).Scan(&proxyParamList) - t.AssertNil(err) - t.Assert(len(proxyParamList), 2) - t.Assert(proxyParamList, []*ProxyParam{ - { - ProxyId: 1, - RecommendIds: []int64{584, 585}, - Photos: nil, - }, - { - ProxyId: 2, - RecommendIds: []int64{}, - Photos: nil, - }, - }) - }) - gtest.C(t, func(t *gtest.T) { - type ProxyParam struct { - ProxyId int64 `json:"proxyId" orm:"proxy_id"` - RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` - Photos []any `json:"photos" orm:"photos"` - } - - var proxyParamList []*ProxyParam - err := db.Model(table).Ctx(ctx).Scan(&proxyParamList) - t.AssertNil(err) - t.Assert(len(proxyParamList), 2) - t.Assert(proxyParamList, []*ProxyParam{ - { - ProxyId: 1, - RecommendIds: []int64{584, 585}, - Photos: nil, - }, - { - ProxyId: 2, - RecommendIds: []int64{}, - Photos: nil, - }, - }) - }) - gtest.C(t, func(t *gtest.T) { - type ProxyParam struct { - ProxyId int64 `json:"proxyId" orm:"proxy_id"` - RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` - Photos string `json:"photos" orm:"photos"` - } - - var proxyParamList []*ProxyParam - err := db.Model(table).Ctx(ctx).Scan(&proxyParamList) - t.AssertNil(err) - t.Assert(len(proxyParamList), 2) - t.Assert(proxyParamList, []*ProxyParam{ - { - ProxyId: 1, - RecommendIds: []int64{584, 585}, - Photos: "null", - }, - { - ProxyId: 2, - RecommendIds: []int64{}, - Photos: "", - }, - }) - }) - gtest.C(t, func(t *gtest.T) { - type ProxyParam struct { - ProxyId int64 `json:"proxyId" orm:"proxy_id"` - RecommendIds string `json:"recommendIds" orm:"recommend_ids"` - Photos json.RawMessage `json:"photos" orm:"photos"` - } - - var proxyParamList []*ProxyParam - err := db.Model(table).Ctx(ctx).Scan(&proxyParamList) - t.AssertNil(err) - t.Assert(len(proxyParamList), 2) - t.Assert(proxyParamList, []*ProxyParam{ - { - ProxyId: 1, - RecommendIds: "[584, 585]", - Photos: json.RawMessage("null"), - }, - { - ProxyId: 2, - RecommendIds: "[]", - Photos: json.RawMessage("null"), - }, - }) - }) + table := "issue4086" + defer dropTable(table) + array := gstr.SplitAndTrim(gtest.DataContent(`issues`, `4086.sql`), ";") + for _, v := range array { + _, err := db.Exec(ctx, v) + gtest.AssertNil(err) + } + + gtest.C(t, func(t *gtest.T) { + type ProxyParam struct { + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` + Photos []string `json:"photos" orm:"photos"` + } + + var proxyParamList []*ProxyParam + err := db.Model(table).Ctx(ctx).Scan(&proxyParamList) + t.AssertNil(err) + t.Assert(len(proxyParamList), 2) + t.Assert(proxyParamList, []*ProxyParam{ + { + ProxyId: 1, + RecommendIds: []int64{584, 585}, + Photos: nil, + }, + { + ProxyId: 2, + RecommendIds: []int64{}, + Photos: nil, + }, + }) + }) + gtest.C(t, func(t *gtest.T) { + type ProxyParam struct { + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` + Photos []any `json:"photos" orm:"photos"` + } + + var proxyParamList []*ProxyParam + err := db.Model(table).Ctx(ctx).Scan(&proxyParamList) + t.AssertNil(err) + t.Assert(len(proxyParamList), 2) + t.Assert(proxyParamList, []*ProxyParam{ + { + ProxyId: 1, + RecommendIds: []int64{584, 585}, + Photos: nil, + }, + { + ProxyId: 2, + RecommendIds: []int64{}, + Photos: nil, + }, + }) + }) + gtest.C(t, func(t *gtest.T) { + type ProxyParam struct { + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` + Photos string `json:"photos" orm:"photos"` + } + + var proxyParamList []*ProxyParam + err := db.Model(table).Ctx(ctx).Scan(&proxyParamList) + t.AssertNil(err) + t.Assert(len(proxyParamList), 2) + t.Assert(proxyParamList, []*ProxyParam{ + { + ProxyId: 1, + RecommendIds: []int64{584, 585}, + Photos: "null", + }, + { + ProxyId: 2, + RecommendIds: []int64{}, + Photos: "", + }, + }) + }) + gtest.C(t, func(t *gtest.T) { + type ProxyParam struct { + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds string `json:"recommendIds" orm:"recommend_ids"` + Photos json.RawMessage `json:"photos" orm:"photos"` + } + + var proxyParamList []*ProxyParam + err := db.Model(table).Ctx(ctx).Scan(&proxyParamList) + t.AssertNil(err) + t.Assert(len(proxyParamList), 2) + t.Assert(proxyParamList, []*ProxyParam{ + { + ProxyId: 1, + RecommendIds: "[584, 585]", + Photos: json.RawMessage("null"), + }, + { + ProxyId: 2, + RecommendIds: "[]", + Photos: json.RawMessage("null"), + }, + }) + }) } diff --git a/contrib/drivers/mysql/mysql_z_unit_model_test.go b/contrib/drivers/mysql/mysql_z_unit_model_test.go index 9ae609d735c..54117359cec 100644 --- a/contrib/drivers/mysql/mysql_z_unit_model_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_model_test.go @@ -7,584 +7,584 @@ package mysql_test import ( - "bytes" - "context" - "database/sql" - "fmt" - "os" - "strings" - "testing" - "time" - - "github.com/gogf/gf/v2/container/garray" - "github.com/gogf/gf/v2/database/gdb" - "github.com/gogf/gf/v2/encoding/gjson" - "github.com/gogf/gf/v2/frame/g" - "github.com/gogf/gf/v2/os/gfile" - "github.com/gogf/gf/v2/os/glog" - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/test/gtest" - "github.com/gogf/gf/v2/text/gstr" - "github.com/gogf/gf/v2/util/guid" + "bytes" + "context" + "database/sql" + "fmt" + "os" + "strings" + "testing" + "time" + + "github.com/gogf/gf/v2/container/garray" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/encoding/gjson" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gfile" + "github.com/gogf/gf/v2/os/glog" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/test/gtest" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/guid" ) func Test_Model_Insert(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - user := db.Model(table) - result, err := user.Data(g.Map{ - "id": 1, - "uid": 1, - "passport": "t1", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "name_1", - "create_time": gtime.Now().String(), - }).Insert() - t.AssertNil(err) - n, _ := result.LastInsertId() - t.Assert(n, 1) - - result, err = db.Model(table).Data(g.Map{ - "id": "2", - "uid": "2", - "passport": "t2", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "name_2", - "create_time": gtime.Now().String(), - }).Insert() - t.AssertNil(err) - n, _ = result.RowsAffected() - t.Assert(n, 1) - - type User struct { - Id int `gconv:"id"` - Uid int `gconv:"uid"` - Passport string `json:"passport"` - Password string `gconv:"password"` - Nickname string `gconv:"nickname"` - CreateTime *gtime.Time `json:"create_time"` - } - // Model inserting. - result, err = db.Model(table).Data(User{ - Id: 3, - Uid: 3, - Passport: "t3", - Password: "25d55ad283aa400af464c76d713c07ad", - Nickname: "name_3", - }).Insert() - t.AssertNil(err) - n, _ = result.RowsAffected() - t.Assert(n, 1) - value, err := db.Model(table).Fields("passport").Where("id=3").Value() - t.AssertNil(err) - t.Assert(value.String(), "t3") - - result, err = db.Model(table).Data(&User{ - Id: 4, - Uid: 4, - Passport: "t4", - Password: "25d55ad283aa400af464c76d713c07ad", - Nickname: "T4", - CreateTime: gtime.Now(), - }).Insert() - t.AssertNil(err) - n, _ = result.RowsAffected() - t.Assert(n, 1) - value, err = db.Model(table).Fields("passport").Where("id=4").Value() - t.AssertNil(err) - t.Assert(value.String(), "t4") - - result, err = db.Model(table).Where("id>?", 1).Delete() - t.AssertNil(err) - n, _ = result.RowsAffected() - t.Assert(n, 3) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + user := db.Model(table) + result, err := user.Data(g.Map{ + "id": 1, + "uid": 1, + "passport": "t1", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_1", + "create_time": gtime.Now().String(), + }).Insert() + t.AssertNil(err) + n, _ := result.LastInsertId() + t.Assert(n, 1) + + result, err = db.Model(table).Data(g.Map{ + "id": "2", + "uid": "2", + "passport": "t2", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_2", + "create_time": gtime.Now().String(), + }).Insert() + t.AssertNil(err) + n, _ = result.RowsAffected() + t.Assert(n, 1) + + type User struct { + Id int `gconv:"id"` + Uid int `gconv:"uid"` + Passport string `json:"passport"` + Password string `gconv:"password"` + Nickname string `gconv:"nickname"` + CreateTime *gtime.Time `json:"create_time"` + } + // Model inserting. + result, err = db.Model(table).Data(User{ + Id: 3, + Uid: 3, + Passport: "t3", + Password: "25d55ad283aa400af464c76d713c07ad", + Nickname: "name_3", + }).Insert() + t.AssertNil(err) + n, _ = result.RowsAffected() + t.Assert(n, 1) + value, err := db.Model(table).Fields("passport").Where("id=3").Value() + t.AssertNil(err) + t.Assert(value.String(), "t3") + + result, err = db.Model(table).Data(&User{ + Id: 4, + Uid: 4, + Passport: "t4", + Password: "25d55ad283aa400af464c76d713c07ad", + Nickname: "T4", + CreateTime: gtime.Now(), + }).Insert() + t.AssertNil(err) + n, _ = result.RowsAffected() + t.Assert(n, 1) + value, err = db.Model(table).Fields("passport").Where("id=4").Value() + t.AssertNil(err) + t.Assert(value.String(), "t4") + + result, err = db.Model(table).Where("id>?", 1).Delete() + t.AssertNil(err) + n, _ = result.RowsAffected() + t.Assert(n, 3) + }) } // Fix issue: https://github.com/gogf/gf/issues/819 func Test_Model_Insert_WithStructAndSliceAttribute(t *testing.T) { - table := createTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - type Password struct { - Salt string `json:"salt"` - Pass string `json:"pass"` - } - data := g.Map{ - "id": 1, - "passport": "t1", - "password": &Password{"123", "456"}, - "nickname": []string{"A", "B", "C"}, - "create_time": gtime.Now().String(), - } - _, err := db.Model(table).Data(data).Insert() - t.AssertNil(err) - - one, err := db.Model(table).One("id", 1) - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["create_time"], data["create_time"]) - t.Assert(one["nickname"], gjson.New(data["nickname"]).MustToJson()) - }) + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type Password struct { + Salt string `json:"salt"` + Pass string `json:"pass"` + } + data := g.Map{ + "id": 1, + "passport": "t1", + "password": &Password{"123", "456"}, + "nickname": []string{"A", "B", "C"}, + "create_time": gtime.Now().String(), + } + _, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + + one, err := db.Model(table).One("id", 1) + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["create_time"], data["create_time"]) + t.Assert(one["nickname"], gjson.New(data["nickname"]).MustToJson()) + }) } func Test_Model_Insert_KeyFieldNameMapping(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - Nickname string - CreateTime string - } - data := User{ - Id: 1, - Passport: "user_1", - Password: "pass_1", - Nickname: "name_1", - CreateTime: "2020-10-10 12:00:01", - } - _, err := db.Model(table).Data(data).Insert() - t.AssertNil(err) - - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data.Passport) - t.Assert(one["create_time"], data.CreateTime) - t.Assert(one["nickname"], data.Nickname) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + Nickname string + CreateTime string + } + data := User{ + Id: 1, + Passport: "user_1", + Password: "pass_1", + Nickname: "name_1", + CreateTime: "2020-10-10 12:00:01", + } + _, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data.Passport) + t.Assert(one["create_time"], data.CreateTime) + t.Assert(one["nickname"], data.Nickname) + }) } func Test_Model_Update_KeyFieldNameMapping(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - Nickname string - CreateTime string - } - data := User{ - Id: 1, - Passport: "user_10", - Password: "pass_10", - Nickname: "name_10", - CreateTime: "2020-10-10 12:00:01", - } - _, err := db.Model(table).Data(data).WherePri(1).Update() - t.AssertNil(err) - - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data.Passport) - t.Assert(one["create_time"], data.CreateTime) - t.Assert(one["nickname"], data.Nickname) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + Nickname string + CreateTime string + } + data := User{ + Id: 1, + Passport: "user_10", + Password: "pass_10", + Nickname: "name_10", + CreateTime: "2020-10-10 12:00:01", + } + _, err := db.Model(table).Data(data).WherePri(1).Update() + t.AssertNil(err) + + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data.Passport) + t.Assert(one["create_time"], data.CreateTime) + t.Assert(one["nickname"], data.Nickname) + }) } func Test_Model_Insert_Time(t *testing.T) { - table := createTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "t1", - "password": "p1", - "nickname": "n1", - "create_time": "2020-10-10 20:09:18.334", - } - _, err := db.Model(table).Data(data).Insert() - t.AssertNil(err) - - one, err := db.Model(table).One("id", 1) - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["create_time"], "2020-10-10 20:09:18") - t.Assert(one["nickname"], data["nickname"]) - }) + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "t1", + "password": "p1", + "nickname": "n1", + "create_time": "2020-10-10 20:09:18.334", + } + _, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + + one, err := db.Model(table).One("id", 1) + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["create_time"], "2020-10-10 20:09:18") + t.Assert(one["nickname"], data["nickname"]) + }) } func Test_Model_BatchInsertWithArrayStruct(t *testing.T) { - table := createTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - user := db.Model(table) - array := garray.New() - for i := 1; i <= TableSize; i++ { - array.Append(g.Map{ - "id": i, - "uid": i, - "passport": fmt.Sprintf("t%d", i), - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": fmt.Sprintf("name_%d", i), - "create_time": gtime.Now().String(), - }) - } - - result, err := user.Data(array).Insert() - t.AssertNil(err) - n, _ := result.LastInsertId() - t.Assert(n, TableSize) - }) + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + user := db.Model(table) + array := garray.New() + for i := 1; i <= TableSize; i++ { + array.Append(g.Map{ + "id": i, + "uid": i, + "passport": fmt.Sprintf("t%d", i), + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": fmt.Sprintf("name_%d", i), + "create_time": gtime.Now().String(), + }) + } + + result, err := user.Data(array).Insert() + t.AssertNil(err) + n, _ := result.LastInsertId() + t.Assert(n, TableSize) + }) } func Test_Model_InsertIgnore(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).Data(g.Map{ - "id": 1, - "uid": 1, - "passport": "t1", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "name_1", - "create_time": gtime.Now().String(), - }).Insert() - t.AssertNE(err, nil) - }) - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).Data(g.Map{ - "id": 1, - "uid": 1, - "passport": "t1", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "name_1", - "create_time": gtime.Now().String(), - }).InsertIgnore() - t.AssertNil(err) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).Data(g.Map{ + "id": 1, + "uid": 1, + "passport": "t1", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_1", + "create_time": gtime.Now().String(), + }).Insert() + t.AssertNE(err, nil) + }) + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).Data(g.Map{ + "id": 1, + "uid": 1, + "passport": "t1", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_1", + "create_time": gtime.Now().String(), + }).InsertIgnore() + t.AssertNil(err) + }) } func Test_Model_Batch(t *testing.T) { - // batch insert - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - result, err := db.Model(table).Data(g.List{ - { - "id": 2, - "uid": 2, - "passport": "t2", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "name_2", - "create_time": gtime.Now().String(), - }, - { - "id": 3, - "uid": 3, - "passport": "t3", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "name_3", - "create_time": gtime.Now().String(), - }, - }).Batch(1).Insert() - if err != nil { - gtest.Error(err) - } - n, _ := result.RowsAffected() - 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.Model(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() - defer dropTable(table) - result, err := db.Model(table).All() - t.AssertNil(err) - t.Assert(len(result), TableSize) - for _, v := range result { - v["nickname"].Set(v["nickname"].String() + v["id"].String()) - } - r, e := db.Model(table).Data(result).Save() - t.Assert(e, nil) - n, e := r.RowsAffected() - t.Assert(e, nil) - t.Assert(n, TableSize*2) - }) - - // batch replace - gtest.C(t, func(t *gtest.T) { - table := createInitTable() - defer dropTable(table) - result, err := db.Model(table).All() - t.AssertNil(err) - t.Assert(len(result), TableSize) - for _, v := range result { - v["nickname"].Set(v["nickname"].String() + v["id"].String()) - } - r, e := db.Model(table).Data(result).Replace() - t.Assert(e, nil) - n, e := r.RowsAffected() - t.Assert(e, nil) - t.Assert(n, TableSize*2) - }) + // batch insert + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + result, err := db.Model(table).Data(g.List{ + { + "id": 2, + "uid": 2, + "passport": "t2", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_2", + "create_time": gtime.Now().String(), + }, + { + "id": 3, + "uid": 3, + "passport": "t3", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_3", + "create_time": gtime.Now().String(), + }, + }).Batch(1).Insert() + if err != nil { + gtest.Error(err) + } + n, _ := result.RowsAffected() + 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.Model(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() + defer dropTable(table) + result, err := db.Model(table).All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + for _, v := range result { + v["nickname"].Set(v["nickname"].String() + v["id"].String()) + } + r, e := db.Model(table).Data(result).Save() + t.Assert(e, nil) + n, e := r.RowsAffected() + t.Assert(e, nil) + t.Assert(n, TableSize*2) + }) + + // batch replace + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + result, err := db.Model(table).All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + for _, v := range result { + v["nickname"].Set(v["nickname"].String() + v["id"].String()) + } + r, e := db.Model(table).Data(result).Replace() + t.Assert(e, nil) + n, e := r.RowsAffected() + t.Assert(e, nil) + t.Assert(n, TableSize*2) + }) } func Test_Model_Replace(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data(g.Map{ - "id": 1, - "passport": "t11", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "T11", - "create_time": "2018-10-24 10:00:00", - }).Replace() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data(g.Map{ + "id": 1, + "passport": "t11", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "T11", + "create_time": "2018-10-24 10:00:00", + }).Replace() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) } func Test_Model_Save(t *testing.T) { - table := createTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data(g.Map{ - "id": 1, - "passport": "t111", - "password": "25d55ad283aa400af464c76d713c07ad", - "nickname": "T111", - "create_time": "2018-10-24 10:00:00", - }).Save() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data(g.Map{ + "id": 1, + "passport": "t111", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "T111", + "create_time": "2018-10-24 10:00:00", + }).Save() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) } func Test_Model_Update(t *testing.T) { - table := createInitTable() - defer dropTable(table) - // UPDATE...LIMIT - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data("nickname", "T100").Where(1).Order("id desc").Limit(2).Update() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 2) - - v1, err := db.Model(table).Fields("nickname").Where("id", 10).Value() - t.AssertNil(err) - t.Assert(v1.String(), "T100") - - v2, err := db.Model(table).Fields("nickname").Where("id", 8).Value() - t.AssertNil(err) - t.Assert(v2.String(), "name_8") - }) - - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data("passport", "user_22").Where("passport=?", "user_2").Update() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data("passport", "user_2").Where("passport='user_22'").Update() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - - // Update + Data(string) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data("passport='user_33'").Where("passport='user_3'").Update() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - // Update + Fields(string) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Fields("passport").Data(g.Map{ - "passport": "user_44", - "none": "none", - }).Where("passport='user_4'").Update() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) + table := createInitTable() + defer dropTable(table) + // UPDATE...LIMIT + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data("nickname", "T100").Where(1).Order("id desc").Limit(2).Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 2) + + v1, err := db.Model(table).Fields("nickname").Where("id", 10).Value() + t.AssertNil(err) + t.Assert(v1.String(), "T100") + + v2, err := db.Model(table).Fields("nickname").Where("id", 8).Value() + t.AssertNil(err) + t.Assert(v2.String(), "name_8") + }) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data("passport", "user_22").Where("passport=?", "user_2").Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data("passport", "user_2").Where("passport='user_22'").Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + + // Update + Data(string) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data("passport='user_33'").Where("passport='user_3'").Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + // Update + Fields(string) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Fields("passport").Data(g.Map{ + "passport": "user_44", + "none": "none", + }).Where("passport='user_4'").Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) } func Test_Model_UpdateAndGetAffected(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - n, err := db.Model(table).Data("nickname", "T100"). - Where(1).Order("id desc").Limit(2). - UpdateAndGetAffected() - t.AssertNil(err) - t.Assert(n, 2) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + n, err := db.Model(table).Data("nickname", "T100"). + Where(1).Order("id desc").Limit(2). + UpdateAndGetAffected() + t.AssertNil(err) + t.Assert(n, 2) + }) } func Test_Model_Clone(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - md := db.Model(table).Safe(true).Where("id IN(?)", g.Slice{1, 3}) - count, err := md.Count() - t.AssertNil(err) + gtest.C(t, func(t *gtest.T) { + md := db.Model(table).Safe(true).Where("id IN(?)", g.Slice{1, 3}) + count, err := md.Count() + t.AssertNil(err) - record, err := md.Safe(true).Order("id DESC").One() - t.AssertNil(err) + record, err := md.Safe(true).Order("id DESC").One() + t.AssertNil(err) - result, err := md.Safe(true).Order("id ASC").All() - t.AssertNil(err) + result, err := md.Safe(true).Order("id ASC").All() + t.AssertNil(err) - t.Assert(count, int64(2)) - t.Assert(record["id"].Int(), 3) - t.Assert(len(result), 2) - t.Assert(result[0]["id"].Int(), 1) - t.Assert(result[1]["id"].Int(), 3) - }) + t.Assert(count, int64(2)) + t.Assert(record["id"].Int(), 3) + t.Assert(len(result), 2) + t.Assert(result[0]["id"].Int(), 1) + t.Assert(result[1]["id"].Int(), 3) + }) } func Test_Model_Safe(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - md := db.Model(table).Safe(false).Where("id IN(?)", g.Slice{1, 3}) - count, err := md.Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - - md.Where("id = ?", 1) - count, err = md.Count() - t.AssertNil(err) - t.Assert(count, int64(1)) - }) - gtest.C(t, func(t *gtest.T) { - md := db.Model(table).Safe(true).Where("id IN(?)", g.Slice{1, 3}) - count, err := md.Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - - md.Where("id = ?", 1) - count, err = md.Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - }) - - gtest.C(t, func(t *gtest.T) { - md := db.Model(table).Safe().Where("id IN(?)", g.Slice{1, 3}) - count, err := md.Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - - md.Where("id = ?", 1) - count, err = md.Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - }) - gtest.C(t, func(t *gtest.T) { - md1 := db.Model(table).Safe() - md2 := md1.Where("id in (?)", g.Slice{1, 3}) - count, err := md2.Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - - all, err := md2.All() - t.AssertNil(err) - t.Assert(len(all), 2) - - all, err = md2.Page(1, 10).All() - t.AssertNil(err) - t.Assert(len(all), 2) - }) - - gtest.C(t, func(t *gtest.T) { - table := createInitTable() - defer dropTable(table) - - md1 := db.Model(table).Where("id>", 0).Safe() - md2 := md1.Where("id in (?)", g.Slice{1, 3}) - md3 := md1.Where("id in (?)", g.Slice{4, 5, 6}) - - // 1,3 - count, err := md2.Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - - all, err := md2.Order("id asc").All() - t.AssertNil(err) - t.Assert(len(all), 2) - t.Assert(all[0]["id"].Int(), 1) - t.Assert(all[1]["id"].Int(), 3) - - all, err = md2.Page(1, 10).All() - t.AssertNil(err) - t.Assert(len(all), 2) - - // 4,5,6 - count, err = md3.Count() - t.AssertNil(err) - t.Assert(count, int64(3)) - - all, err = md3.Order("id asc").All() - t.AssertNil(err) - t.Assert(len(all), 3) - t.Assert(all[0]["id"].Int(), 4) - t.Assert(all[1]["id"].Int(), 5) - t.Assert(all[2]["id"].Int(), 6) - - all, err = md3.Page(1, 10).All() - t.AssertNil(err) - t.Assert(len(all), 3) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + md := db.Model(table).Safe(false).Where("id IN(?)", g.Slice{1, 3}) + count, err := md.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + + md.Where("id = ?", 1) + count, err = md.Count() + t.AssertNil(err) + t.Assert(count, int64(1)) + }) + gtest.C(t, func(t *gtest.T) { + md := db.Model(table).Safe(true).Where("id IN(?)", g.Slice{1, 3}) + count, err := md.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + + md.Where("id = ?", 1) + count, err = md.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + }) + + gtest.C(t, func(t *gtest.T) { + md := db.Model(table).Safe().Where("id IN(?)", g.Slice{1, 3}) + count, err := md.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + + md.Where("id = ?", 1) + count, err = md.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + }) + gtest.C(t, func(t *gtest.T) { + md1 := db.Model(table).Safe() + md2 := md1.Where("id in (?)", g.Slice{1, 3}) + count, err := md2.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + + all, err := md2.All() + t.AssertNil(err) + t.Assert(len(all), 2) + + all, err = md2.Page(1, 10).All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + + md1 := db.Model(table).Where("id>", 0).Safe() + md2 := md1.Where("id in (?)", g.Slice{1, 3}) + md3 := md1.Where("id in (?)", g.Slice{4, 5, 6}) + + // 1,3 + count, err := md2.Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + + all, err := md2.Order("id asc").All() + t.AssertNil(err) + t.Assert(len(all), 2) + t.Assert(all[0]["id"].Int(), 1) + t.Assert(all[1]["id"].Int(), 3) + + all, err = md2.Page(1, 10).All() + t.AssertNil(err) + t.Assert(len(all), 2) + + // 4,5,6 + count, err = md3.Count() + t.AssertNil(err) + t.Assert(count, int64(3)) + + all, err = md3.Order("id asc").All() + t.AssertNil(err) + t.Assert(len(all), 3) + t.Assert(all[0]["id"].Int(), 4) + t.Assert(all[1]["id"].Int(), 5) + t.Assert(all[2]["id"].Int(), 6) + + all, err = md3.Page(1, 10).All() + t.AssertNil(err) + t.Assert(len(all), 3) + }) } func Test_Model_All(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).All() - t.AssertNil(err) - t.Assert(len(result), TableSize) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Where("id<0").All() - t.Assert(result, nil) - t.AssertNil(err) - }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("id<0").All() + t.Assert(result, nil) + t.AssertNil(err) + }) } func Test_Model_Fields(t *testing.T) { - tableName1 := createInitTable() - defer dropTable(tableName1) + tableName1 := createInitTable() + defer dropTable(tableName1) - tableName2 := "user_" + gtime.Now().TimestampNanoStr() - if _, err := db.Exec(ctx, fmt.Sprintf(` + tableName2 := "user_" + gtime.Now().TimestampNanoStr() + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE %s ( id int(10) unsigned NOT NULL AUTO_INCREMENT, name varchar(45) NULL, @@ -592,1924 +592,1924 @@ func Test_Model_Fields(t *testing.T) { PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; `, tableName2, - )); err != nil { - gtest.AssertNil(err) - } - defer dropTable(tableName2) - - r, err := db.Insert(ctx, tableName2, g.Map{ - "id": 1, - "name": "table2_1", - "age": 18, - }) - gtest.AssertNil(err) - n, _ := r.RowsAffected() - gtest.Assert(n, 1) - - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(tableName1).As("u").Fields("u.passport,u.id").Where("u.id<2").All() - t.AssertNil(err) - t.Assert(len(all), 1) - t.Assert(len(all[0]), 2) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(tableName1).As("u1"). - LeftJoin(tableName1, "u2", "u2.id=u1.id"). - Fields("u1.passport,u1.id,u2.id AS u2id"). - Where("u1.id<2"). - All() - t.AssertNil(err) - t.Assert(len(all), 1) - t.Assert(len(all[0]), 3) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(tableName1).As("u1"). - LeftJoin(tableName2, "u2", "u2.id=u1.id"). - Fields("u1.passport,u1.id,u2.name,u2.age"). - Where("u1.id<2"). - All() - t.AssertNil(err) - t.Assert(len(all), 1) - t.Assert(len(all[0]), 4) - t.Assert(all[0]["id"], 1) - t.Assert(all[0]["age"], 18) - t.Assert(all[0]["name"], "table2_1") - t.Assert(all[0]["passport"], "user_1") - }) + )); err != nil { + gtest.AssertNil(err) + } + defer dropTable(tableName2) + + r, err := db.Insert(ctx, tableName2, g.Map{ + "id": 1, + "name": "table2_1", + "age": 18, + }) + gtest.AssertNil(err) + n, _ := r.RowsAffected() + gtest.Assert(n, 1) + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(tableName1).As("u").Fields("u.passport,u.id").Where("u.id<2").All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(len(all[0]), 2) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(tableName1).As("u1"). + LeftJoin(tableName1, "u2", "u2.id=u1.id"). + Fields("u1.passport,u1.id,u2.id AS u2id"). + Where("u1.id<2"). + All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(len(all[0]), 3) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(tableName1).As("u1"). + LeftJoin(tableName2, "u2", "u2.id=u1.id"). + Fields("u1.passport,u1.id,u2.name,u2.age"). + Where("u1.id<2"). + All() + t.AssertNil(err) + t.Assert(len(all), 1) + t.Assert(len(all[0]), 4) + t.Assert(all[0]["id"], 1) + t.Assert(all[0]["age"], 18) + t.Assert(all[0]["name"], "table2_1") + t.Assert(all[0]["passport"], "user_1") + }) } func Test_Model_One(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - record, err := db.Model(table).Where("id", 1).One() - t.AssertNil(err) - t.Assert(record["nickname"].String(), "name_1") - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + record, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.Assert(record["nickname"].String(), "name_1") + }) - gtest.C(t, func(t *gtest.T) { - record, err := db.Model(table).Where("id", 0).One() - t.AssertNil(err) - t.Assert(record, nil) - }) + gtest.C(t, func(t *gtest.T) { + record, err := db.Model(table).Where("id", 0).One() + t.AssertNil(err) + t.Assert(record, nil) + }) } func Test_Model_Value(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).Fields("nickname").Where("id", 1).Value() - t.AssertNil(err) - t.Assert(value.String(), "name_1") - }) + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Fields("nickname").Where("id", 1).Value() + t.AssertNil(err) + t.Assert(value.String(), "name_1") + }) - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).Fields("nickname").Where("id", 0).Value() - t.AssertNil(err) - t.Assert(value, nil) - }) + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Fields("nickname").Where("id", 0).Value() + t.AssertNil(err) + t.Assert(value, nil) + }) } func Test_Model_Array(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id", g.Slice{1, 2, 3}).All() - t.AssertNil(err) - t.Assert(all.Array("id"), g.Slice{1, 2, 3}) - t.Assert(all.Array("nickname"), g.Slice{"name_1", "name_2", "name_3"}) - }) - - gtest.C(t, func(t *gtest.T) { - array, err := db.Model(table).Fields("nickname").Where("id", g.Slice{1, 2, 3}).Array() - t.AssertNil(err) - t.Assert(array, g.Slice{"name_1", "name_2", "name_3"}) - }) - gtest.C(t, func(t *gtest.T) { - array, err := db.Model(table).Array("nickname", "id", g.Slice{1, 2, 3}) - t.AssertNil(err) - t.Assert(array, g.Slice{"name_1", "name_2", "name_3"}) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id", g.Slice{1, 2, 3}).All() + t.AssertNil(err) + t.Assert(all.Array("id"), g.Slice{1, 2, 3}) + t.Assert(all.Array("nickname"), g.Slice{"name_1", "name_2", "name_3"}) + }) + + gtest.C(t, func(t *gtest.T) { + array, err := db.Model(table).Fields("nickname").Where("id", g.Slice{1, 2, 3}).Array() + t.AssertNil(err) + t.Assert(array, g.Slice{"name_1", "name_2", "name_3"}) + }) + gtest.C(t, func(t *gtest.T) { + array, err := db.Model(table).Array("nickname", "id", g.Slice{1, 2, 3}) + t.AssertNil(err) + t.Assert(array, g.Slice{"name_1", "name_2", "name_3"}) + }) } func Test_Model_Count(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) - // Count with cache, check internal ctx data feature. - gtest.C(t, func(t *gtest.T) { - for i := 0; i < 10; i++ { - count, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Name: guid.S(), - Force: false, - }).Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - } - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).FieldsEx("id").Where("id>8").Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Fields("distinct id,nickname").Where("id>8").Count() - t.AssertNil(err) - t.Assert(count, int64(2)) - }) - // COUNT...LIMIT... - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Page(1, 2).Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) + // Count with cache, check internal ctx data feature. + gtest.C(t, func(t *gtest.T) { + for i := 0; i < 10; i++ { + count, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Name: guid.S(), + Force: false, + }).Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + } + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).FieldsEx("id").Where("id>8").Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Fields("distinct id,nickname").Where("id>8").Count() + t.AssertNil(err) + t.Assert(count, int64(2)) + }) + // COUNT...LIMIT... + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Page(1, 2).Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) } func Test_Model_Exist(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - exist, err := db.Model(table).Exist() - t.AssertNil(err) - t.Assert(exist, TableSize > 0) - exist, err = db.Model(table).Where("id", -1).Exist() - t.AssertNil(err) - t.Assert(exist, false) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + exist, err := db.Model(table).Exist() + t.AssertNil(err) + t.Assert(exist, TableSize > 0) + exist, err = db.Model(table).Where("id", -1).Exist() + t.AssertNil(err) + t.Assert(exist, false) + }) } func Test_Model_Value_WithCache(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).Value() - t.AssertNil(err) - t.Assert(value.Int(), 0) - }) - return - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data(g.MapStrAny{ - "id": 1, - "passport": fmt.Sprintf(`passport_%d`, 1), - "password": fmt.Sprintf(`password_%d`, 1), - "nickname": fmt.Sprintf(`nickname_%d`, 1), - }).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).Value("id") - t.AssertNil(err) - t.Assert(value.Int(), 1) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).Value() + t.AssertNil(err) + t.Assert(value.Int(), 0) + }) + return + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data(g.MapStrAny{ + "id": 1, + "passport": fmt.Sprintf(`passport_%d`, 1), + "password": fmt.Sprintf(`password_%d`, 1), + "nickname": fmt.Sprintf(`nickname_%d`, 1), + }).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).Value("id") + t.AssertNil(err) + t.Assert(value.Int(), 1) + }) } func Test_Model_Count_WithCache(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).Count() - t.AssertNil(err) - t.Assert(count, int64(0)) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data(g.MapStrAny{ - "id": 1, - "passport": fmt.Sprintf(`passport_%d`, 1), - "password": fmt.Sprintf(`password_%d`, 1), - "nickname": fmt.Sprintf(`nickname_%d`, 1), - }).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).Count() - t.AssertNil(err) - t.Assert(count, int64(1)) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).Count() + t.AssertNil(err) + t.Assert(count, int64(0)) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data(g.MapStrAny{ + "id": 1, + "passport": fmt.Sprintf(`passport_%d`, 1), + "password": fmt.Sprintf(`password_%d`, 1), + "nickname": fmt.Sprintf(`nickname_%d`, 1), + }).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).Count() + t.AssertNil(err) + t.Assert(count, int64(1)) + }) } func Test_Model_Count_All_WithCache(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).Count() - t.AssertNil(err) - t.Assert(count, int64(0)) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data(g.MapStrAny{ - "id": 1, - "passport": fmt.Sprintf(`passport_%d`, 1), - "password": fmt.Sprintf(`password_%d`, 1), - "nickname": fmt.Sprintf(`nickname_%d`, 1), - }).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).Count() - t.AssertNil(err) - t.Assert(count, int64(1)) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data(g.MapStrAny{ - "id": 2, - "passport": fmt.Sprintf(`passport_%d`, 2), - "password": fmt.Sprintf(`password_%d`, 2), - "nickname": fmt.Sprintf(`nickname_%d`, 2), - }).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).Count() - t.AssertNil(err) - t.Assert(count, int64(1)) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).Count() + t.AssertNil(err) + t.Assert(count, int64(0)) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data(g.MapStrAny{ + "id": 1, + "passport": fmt.Sprintf(`passport_%d`, 1), + "password": fmt.Sprintf(`password_%d`, 1), + "nickname": fmt.Sprintf(`nickname_%d`, 1), + }).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).Count() + t.AssertNil(err) + t.Assert(count, int64(1)) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data(g.MapStrAny{ + "id": 2, + "passport": fmt.Sprintf(`passport_%d`, 2), + "password": fmt.Sprintf(`password_%d`, 2), + "nickname": fmt.Sprintf(`nickname_%d`, 2), + }).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).Count() + t.AssertNil(err) + t.Assert(count, int64(1)) + }) } func Test_Model_CountColumn_WithCache(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).CountColumn("id") - t.AssertNil(err) - t.Assert(count, int64(0)) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Data(g.MapStrAny{ - "id": 1, - "passport": fmt.Sprintf(`passport_%d`, 1), - "password": fmt.Sprintf(`password_%d`, 1), - "nickname": fmt.Sprintf(`nickname_%d`, 1), - }).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ - Duration: time.Second * 10, - Force: false, - }).CountColumn("id") - t.AssertNil(err) - t.Assert(count, int64(1)) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).CountColumn("id") + t.AssertNil(err) + t.Assert(count, int64(0)) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Data(g.MapStrAny{ + "id": 1, + "passport": fmt.Sprintf(`passport_%d`, 1), + "password": fmt.Sprintf(`password_%d`, 1), + "nickname": fmt.Sprintf(`nickname_%d`, 1), + }).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 1).Cache(gdb.CacheOption{ + Duration: time.Second * 10, + Force: false, + }).CountColumn("id") + t.AssertNil(err) + t.Assert(count, int64(1)) + }) } func Test_Model_Select(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime gtime.Time - } - gtest.C(t, func(t *gtest.T) { - var users []User - err := db.Model(table).Scan(&users) - t.AssertNil(err) - t.Assert(len(users), TableSize) - }) + table := createInitTable() + defer dropTable(table) + + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + gtest.C(t, func(t *gtest.T) { + var users []User + err := db.Model(table).Scan(&users) + t.AssertNil(err) + t.Assert(len(users), TableSize) + }) } func Test_Model_Struct(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime gtime.Time - } - user := new(User) - err := db.Model(table).Where("id=1").Scan(user) - t.AssertNil(err) - t.Assert(user.NickName, "name_1") - t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") - }) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - user := new(User) - err := db.Model(table).Where("id=1").Scan(user) - t.AssertNil(err) - t.Assert(user.NickName, "name_1") - t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") - }) - // Auto creating struct object. - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - user := (*User)(nil) - err := db.Model(table).Where("id=1").Scan(&user) - t.AssertNil(err) - t.Assert(user.NickName, "name_1") - t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") - }) - // Just using Scan. - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - user := (*User)(nil) - err := db.Model(table).Where("id=1").Scan(&user) - if err != nil { - gtest.Error(err) - } - t.Assert(user.NickName, "name_1") - t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") - }) - // sql.ErrNoRows - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - user := new(User) - err := db.Model(table).Where("id=-1").Scan(user) - t.Assert(err, sql.ErrNoRows) - }) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - var user *User - err := db.Model(table).Where("id=-1").Scan(&user) - t.AssertNil(err) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=1").Scan(user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=1").Scan(user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") + }) + // Auto creating struct object. + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := (*User)(nil) + err := db.Model(table).Where("id=1").Scan(&user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") + }) + // Just using Scan. + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := (*User)(nil) + err := db.Model(table).Where("id=1").Scan(&user) + if err != nil { + gtest.Error(err) + } + t.Assert(user.NickName, "name_1") + t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") + }) + // sql.ErrNoRows + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=-1").Scan(user) + t.Assert(err, sql.ErrNoRows) + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var user *User + err := db.Model(table).Where("id=-1").Scan(&user) + t.AssertNil(err) + }) } func Test_Model_Struct_CustomType(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - type MyInt int - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id MyInt - Passport string - Password string - NickName string - CreateTime gtime.Time - } - user := new(User) - err := db.Model(table).Where("id=1").Scan(user) - t.AssertNil(err) - t.Assert(user.NickName, "name_1") - t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") - }) + table := createInitTable() + defer dropTable(table) + + type MyInt int + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id MyInt + Passport string + Password string + NickName string + CreateTime gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=1").Scan(user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") + }) } func Test_Model_Structs(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime gtime.Time - } - var users []User - err := db.Model(table).Order("id asc").Scan(&users) - if err != nil { - gtest.Error(err) - } - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - t.Assert(users[1].Id, 2) - t.Assert(users[2].Id, 3) - t.Assert(users[0].NickName, "name_1") - t.Assert(users[1].NickName, "name_2") - t.Assert(users[2].NickName, "name_3") - t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") - }) - // Auto create struct slice. - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - var users []*User - err := db.Model(table).Order("id asc").Scan(&users) - if err != nil { - gtest.Error(err) - } - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - t.Assert(users[1].Id, 2) - t.Assert(users[2].Id, 3) - t.Assert(users[0].NickName, "name_1") - t.Assert(users[1].NickName, "name_2") - t.Assert(users[2].NickName, "name_3") - t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") - }) - // Just using Scan. - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - var users []*User - err := db.Model(table).Order("id asc").Scan(&users) - if err != nil { - gtest.Error(err) - } - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - t.Assert(users[1].Id, 2) - t.Assert(users[2].Id, 3) - t.Assert(users[0].NickName, "name_1") - t.Assert(users[1].NickName, "name_2") - t.Assert(users[2].NickName, "name_3") - t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") - }) - // sql.ErrNoRows - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - var users []*User - err := db.Model(table).Where("id<0").Scan(&users) - t.AssertNil(err) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + var users []User + err := db.Model(table).Order("id asc").Scan(&users) + if err != nil { + gtest.Error(err) + } + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[1].Id, 2) + t.Assert(users[2].Id, 3) + t.Assert(users[0].NickName, "name_1") + t.Assert(users[1].NickName, "name_2") + t.Assert(users[2].NickName, "name_3") + t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") + }) + // Auto create struct slice. + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var users []*User + err := db.Model(table).Order("id asc").Scan(&users) + if err != nil { + gtest.Error(err) + } + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[1].Id, 2) + t.Assert(users[2].Id, 3) + t.Assert(users[0].NickName, "name_1") + t.Assert(users[1].NickName, "name_2") + t.Assert(users[2].NickName, "name_3") + t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") + }) + // Just using Scan. + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var users []*User + err := db.Model(table).Order("id asc").Scan(&users) + if err != nil { + gtest.Error(err) + } + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[1].Id, 2) + t.Assert(users[2].Id, 3) + t.Assert(users[0].NickName, "name_1") + t.Assert(users[1].NickName, "name_2") + t.Assert(users[2].NickName, "name_3") + t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") + }) + // sql.ErrNoRows + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var users []*User + err := db.Model(table).Where("id<0").Scan(&users) + t.AssertNil(err) + }) } func Test_Model_StructsWithOrmTag(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - dbInvalid.SetDebug(true) - defer dbInvalid.SetDebug(false) - gtest.C(t, func(t *gtest.T) { - type User struct { - Uid int `orm:"id"` - Passport string - Password string `orm:"password"` - Name string `orm:"nick_name"` - Time gtime.Time `orm:"create_time"` - } - var ( - users []User - buffer = bytes.NewBuffer(nil) - ) - dbInvalid.GetLogger().(*glog.Logger).SetWriter(buffer) - defer dbInvalid.GetLogger().(*glog.Logger).SetWriter(os.Stdout) - dbInvalid.Model(table).Order("id asc").Scan(&users) - // fmt.Println(buffer.String()) - t.Assert( - gstr.Contains( - buffer.String(), - "SELECT `id`,`Passport`,`password`,`nick_name`,`create_time` FROM `user", - ), - true, - ) - }) - - // db.SetDebug(true) - // defer db.SetDebug(false) - gtest.C(t, func(t *gtest.T) { - type A struct { - Passport string - Password string - } - type B struct { - A - NickName string - } - one, err := db.Model(table).Fields(&B{}).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 3) - t.Assert(one["nickname"], "name_2") - t.Assert(one["passport"], "user_2") - t.Assert(one["password"], "pass_2") - }) + table := createInitTable() + defer dropTable(table) + + dbInvalid.SetDebug(true) + defer dbInvalid.SetDebug(false) + gtest.C(t, func(t *gtest.T) { + type User struct { + Uid int `orm:"id"` + Passport string + Password string `orm:"password"` + Name string `orm:"nick_name"` + Time gtime.Time `orm:"create_time"` + } + var ( + users []User + buffer = bytes.NewBuffer(nil) + ) + dbInvalid.GetLogger().(*glog.Logger).SetWriter(buffer) + defer dbInvalid.GetLogger().(*glog.Logger).SetWriter(os.Stdout) + dbInvalid.Model(table).Order("id asc").Scan(&users) + // fmt.Println(buffer.String()) + t.Assert( + gstr.Contains( + buffer.String(), + "SELECT `id`,`Passport`,`password`,`nick_name`,`create_time` FROM `user", + ), + true, + ) + }) + + // db.SetDebug(true) + // defer db.SetDebug(false) + gtest.C(t, func(t *gtest.T) { + type A struct { + Passport string + Password string + } + type B struct { + A + NickName string + } + one, err := db.Model(table).Fields(&B{}).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 3) + t.Assert(one["nickname"], "name_2") + t.Assert(one["passport"], "user_2") + t.Assert(one["password"], "pass_2") + }) } func Test_Model_Scan(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime gtime.Time - } - user := new(User) - err := db.Model(table).Where("id=1").Scan(user) - t.AssertNil(err) - t.Assert(user.NickName, "name_1") - t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") - }) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - user := new(User) - err := db.Model(table).Where("id=1").Scan(user) - t.AssertNil(err) - t.Assert(user.NickName, "name_1") - t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") - }) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime gtime.Time - } - var users []User - err := db.Model(table).Order("id asc").Scan(&users) - t.AssertNil(err) - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - t.Assert(users[1].Id, 2) - t.Assert(users[2].Id, 3) - t.Assert(users[0].NickName, "name_1") - t.Assert(users[1].NickName, "name_2") - t.Assert(users[2].NickName, "name_3") - t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") - }) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - var users []*User - err := db.Model(table).Order("id asc").Scan(&users) - t.AssertNil(err) - t.Assert(len(users), TableSize) - t.Assert(users[0].Id, 1) - t.Assert(users[1].Id, 2) - t.Assert(users[2].Id, 3) - t.Assert(users[0].NickName, "name_1") - t.Assert(users[1].NickName, "name_2") - t.Assert(users[2].NickName, "name_3") - t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") - }) - // sql.ErrNoRows - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime *gtime.Time - } - var ( - user = new(User) - users = new([]*User) - ) - err1 := db.Model(table).Where("id < 0").Scan(user) - err2 := db.Model(table).Where("id < 0").Scan(users) - t.Assert(err1, sql.ErrNoRows) - t.Assert(err2, nil) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=1").Scan(user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + user := new(User) + err := db.Model(table).Where("id=1").Scan(user) + t.AssertNil(err) + t.Assert(user.NickName, "name_1") + t.Assert(user.CreateTime.String(), "2018-10-24 10:00:00") + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + var users []User + err := db.Model(table).Order("id asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[1].Id, 2) + t.Assert(users[2].Id, 3) + t.Assert(users[0].NickName, "name_1") + t.Assert(users[1].NickName, "name_2") + t.Assert(users[2].NickName, "name_3") + t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var users []*User + err := db.Model(table).Order("id asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), TableSize) + t.Assert(users[0].Id, 1) + t.Assert(users[1].Id, 2) + t.Assert(users[2].Id, 3) + t.Assert(users[0].NickName, "name_1") + t.Assert(users[1].NickName, "name_2") + t.Assert(users[2].NickName, "name_3") + t.Assert(users[0].CreateTime.String(), "2018-10-24 10:00:00") + }) + // sql.ErrNoRows + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime *gtime.Time + } + var ( + user = new(User) + users = new([]*User) + ) + err1 := db.Model(table).Where("id < 0").Scan(user) + err2 := db.Model(table).Where("id < 0").Scan(users) + t.Assert(err1, sql.ErrNoRows) + t.Assert(err2, nil) + }) } func Test_Model_Scan_NilSliceAttrWhenNoRecordsFound(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - CreateTime gtime.Time - } - type Response struct { - Users []User `json:"users"` - } - var res Response - err := db.Model(table).Scan(&res.Users) - t.AssertNil(err) - t.Assert(res.Users, nil) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + CreateTime gtime.Time + } + type Response struct { + Users []User `json:"users"` + } + var res Response + err := db.Model(table).Scan(&res.Users) + t.AssertNil(err) + t.Assert(res.Users, nil) + }) } func Test_Model_OrderBy(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Order("id DESC").All() - t.AssertNil(err) - t.Assert(len(result), TableSize) - t.Assert(result[0]["nickname"].String(), fmt.Sprintf("name_%d", TableSize)) - }) - - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Order(gdb.Raw("NULL")).All() - t.AssertNil(err) - t.Assert(len(result), TableSize) - t.Assert(result[0]["nickname"].String(), "name_1") - }) - - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Order(gdb.Raw("field(id, 10,1,2,3,4,5,6,7,8,9)")).All() - t.AssertNil(err) - t.Assert(len(result), TableSize) - t.Assert(result[0]["nickname"].String(), "name_10") - t.Assert(result[1]["nickname"].String(), "name_1") - t.Assert(result[2]["nickname"].String(), "name_2") - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Order("id DESC").All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + t.Assert(result[0]["nickname"].String(), fmt.Sprintf("name_%d", TableSize)) + }) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Order(gdb.Raw("NULL")).All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + t.Assert(result[0]["nickname"].String(), "name_1") + }) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Order(gdb.Raw("field(id, 10,1,2,3,4,5,6,7,8,9)")).All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + t.Assert(result[0]["nickname"].String(), "name_10") + t.Assert(result[1]["nickname"].String(), "name_1") + t.Assert(result[2]["nickname"].String(), "name_2") + }) } func Test_Model_GroupBy(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Group("id").All() - t.AssertNil(err) - t.Assert(len(result), TableSize) - t.Assert(result[0]["nickname"].String(), "name_1") - }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Group("id").All() + t.AssertNil(err) + t.Assert(len(result), TableSize) + t.Assert(result[0]["nickname"].String(), "name_1") + }) } func Test_Model_Data(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - table := createInitTable() - defer dropTable(table) - result, err := db.Model(table).Data("nickname=?", "test").Where("id=?", 3).Update() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - }) - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - users := make([]g.MapStrAny, 0) - for i := 1; i <= 10; i++ { - users = append(users, g.MapStrAny{ - "id": i, - "passport": fmt.Sprintf(`passport_%d`, i), - "password": fmt.Sprintf(`password_%d`, i), - "nickname": fmt.Sprintf(`nickname_%d`, i), - }) - } - result, err := db.Model(table).Data(users).Batch(2).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 10) - }) - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - users := garray.New() - for i := 1; i <= 10; i++ { - users.Append(g.MapStrAny{ - "id": i, - "passport": fmt.Sprintf(`passport_%d`, i), - "password": fmt.Sprintf(`password_%d`, i), - "nickname": fmt.Sprintf(`nickname_%d`, i), - }) - } - result, err := db.Model(table).Data(users).Batch(2).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 10) - }) + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + result, err := db.Model(table).Data("nickname=?", "test").Where("id=?", 3).Update() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + users := make([]g.MapStrAny, 0) + for i := 1; i <= 10; i++ { + users = append(users, g.MapStrAny{ + "id": i, + "passport": fmt.Sprintf(`passport_%d`, i), + "password": fmt.Sprintf(`password_%d`, i), + "nickname": fmt.Sprintf(`nickname_%d`, i), + }) + } + result, err := db.Model(table).Data(users).Batch(2).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 10) + }) + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + users := garray.New() + for i := 1; i <= 10; i++ { + users.Append(g.MapStrAny{ + "id": i, + "passport": fmt.Sprintf(`passport_%d`, i), + "password": fmt.Sprintf(`password_%d`, i), + "nickname": fmt.Sprintf(`nickname_%d`, i), + }) + } + result, err := db.Model(table).Data(users).Batch(2).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 10) + }) } func Test_Model_Delete(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - // DELETE...LIMIT - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Where(1).Limit(2).Delete() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 2) - }) + // DELETE...LIMIT + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(1).Limit(2).Delete() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 2) + }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Where(1).Delete() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, TableSize-2) - }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(1).Delete() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, TableSize-2) + }) } func Test_Model_Offset(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Limit(2).Offset(5).Order("id").All() - t.AssertNil(err) - t.Assert(len(result), 2) - t.Assert(result[0]["id"], 6) - t.Assert(result[1]["id"], 7) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Limit(2).Offset(5).Order("id").All() + t.AssertNil(err) + t.Assert(len(result), 2) + t.Assert(result[0]["id"], 6) + t.Assert(result[1]["id"], 7) + }) } func Test_Model_Page(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Page(3, 3).Order("id").All() - t.AssertNil(err) - t.Assert(len(result), 3) - t.Assert(result[0]["id"], 7) - t.Assert(result[1]["id"], 8) - }) - gtest.C(t, func(t *gtest.T) { - model := db.Model(table).Safe().Order("id") - all, err := model.Page(3, 3).All() - count, err := model.Count() - t.AssertNil(err) - t.Assert(len(all), 3) - t.Assert(all[0]["id"], "7") - t.Assert(count, int64(TableSize)) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Page(3, 3).Order("id").All() + t.AssertNil(err) + t.Assert(len(result), 3) + t.Assert(result[0]["id"], 7) + t.Assert(result[1]["id"], 8) + }) + gtest.C(t, func(t *gtest.T) { + model := db.Model(table).Safe().Order("id") + all, err := model.Page(3, 3).All() + count, err := model.Count() + t.AssertNil(err) + t.Assert(len(all), 3) + t.Assert(all[0]["id"], "7") + t.Assert(count, int64(TableSize)) + }) } func Test_Model_Option_Map(t *testing.T) { - // Insert - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - r, err := db.Model(table).Fields("id, passport").Data(g.Map{ - "id": 1, - "passport": "1", - "password": "1", - "nickname": "1", - }).Insert() - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - one, err := db.Model(table).Where("id", 1).One() - t.AssertNil(err) - t.AssertNE(one["password"].String(), "1") - t.AssertNE(one["nickname"].String(), "1") - t.Assert(one["passport"].String(), "1") - }) - - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - r, err := db.Model(table).OmitEmptyData().Data(g.Map{ - "id": 1, - "passport": 0, - "password": 0, - "nickname": "1", - }).Insert() - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - one, err := db.Model(table).Where("id", 1).One() - t.AssertNil(err) - t.AssertNE(one["passport"].String(), "0") - t.AssertNE(one["password"].String(), "0") - t.Assert(one["nickname"].String(), "1") - }) - - // Replace - gtest.C(t, func(t *gtest.T) { - table := createInitTable() - defer dropTable(table) - _, err := db.Model(table).OmitEmptyData().Data(g.Map{ - "id": 1, - "passport": 0, - "password": 0, - "nickname": "1", - }).Replace() - t.AssertNil(err) - one, err := db.Model(table).Where("id", 1).One() - t.AssertNil(err) - t.AssertNE(one["passport"].String(), "0") - t.AssertNE(one["password"].String(), "0") - t.Assert(one["nickname"].String(), "1") - }) - - // Save - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - r, err := db.Model(table).Fields("id, passport").Data(g.Map{ - "id": 1, - "passport": "1", - "password": "1", - "nickname": "1", - }).Save() - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - one, err := db.Model(table).Where("id", 1).One() - t.AssertNil(err) - t.AssertNE(one["password"].String(), "1") - t.AssertNE(one["nickname"].String(), "1") - t.Assert(one["passport"].String(), "1") - }) - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - _, err := db.Model(table).OmitEmptyData().Data(g.Map{ - "id": 1, - "passport": 0, - "password": 0, - "nickname": "1", - }).Save() - t.AssertNil(err) - one, err := db.Model(table).Where("id", 1).One() - t.AssertNil(err) - t.AssertNE(one["passport"].String(), "0") - t.AssertNE(one["password"].String(), "0") - t.Assert(one["nickname"].String(), "1") - - _, err = db.Model(table).Data(g.Map{ - "id": 1, - "passport": 0, - "password": 0, - "nickname": "1", - }).Save() - t.AssertNil(err) - one, err = db.Model(table).Where("id", 1).One() - t.AssertNil(err) - t.Assert(one["passport"].String(), "0") - t.Assert(one["password"].String(), "0") - t.Assert(one["nickname"].String(), "1") - }) - - // Update - gtest.C(t, func(t *gtest.T) { - table := createInitTable() - defer dropTable(table) - - r, err := db.Model(table).Data(g.Map{"nickname": ""}).Where("id", 1).Update() - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - - _, err = db.Model(table).OmitEmptyData().Data(g.Map{"nickname": ""}).Where("id", 2).Update() - t.AssertNE(err, nil) - - r, err = db.Model(table).OmitEmpty().Data(g.Map{"nickname": "", "password": "123"}).Where("id", 3).Update() - t.AssertNil(err) - n, _ = r.RowsAffected() - t.Assert(n, 1) - - _, err = db.Model(table).OmitEmpty().Fields("nickname").Data(g.Map{"nickname": "", "password": "123"}).Where("id", 4).Update() - t.AssertNE(err, nil) - - r, err = db.Model(table).OmitEmpty(). - Fields("password").Data(g.Map{ - "nickname": "", - "passport": "123", - "password": "456", - }).Where("id", 5).Update() - t.AssertNil(err) - n, _ = r.RowsAffected() - t.Assert(n, 1) - - one, err := db.Model(table).Where("id", 5).One() - t.AssertNil(err) - t.Assert(one["password"], "456") - t.AssertNE(one["passport"].String(), "") - t.AssertNE(one["passport"].String(), "123") - }) + // Insert + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + r, err := db.Model(table).Fields("id, passport").Data(g.Map{ + "id": 1, + "passport": "1", + "password": "1", + "nickname": "1", + }).Insert() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + one, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.AssertNE(one["password"].String(), "1") + t.AssertNE(one["nickname"].String(), "1") + t.Assert(one["passport"].String(), "1") + }) + + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + r, err := db.Model(table).OmitEmptyData().Data(g.Map{ + "id": 1, + "passport": 0, + "password": 0, + "nickname": "1", + }).Insert() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + one, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.AssertNE(one["passport"].String(), "0") + t.AssertNE(one["password"].String(), "0") + t.Assert(one["nickname"].String(), "1") + }) + + // Replace + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + _, err := db.Model(table).OmitEmptyData().Data(g.Map{ + "id": 1, + "passport": 0, + "password": 0, + "nickname": "1", + }).Replace() + t.AssertNil(err) + one, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.AssertNE(one["passport"].String(), "0") + t.AssertNE(one["password"].String(), "0") + t.Assert(one["nickname"].String(), "1") + }) + + // Save + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + r, err := db.Model(table).Fields("id, passport").Data(g.Map{ + "id": 1, + "passport": "1", + "password": "1", + "nickname": "1", + }).Save() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + one, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.AssertNE(one["password"].String(), "1") + t.AssertNE(one["nickname"].String(), "1") + t.Assert(one["passport"].String(), "1") + }) + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + _, err := db.Model(table).OmitEmptyData().Data(g.Map{ + "id": 1, + "passport": 0, + "password": 0, + "nickname": "1", + }).Save() + t.AssertNil(err) + one, err := db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.AssertNE(one["passport"].String(), "0") + t.AssertNE(one["password"].String(), "0") + t.Assert(one["nickname"].String(), "1") + + _, err = db.Model(table).Data(g.Map{ + "id": 1, + "passport": 0, + "password": 0, + "nickname": "1", + }).Save() + t.AssertNil(err) + one, err = db.Model(table).Where("id", 1).One() + t.AssertNil(err) + t.Assert(one["passport"].String(), "0") + t.Assert(one["password"].String(), "0") + t.Assert(one["nickname"].String(), "1") + }) + + // Update + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + + r, err := db.Model(table).Data(g.Map{"nickname": ""}).Where("id", 1).Update() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + + _, err = db.Model(table).OmitEmptyData().Data(g.Map{"nickname": ""}).Where("id", 2).Update() + t.AssertNE(err, nil) + + r, err = db.Model(table).OmitEmpty().Data(g.Map{"nickname": "", "password": "123"}).Where("id", 3).Update() + t.AssertNil(err) + n, _ = r.RowsAffected() + t.Assert(n, 1) + + _, err = db.Model(table).OmitEmpty().Fields("nickname").Data(g.Map{"nickname": "", "password": "123"}).Where("id", 4).Update() + t.AssertNE(err, nil) + + r, err = db.Model(table).OmitEmpty(). + Fields("password").Data(g.Map{ + "nickname": "", + "passport": "123", + "password": "456", + }).Where("id", 5).Update() + t.AssertNil(err) + n, _ = r.RowsAffected() + t.Assert(n, 1) + + one, err := db.Model(table).Where("id", 5).One() + t.AssertNil(err) + t.Assert(one["password"], "456") + t.AssertNE(one["passport"].String(), "") + t.AssertNE(one["passport"].String(), "123") + }) } func Test_Model_Option_List(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - r, err := db.Model(table).Fields("id, password").Data(g.List{ - g.Map{ - "id": 1, - "passport": "1", - "password": "1", - "nickname": "1", - }, - g.Map{ - "id": 2, - "passport": "2", - "password": "2", - "nickname": "2", - }, - }).Save() - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 2) - list, err := db.Model(table).Order("id asc").All() - t.AssertNil(err) - t.Assert(len(list), 2) - t.Assert(list[0]["id"].String(), "1") - t.Assert(list[0]["nickname"].String(), "") - t.Assert(list[0]["passport"].String(), "") - t.Assert(list[0]["password"].String(), "1") - - t.Assert(list[1]["id"].String(), "2") - t.Assert(list[1]["nickname"].String(), "") - t.Assert(list[1]["passport"].String(), "") - t.Assert(list[1]["password"].String(), "2") - }) - - gtest.C(t, func(t *gtest.T) { - table := createTable() - defer dropTable(table) - r, err := db.Model(table).OmitEmpty().Fields("id, password").Data(g.List{ - g.Map{ - "id": 1, - "passport": "1", - "password": 0, - "nickname": "1", - }, - g.Map{ - "id": 2, - "passport": "2", - "password": "2", - "nickname": "2", - }, - }).Save() - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 2) - list, err := db.Model(table).Order("id asc").All() - t.AssertNil(err) - t.Assert(len(list), 2) - t.Assert(list[0]["id"].String(), "1") - t.Assert(list[0]["nickname"].String(), "") - t.Assert(list[0]["passport"].String(), "") - t.Assert(list[0]["password"].String(), "0") - - t.Assert(list[1]["id"].String(), "2") - t.Assert(list[1]["nickname"].String(), "") - t.Assert(list[1]["passport"].String(), "") - t.Assert(list[1]["password"].String(), "2") - }) + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + r, err := db.Model(table).Fields("id, password").Data(g.List{ + g.Map{ + "id": 1, + "passport": "1", + "password": "1", + "nickname": "1", + }, + g.Map{ + "id": 2, + "passport": "2", + "password": "2", + "nickname": "2", + }, + }).Save() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 2) + list, err := db.Model(table).Order("id asc").All() + t.AssertNil(err) + t.Assert(len(list), 2) + t.Assert(list[0]["id"].String(), "1") + t.Assert(list[0]["nickname"].String(), "") + t.Assert(list[0]["passport"].String(), "") + t.Assert(list[0]["password"].String(), "1") + + t.Assert(list[1]["id"].String(), "2") + t.Assert(list[1]["nickname"].String(), "") + t.Assert(list[1]["passport"].String(), "") + t.Assert(list[1]["password"].String(), "2") + }) + + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + r, err := db.Model(table).OmitEmpty().Fields("id, password").Data(g.List{ + g.Map{ + "id": 1, + "passport": "1", + "password": 0, + "nickname": "1", + }, + g.Map{ + "id": 2, + "passport": "2", + "password": "2", + "nickname": "2", + }, + }).Save() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 2) + list, err := db.Model(table).Order("id asc").All() + t.AssertNil(err) + t.Assert(len(list), 2) + t.Assert(list[0]["id"].String(), "1") + t.Assert(list[0]["nickname"].String(), "") + t.Assert(list[0]["passport"].String(), "") + t.Assert(list[0]["password"].String(), "0") + + t.Assert(list[1]["id"].String(), "2") + t.Assert(list[1]["nickname"].String(), "") + t.Assert(list[1]["passport"].String(), "") + t.Assert(list[1]["password"].String(), "2") + }) } func Test_Model_OmitEmpty(t *testing.T) { - table := fmt.Sprintf(`table_%s`, gtime.TimestampNanoStr()) - if _, err := db.Exec(ctx, fmt.Sprintf(` + table := fmt.Sprintf(`table_%s`, gtime.TimestampNanoStr()) + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE IF NOT EXISTS %s ( id int(10) unsigned NOT NULL AUTO_INCREMENT, name varchar(45) NOT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; `, table)); err != nil { - gtest.Error(err) - } - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).OmitEmpty().Data(g.Map{ - "id": 1, - "name": "", - }).Save() - t.AssertNE(err, nil) - }) - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).OmitEmptyData().Data(g.Map{ - "id": 1, - "name": "", - }).Save() - t.AssertNE(err, nil) - }) - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).OmitEmptyWhere().Data(g.Map{ - "id": 1, - "name": "", - }).Save() - t.AssertNil(err) - }) + gtest.Error(err) + } + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).OmitEmpty().Data(g.Map{ + "id": 1, + "name": "", + }).Save() + t.AssertNE(err, nil) + }) + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).OmitEmptyData().Data(g.Map{ + "id": 1, + "name": "", + }).Save() + t.AssertNE(err, nil) + }) + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).OmitEmptyWhere().Data(g.Map{ + "id": 1, + "name": "", + }).Save() + t.AssertNil(err) + }) } func Test_Model_OmitNil(t *testing.T) { - table := fmt.Sprintf(`table_%s`, gtime.TimestampNanoStr()) - if _, err := db.Exec(ctx, fmt.Sprintf(` + table := fmt.Sprintf(`table_%s`, gtime.TimestampNanoStr()) + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE IF NOT EXISTS %s ( id int(10) unsigned NOT NULL AUTO_INCREMENT, name varchar(45) NOT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; `, table)); err != nil { - gtest.Error(err) - } - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).OmitNil().Data(g.Map{ - "id": 1, - "name": nil, - }).Save() - t.AssertNE(err, nil) - }) - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).OmitNil().Data(g.Map{ - "id": 1, - "name": "", - }).Save() - t.AssertNil(err) - }) - gtest.C(t, func(t *gtest.T) { - _, err := db.Model(table).OmitNilWhere().Data(g.Map{ - "id": 1, - "name": "", - }).Save() - t.AssertNil(err) - }) + gtest.Error(err) + } + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).OmitNil().Data(g.Map{ + "id": 1, + "name": nil, + }).Save() + t.AssertNE(err, nil) + }) + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).OmitNil().Data(g.Map{ + "id": 1, + "name": "", + }).Save() + t.AssertNil(err) + }) + gtest.C(t, func(t *gtest.T) { + _, err := db.Model(table).OmitNilWhere().Data(g.Map{ + "id": 1, + "name": "", + }).Save() + t.AssertNil(err) + }) } func Test_Model_FieldsEx(t *testing.T) { - table := createInitTable() - defer dropTable(table) - // Select. - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table).FieldsEx("create_time, id").Where("id in (?)", g.Slice{1, 2}).Order("id asc").All() - t.AssertNil(err) - t.Assert(len(r), 2) - t.Assert(len(r[0]), 4) - t.Assert(r[0]["id"], "") - t.Assert(r[0]["passport"], "user_1") - t.Assert(r[0]["password"], "pass_1") - t.Assert(r[0]["nickname"], "name_1") - t.Assert(r[0]["create_time"], "") - t.Assert(r[1]["id"], "") - t.Assert(r[1]["passport"], "user_2") - t.Assert(r[1]["password"], "pass_2") - t.Assert(r[1]["nickname"], "name_2") - t.Assert(r[1]["create_time"], "") - }) - // Update. - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table).FieldsEx("password").Data(g.Map{"nickname": "123", "password": "456"}).Where("id", 3).Update() - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - - one, err := db.Model(table).Where("id", 3).One() - t.AssertNil(err) - t.Assert(one["nickname"], "123") - t.AssertNE(one["password"], "456") - }) + table := createInitTable() + defer dropTable(table) + // Select. + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).FieldsEx("create_time, id").Where("id in (?)", g.Slice{1, 2}).Order("id asc").All() + t.AssertNil(err) + t.Assert(len(r), 2) + t.Assert(len(r[0]), 4) + t.Assert(r[0]["id"], "") + t.Assert(r[0]["passport"], "user_1") + t.Assert(r[0]["password"], "pass_1") + t.Assert(r[0]["nickname"], "name_1") + t.Assert(r[0]["create_time"], "") + t.Assert(r[1]["id"], "") + t.Assert(r[1]["passport"], "user_2") + t.Assert(r[1]["password"], "pass_2") + t.Assert(r[1]["nickname"], "name_2") + t.Assert(r[1]["create_time"], "") + }) + // Update. + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).FieldsEx("password").Data(g.Map{"nickname": "123", "password": "456"}).Where("id", 3).Update() + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + + one, err := db.Model(table).Where("id", 3).One() + t.AssertNil(err) + t.Assert(one["nickname"], "123") + t.AssertNE(one["password"], "456") + }) } func Test_Model_FieldsEx_WithReservedWords(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - var ( - table = "fieldsex_test_table" - sqlTpcPath = gtest.DataPath("reservedwords_table_tpl.sql") - sqlContent = gfile.GetContents(sqlTpcPath) - ) - t.AssertNE(sqlContent, "") - if _, err := db.Exec(ctx, fmt.Sprintf(sqlContent, table)); err != nil { - t.AssertNil(err) - } - defer dropTable(table) - _, err := db.Model(table).FieldsEx("content").One() - t.AssertNil(err) - }) + gtest.C(t, func(t *gtest.T) { + var ( + table = "fieldsex_test_table" + sqlTpcPath = gtest.DataPath("reservedwords_table_tpl.sql") + sqlContent = gfile.GetContents(sqlTpcPath) + ) + t.AssertNE(sqlContent, "") + if _, err := db.Exec(ctx, fmt.Sprintf(sqlContent, table)); err != nil { + t.AssertNil(err) + } + defer dropTable(table) + _, err := db.Model(table).FieldsEx("content").One() + t.AssertNil(err) + }) } func Test_Model_Prefix(t *testing.T) { - db := dbPrefix - table := fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano()) - createInitTableWithDb(db, TableNamePrefix1+table) - defer dropTable(TableNamePrefix1 + table) - // Select. - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table).Where("id in (?)", g.Slice{1, 2}).Order("id asc").All() - t.AssertNil(err) - t.Assert(len(r), 2) - t.Assert(r[0]["id"], "1") - t.Assert(r[1]["id"], "2") - }) - // Select with alias. - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table+" as u").Where("u.id in (?)", g.Slice{1, 2}).Order("u.id asc").All() - t.AssertNil(err) - t.Assert(len(r), 2) - t.Assert(r[0]["id"], "1") - t.Assert(r[1]["id"], "2") - }) - // Select with alias to struct. - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - NickName string - } - var users []User - err := db.Model(table+" u").Where("u.id in (?)", g.Slice{1, 5}).Order("u.id asc").Scan(&users) - t.AssertNil(err) - t.Assert(len(users), 2) - t.Assert(users[0].Id, 1) - t.Assert(users[1].Id, 5) - }) - // Select with alias and join statement. - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table+" as u1").LeftJoin(table+" as u2", "u2.id=u1.id").Where("u1.id in (?)", g.Slice{1, 2}).Order("u1.id asc").All() - t.AssertNil(err) - t.Assert(len(r), 2) - t.Assert(r[0]["id"], "1") - t.Assert(r[1]["id"], "2") - }) - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table).As("u1").LeftJoin(table+" as u2", "u2.id=u1.id").Where("u1.id in (?)", g.Slice{1, 2}).Order("u1.id asc").All() - t.AssertNil(err) - t.Assert(len(r), 2) - t.Assert(r[0]["id"], "1") - t.Assert(r[1]["id"], "2") - }) + db := dbPrefix + table := fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano()) + createInitTableWithDb(db, TableNamePrefix1+table) + defer dropTable(TableNamePrefix1 + table) + // Select. + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).Where("id in (?)", g.Slice{1, 2}).Order("id asc").All() + t.AssertNil(err) + t.Assert(len(r), 2) + t.Assert(r[0]["id"], "1") + t.Assert(r[1]["id"], "2") + }) + // Select with alias. + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table+" as u").Where("u.id in (?)", g.Slice{1, 2}).Order("u.id asc").All() + t.AssertNil(err) + t.Assert(len(r), 2) + t.Assert(r[0]["id"], "1") + t.Assert(r[1]["id"], "2") + }) + // Select with alias to struct. + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + NickName string + } + var users []User + err := db.Model(table+" u").Where("u.id in (?)", g.Slice{1, 5}).Order("u.id asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(users[0].Id, 1) + t.Assert(users[1].Id, 5) + }) + // Select with alias and join statement. + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table+" as u1").LeftJoin(table+" as u2", "u2.id=u1.id").Where("u1.id in (?)", g.Slice{1, 2}).Order("u1.id asc").All() + t.AssertNil(err) + t.Assert(len(r), 2) + t.Assert(r[0]["id"], "1") + t.Assert(r[1]["id"], "2") + }) + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).As("u1").LeftJoin(table+" as u2", "u2.id=u1.id").Where("u1.id in (?)", g.Slice{1, 2}).Order("u1.id asc").All() + t.AssertNil(err) + t.Assert(len(r), 2) + t.Assert(r[0]["id"], "1") + t.Assert(r[1]["id"], "2") + }) } func Test_Model_Schema1(t *testing.T) { - // db.SetDebug(true) - - db = db.Schema(TestSchema1) - table := fmt.Sprintf(`%s_%s`, TableName, gtime.TimestampNanoStr()) - createInitTableWithDb(db, table) - db = db.Schema(TestSchema2) - createInitTableWithDb(db, table) - defer func() { - db = db.Schema(TestSchema1) - dropTableWithDb(db, table) - db = db.Schema(TestSchema2) - dropTableWithDb(db, table) - db = db.Schema(TestSchema1) - }() - // Method. - gtest.C(t, func(t *gtest.T) { - db = db.Schema(TestSchema1) - r, err := db.Model(table).Update(g.Map{"nickname": "name_100"}, "id=1") - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - - v, err := db.Model(table).Value("nickname", "id=1") - t.AssertNil(err) - t.Assert(v.String(), "name_100") - - db = db.Schema(TestSchema2) - v, err = db.Model(table).Value("nickname", "id=1") - t.AssertNil(err) - t.Assert(v.String(), "name_1") - }) - // Model. - gtest.C(t, func(t *gtest.T) { - v, err := db.Model(table).Schema(TestSchema1).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_2") - - r, err := db.Model(table).Schema(TestSchema1).Update(g.Map{"nickname": "name_200"}, "id=2") - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - - v, err = db.Model(table).Schema(TestSchema1).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_200") - - v, err = db.Model(table).Schema(TestSchema2).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_2") - - v, err = db.Model(table).Schema(TestSchema1).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_200") - }) - // Model. - gtest.C(t, func(t *gtest.T) { - i := 1000 - _, err := db.Model(table).Schema(TestSchema1).Insert(g.Map{ - "id": i, - "passport": fmt.Sprintf(`user_%d`, i), - "password": fmt.Sprintf(`pass_%d`, i), - "nickname": fmt.Sprintf(`name_%d`, i), - "create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(), - "none-exist-field": 1, - }) - t.AssertNil(err) - - v, err := db.Model(table).Schema(TestSchema1).Value("nickname", "id=?", i) - t.AssertNil(err) - t.Assert(v.String(), "name_1000") - - v, err = db.Model(table).Schema(TestSchema2).Value("nickname", "id=?", i) - t.AssertNil(err) - t.Assert(v.String(), "") - }) + // db.SetDebug(true) + + db = db.Schema(TestSchema1) + table := fmt.Sprintf(`%s_%s`, TableName, gtime.TimestampNanoStr()) + createInitTableWithDb(db, table) + db = db.Schema(TestSchema2) + createInitTableWithDb(db, table) + defer func() { + db = db.Schema(TestSchema1) + dropTableWithDb(db, table) + db = db.Schema(TestSchema2) + dropTableWithDb(db, table) + db = db.Schema(TestSchema1) + }() + // Method. + gtest.C(t, func(t *gtest.T) { + db = db.Schema(TestSchema1) + r, err := db.Model(table).Update(g.Map{"nickname": "name_100"}, "id=1") + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + + v, err := db.Model(table).Value("nickname", "id=1") + t.AssertNil(err) + t.Assert(v.String(), "name_100") + + db = db.Schema(TestSchema2) + v, err = db.Model(table).Value("nickname", "id=1") + t.AssertNil(err) + t.Assert(v.String(), "name_1") + }) + // Model. + gtest.C(t, func(t *gtest.T) { + v, err := db.Model(table).Schema(TestSchema1).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_2") + + r, err := db.Model(table).Schema(TestSchema1).Update(g.Map{"nickname": "name_200"}, "id=2") + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + + v, err = db.Model(table).Schema(TestSchema1).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_200") + + v, err = db.Model(table).Schema(TestSchema2).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_2") + + v, err = db.Model(table).Schema(TestSchema1).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_200") + }) + // Model. + gtest.C(t, func(t *gtest.T) { + i := 1000 + _, err := db.Model(table).Schema(TestSchema1).Insert(g.Map{ + "id": i, + "passport": fmt.Sprintf(`user_%d`, i), + "password": fmt.Sprintf(`pass_%d`, i), + "nickname": fmt.Sprintf(`name_%d`, i), + "create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(), + "none-exist-field": 1, + }) + t.AssertNil(err) + + v, err := db.Model(table).Schema(TestSchema1).Value("nickname", "id=?", i) + t.AssertNil(err) + t.Assert(v.String(), "name_1000") + + v, err = db.Model(table).Schema(TestSchema2).Value("nickname", "id=?", i) + t.AssertNil(err) + t.Assert(v.String(), "") + }) } func Test_Model_Schema2(t *testing.T) { - // db.SetDebug(true) - - db = db.Schema(TestSchema1) - table := fmt.Sprintf(`%s_%s`, TableName, gtime.TimestampNanoStr()) - createInitTableWithDb(db, table) - db = db.Schema(TestSchema2) - createInitTableWithDb(db, table) - defer func() { - db = db.Schema(TestSchema1) - dropTableWithDb(db, table) - db = db.Schema(TestSchema2) - dropTableWithDb(db, table) - - db = db.Schema(TestSchema1) - }() - // Schema. - gtest.C(t, func(t *gtest.T) { - v, err := db.Schema(TestSchema1).Model(table).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_2") - - r, err := db.Schema(TestSchema1).Model(table).Update(g.Map{"nickname": "name_200"}, "id=2") - t.AssertNil(err) - n, _ := r.RowsAffected() - t.Assert(n, 1) - - v, err = db.Schema(TestSchema1).Model(table).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_200") - - v, err = db.Schema(TestSchema2).Model(table).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_2") - - v, err = db.Schema(TestSchema1).Model(table).Value("nickname", "id=2") - t.AssertNil(err) - t.Assert(v.String(), "name_200") - }) - // Schema. - gtest.C(t, func(t *gtest.T) { - i := 1000 - _, err := db.Schema(TestSchema1).Model(table).Insert(g.Map{ - "id": i, - "passport": fmt.Sprintf(`user_%d`, i), - "password": fmt.Sprintf(`pass_%d`, i), - "nickname": fmt.Sprintf(`name_%d`, i), - "create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(), - "none-exist-field": 1, - }) - t.AssertNil(err) - - v, err := db.Schema(TestSchema1).Model(table).Value("nickname", "id=?", i) - t.AssertNil(err) - t.Assert(v.String(), "name_1000") - - v, err = db.Schema(TestSchema2).Model(table).Value("nickname", "id=?", i) - t.AssertNil(err) - t.Assert(v.String(), "") - }) + // db.SetDebug(true) + + db = db.Schema(TestSchema1) + table := fmt.Sprintf(`%s_%s`, TableName, gtime.TimestampNanoStr()) + createInitTableWithDb(db, table) + db = db.Schema(TestSchema2) + createInitTableWithDb(db, table) + defer func() { + db = db.Schema(TestSchema1) + dropTableWithDb(db, table) + db = db.Schema(TestSchema2) + dropTableWithDb(db, table) + + db = db.Schema(TestSchema1) + }() + // Schema. + gtest.C(t, func(t *gtest.T) { + v, err := db.Schema(TestSchema1).Model(table).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_2") + + r, err := db.Schema(TestSchema1).Model(table).Update(g.Map{"nickname": "name_200"}, "id=2") + t.AssertNil(err) + n, _ := r.RowsAffected() + t.Assert(n, 1) + + v, err = db.Schema(TestSchema1).Model(table).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_200") + + v, err = db.Schema(TestSchema2).Model(table).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_2") + + v, err = db.Schema(TestSchema1).Model(table).Value("nickname", "id=2") + t.AssertNil(err) + t.Assert(v.String(), "name_200") + }) + // Schema. + gtest.C(t, func(t *gtest.T) { + i := 1000 + _, err := db.Schema(TestSchema1).Model(table).Insert(g.Map{ + "id": i, + "passport": fmt.Sprintf(`user_%d`, i), + "password": fmt.Sprintf(`pass_%d`, i), + "nickname": fmt.Sprintf(`name_%d`, i), + "create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(), + "none-exist-field": 1, + }) + t.AssertNil(err) + + v, err := db.Schema(TestSchema1).Model(table).Value("nickname", "id=?", i) + t.AssertNil(err) + t.Assert(v.String(), "name_1000") + + v, err = db.Schema(TestSchema2).Model(table).Value("nickname", "id=?", i) + t.AssertNil(err) + t.Assert(v.String(), "") + }) } func Test_Model_FieldsExStruct(t *testing.T) { - table := createTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int `orm:"id" json:"id"` - Passport string `orm:"password" json:"pass_port"` - Password string `orm:"password" json:"password"` - NickName string `orm:"nickname" json:"nick__name"` - } - user := &User{ - Id: 1, - Passport: "111", - Password: "222", - NickName: "333", - } - r, err := db.Model(table).FieldsEx("create_time, password").OmitEmpty().Data(user).Insert() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 1) - }) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int `orm:"id" json:"id"` - Passport string `orm:"password" json:"pass_port"` - Password string `orm:"password" json:"password"` - NickName string `orm:"nickname" json:"nick__name"` - } - users := make([]*User, 0) - for i := 100; i < 110; i++ { - users = append(users, &User{ - Id: i, - Passport: fmt.Sprintf(`passport_%d`, i), - Password: fmt.Sprintf(`password_%d`, i), - NickName: fmt.Sprintf(`nickname_%d`, i), - }) - } - r, err := db.Model(table).FieldsEx("create_time, password"). - OmitEmpty(). - Batch(2). - Data(users). - Insert() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 10) - }) + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int `orm:"id" json:"id"` + Passport string `orm:"password" json:"pass_port"` + Password string `orm:"password" json:"password"` + NickName string `orm:"nickname" json:"nick__name"` + } + user := &User{ + Id: 1, + Passport: "111", + Password: "222", + NickName: "333", + } + r, err := db.Model(table).FieldsEx("create_time, password").OmitEmpty().Data(user).Insert() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + }) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int `orm:"id" json:"id"` + Passport string `orm:"password" json:"pass_port"` + Password string `orm:"password" json:"password"` + NickName string `orm:"nickname" json:"nick__name"` + } + users := make([]*User, 0) + for i := 100; i < 110; i++ { + users = append(users, &User{ + Id: i, + Passport: fmt.Sprintf(`passport_%d`, i), + Password: fmt.Sprintf(`password_%d`, i), + NickName: fmt.Sprintf(`nickname_%d`, i), + }) + } + r, err := db.Model(table).FieldsEx("create_time, password"). + OmitEmpty(). + Batch(2). + Data(users). + Insert() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 10) + }) } func Test_Model_OmitEmpty_Time(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int `orm:"id" json:"id"` - Passport string `orm:"password" json:"pass_port"` - Password string `orm:"password" json:"password"` - Time time.Time `orm:"create_time" ` - } - user := &User{ - Id: 1, - Passport: "111", - Password: "222", - Time: time.Time{}, - } - r, err := db.Model(table).OmitEmpty().Data(user).WherePri(1).Update() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 1) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int `orm:"id" json:"id"` + Passport string `orm:"password" json:"pass_port"` + Password string `orm:"password" json:"password"` + Time time.Time `orm:"create_time" ` + } + user := &User{ + Id: 1, + Passport: "111", + Password: "222", + Time: time.Time{}, + } + r, err := db.Model(table).OmitEmpty().Data(user).WherePri(1).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + }) } func Test_Result_Chunk(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table).Order("id asc").All() - t.AssertNil(err) - chunks := r.Chunk(3) - t.Assert(len(chunks), 4) - t.Assert(chunks[0][0]["id"].Int(), 1) - t.Assert(chunks[1][0]["id"].Int(), 4) - t.Assert(chunks[2][0]["id"].Int(), 7) - t.Assert(chunks[3][0]["id"].Int(), 10) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).Order("id asc").All() + t.AssertNil(err) + chunks := r.Chunk(3) + t.Assert(len(chunks), 4) + t.Assert(chunks[0][0]["id"].Int(), 1) + t.Assert(chunks[1][0]["id"].Int(), 4) + t.Assert(chunks[2][0]["id"].Int(), 7) + t.Assert(chunks[3][0]["id"].Int(), 10) + }) } func Test_Model_DryRun(t *testing.T) { - table := createInitTable() - defer dropTable(table) - db.SetDryRun(true) - defer db.SetDryRun(false) - - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["id"], 1) - }) - gtest.C(t, func(t *gtest.T) { - r, err := db.Model(table).Data("passport", "port_1").WherePri(1).Update() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 0) - }) + table := createInitTable() + defer dropTable(table) + db.SetDryRun(true) + defer db.SetDryRun(false) + + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["id"], 1) + }) + gtest.C(t, func(t *gtest.T) { + r, err := db.Model(table).Data("passport", "port_1").WherePri(1).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 0) + }) } func Test_Model_Join_SubQuery(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - subQuery := fmt.Sprintf("select * from `%s`", table) - r, err := db.Model(table, "t1").Fields("t2.id").LeftJoin(subQuery, "t2", "t2.id=t1.id").Array() - t.AssertNil(err) - t.Assert(len(r), TableSize) - t.Assert(r[0], "1") - t.Assert(r[TableSize-1], TableSize) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + subQuery := fmt.Sprintf("select * from `%s`", table) + r, err := db.Model(table, "t1").Fields("t2.id").LeftJoin(subQuery, "t2", "t2.id=t1.id").Array() + t.AssertNil(err) + t.Assert(len(r), TableSize) + t.Assert(r[0], "1") + t.Assert(r[TableSize-1], TableSize) + }) } func Test_Model_Cache(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test1", - Force: false, - }).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_1") - - r, err := db.Model(table).Data("passport", "user_100").WherePri(1).Update() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 1) - - one, err = db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test1", - Force: false, - }).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_1") - - time.Sleep(time.Second * 2) - - one, err = db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test1", - Force: false, - }).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_100") - }) - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test2", - Force: false, - }).WherePri(2).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_2") - - r, err := db.Model(table).Data("passport", "user_200").Cache(gdb.CacheOption{ - Duration: -1, - Name: "test2", - Force: false, - }).WherePri(2).Update() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 1) - - one, err = db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test2", - Force: false, - }).WherePri(2).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_200") - }) - // transaction. - gtest.C(t, func(t *gtest.T) { - // make cache for id 3 - one, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test3", - Force: false, - }).WherePri(3).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_3") - - r, err := db.Model(table).Data("passport", "user_300").Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test3", - Force: false, - }).WherePri(3).Update() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 1) - - err = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error { - one, err := tx.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test3", - Force: false, - }).WherePri(3).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_300") - return nil - }) - t.AssertNil(err) - - one, err = db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test3", - Force: false, - }).WherePri(3).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_3") - }) - gtest.C(t, func(t *gtest.T) { - // make cache for id 4 - one, err := db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test4", - Force: false, - }).WherePri(4).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_4") - - r, err := db.Model(table).Data("passport", "user_400").Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test3", - Force: false, - }).WherePri(4).Update() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 1) - - err = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error { - // Cache feature disabled. - one, err := tx.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test4", - Force: false, - }).WherePri(4).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_400") - // Update the cache. - r, err := tx.Model(table).Data("passport", "user_4000"). - Cache(gdb.CacheOption{ - Duration: -1, - Name: "test4", - Force: false, - }).WherePri(4).Update() - t.AssertNil(err) - n, err := r.RowsAffected() - t.AssertNil(err) - t.Assert(n, 1) - return nil - }) - t.AssertNil(err) - // Read from db. - one, err = db.Model(table).Cache(gdb.CacheOption{ - Duration: time.Second, - Name: "test4", - Force: false, - }).WherePri(4).One() - t.AssertNil(err) - t.Assert(one["passport"], "user_4000") - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test1", + Force: false, + }).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_1") + + r, err := db.Model(table).Data("passport", "user_100").WherePri(1).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + + one, err = db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test1", + Force: false, + }).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_1") + + time.Sleep(time.Second * 2) + + one, err = db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test1", + Force: false, + }).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_100") + }) + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test2", + Force: false, + }).WherePri(2).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_2") + + r, err := db.Model(table).Data("passport", "user_200").Cache(gdb.CacheOption{ + Duration: -1, + Name: "test2", + Force: false, + }).WherePri(2).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + + one, err = db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test2", + Force: false, + }).WherePri(2).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_200") + }) + // transaction. + gtest.C(t, func(t *gtest.T) { + // make cache for id 3 + one, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test3", + Force: false, + }).WherePri(3).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_3") + + r, err := db.Model(table).Data("passport", "user_300").Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test3", + Force: false, + }).WherePri(3).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + + err = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error { + one, err := tx.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test3", + Force: false, + }).WherePri(3).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_300") + return nil + }) + t.AssertNil(err) + + one, err = db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test3", + Force: false, + }).WherePri(3).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_3") + }) + gtest.C(t, func(t *gtest.T) { + // make cache for id 4 + one, err := db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test4", + Force: false, + }).WherePri(4).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_4") + + r, err := db.Model(table).Data("passport", "user_400").Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test3", + Force: false, + }).WherePri(4).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + + err = db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error { + // Cache feature disabled. + one, err := tx.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test4", + Force: false, + }).WherePri(4).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_400") + // Update the cache. + r, err := tx.Model(table).Data("passport", "user_4000"). + Cache(gdb.CacheOption{ + Duration: -1, + Name: "test4", + Force: false, + }).WherePri(4).Update() + t.AssertNil(err) + n, err := r.RowsAffected() + t.AssertNil(err) + t.Assert(n, 1) + return nil + }) + t.AssertNil(err) + // Read from db. + one, err = db.Model(table).Cache(gdb.CacheOption{ + Duration: time.Second, + Name: "test4", + Force: false, + }).WherePri(4).One() + t.AssertNil(err) + t.Assert(one["passport"], "user_4000") + }) } func Test_Model_Having(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id > 1").Having("id > 8").All() - t.AssertNil(err) - t.Assert(len(all), 2) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id > 1").Having("id > ?", 8).All() - t.AssertNil(err) - t.Assert(len(all), 2) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id > ?", 1).Having("id > ?", 8).All() - t.AssertNil(err) - t.Assert(len(all), 2) - }) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Where("id > ?", 1).Having("id", 8).All() - t.AssertNil(err) - t.Assert(len(all), 1) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id > 1").Having("id > 8").All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id > 1").Having("id > ?", 8).All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id > ?", 1).Having("id > ?", 8).All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Where("id > ?", 1).Having("id", 8).All() + t.AssertNil(err) + t.Assert(len(all), 1) + }) } func Test_Model_Distinct(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table, "t").Fields("distinct t.id").Where("id > 1").Having("id > 8").All() - t.AssertNil(err) - t.Assert(len(all), 2) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id > 1").Distinct().Count() - t.AssertNil(err) - t.Assert(count, int64(9)) - }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table, "t").Fields("distinct t.id").Where("id > 1").Having("id > 8").All() + t.AssertNil(err) + t.Assert(len(all), 2) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id > 1").Distinct().Count() + t.AssertNil(err) + t.Assert(count, int64(9)) + }) } func Test_Model_Min_Max(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table, "t").Fields("min(t.id)").Where("id > 1").Value() - t.AssertNil(err) - t.Assert(value.Int(), 2) - }) - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table, "t").Fields("max(t.id)").Where("id > 1").Value() - t.AssertNil(err) - t.Assert(value.Int(), 10) - }) + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table, "t").Fields("min(t.id)").Where("id > 1").Value() + t.AssertNil(err) + t.Assert(value.Int(), 2) + }) + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table, "t").Fields("max(t.id)").Where("id > 1").Value() + t.AssertNil(err) + t.Assert(value.Int(), 10) + }) } func Test_Model_Fields_AutoMapping(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).Fields("ID").Where("id", 2).Value() - t.AssertNil(err) - t.Assert(value.Int(), 2) - }) - - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).Fields("NICK_NAME").Where("id", 2).Value() - t.AssertNil(err) - t.Assert(value.String(), "name_2") - }) - // Map - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Fields(g.Map{ - "ID": 1, - "NICK_NAME": 1, - }).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 2) - t.Assert(one["id"], 2) - t.Assert(one["nickname"], "name_2") - }) - // Struct - gtest.C(t, func(t *gtest.T) { - type T struct { - ID int - NICKNAME int - } - one, err := db.Model(table).Fields(&T{ - ID: 0, - NICKNAME: 0, - }).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 2) - t.Assert(one["id"], 2) - t.Assert(one["nickname"], "name_2") - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Fields("ID").Where("id", 2).Value() + t.AssertNil(err) + t.Assert(value.Int(), 2) + }) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).Fields("NICK_NAME").Where("id", 2).Value() + t.AssertNil(err) + t.Assert(value.String(), "name_2") + }) + // Map + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Fields(g.Map{ + "ID": 1, + "NICK_NAME": 1, + }).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["id"], 2) + t.Assert(one["nickname"], "name_2") + }) + // Struct + gtest.C(t, func(t *gtest.T) { + type T struct { + ID int + NICKNAME int + } + one, err := db.Model(table).Fields(&T{ + ID: 0, + NICKNAME: 0, + }).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["id"], 2) + t.Assert(one["nickname"], "name_2") + }) } func Test_Model_FieldsEx_AutoMapping(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - // "id": i, - // "passport": fmt.Sprintf(`user_%d`, i), - // "password": fmt.Sprintf(`pass_%d`, i), - // "nickname": fmt.Sprintf(`name_%d`, i), - // "create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(), - - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).FieldsEx("create_date, Passport, Password, NickName, CreateTime").Where("id", 2).Value() - t.AssertNil(err) - t.Assert(value.Int(), 2) - }) - - gtest.C(t, func(t *gtest.T) { - value, err := db.Model(table).FieldsEx("create_date, ID, Passport, Password, CreateTime").Where("id", 2).Value() - t.AssertNil(err) - t.Assert(value.String(), "name_2") - }) - // Map - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).FieldsEx(g.Map{ - "Passport": 1, - "Password": 1, - "CreateTime": 1, - }).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 3) - t.Assert(one["id"], 2) - t.Assert(one["nickname"], "name_2") - }) - // Struct - gtest.C(t, func(t *gtest.T) { - type T struct { - Passport int - Password int - CreateTime int - } - one, err := db.Model(table).FieldsEx(&T{ - Passport: 0, - Password: 0, - CreateTime: 0, - }).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 3) - t.Assert(one["id"], 2) - t.Assert(one["nickname"], "name_2") - }) + table := createInitTable() + defer dropTable(table) + + // "id": i, + // "passport": fmt.Sprintf(`user_%d`, i), + // "password": fmt.Sprintf(`pass_%d`, i), + // "nickname": fmt.Sprintf(`name_%d`, i), + // "create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(), + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).FieldsEx("create_date, Passport, Password, NickName, CreateTime").Where("id", 2).Value() + t.AssertNil(err) + t.Assert(value.Int(), 2) + }) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Model(table).FieldsEx("create_date, ID, Passport, Password, CreateTime").Where("id", 2).Value() + t.AssertNil(err) + t.Assert(value.String(), "name_2") + }) + // Map + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).FieldsEx(g.Map{ + "Passport": 1, + "Password": 1, + "CreateTime": 1, + }).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 3) + t.Assert(one["id"], 2) + t.Assert(one["nickname"], "name_2") + }) + // Struct + gtest.C(t, func(t *gtest.T) { + type T struct { + Passport int + Password int + CreateTime int + } + one, err := db.Model(table).FieldsEx(&T{ + Passport: 0, + Password: 0, + CreateTime: 0, + }).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 3) + t.Assert(one["id"], 2) + t.Assert(one["nickname"], "name_2") + }) } func Test_Model_Fields_Struct(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - type A struct { - Passport string - Password string - } - type B struct { - A - NickName string - } - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Fields(A{}).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 2) - t.Assert(one["passport"], "user_2") - t.Assert(one["password"], "pass_2") - }) - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Fields(&A{}).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 2) - t.Assert(one["passport"], "user_2") - t.Assert(one["password"], "pass_2") - }) - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Fields(B{}).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 3) - t.Assert(one["passport"], "user_2") - t.Assert(one["password"], "pass_2") - t.Assert(one["nickname"], "name_2") - }) - gtest.C(t, func(t *gtest.T) { - one, err := db.Model(table).Fields(&B{}).Where("id", 2).One() - t.AssertNil(err) - t.Assert(len(one), 3) - t.Assert(one["passport"], "user_2") - t.Assert(one["password"], "pass_2") - t.Assert(one["nickname"], "name_2") - }) + table := createInitTable() + defer dropTable(table) + + type A struct { + Passport string + Password string + } + type B struct { + A + NickName string + } + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Fields(A{}).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["passport"], "user_2") + t.Assert(one["password"], "pass_2") + }) + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Fields(&A{}).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["passport"], "user_2") + t.Assert(one["password"], "pass_2") + }) + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Fields(B{}).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 3) + t.Assert(one["passport"], "user_2") + t.Assert(one["password"], "pass_2") + t.Assert(one["nickname"], "name_2") + }) + gtest.C(t, func(t *gtest.T) { + one, err := db.Model(table).Fields(&B{}).Where("id", 2).One() + t.AssertNil(err) + t.Assert(len(one), 3) + t.Assert(one["passport"], "user_2") + t.Assert(one["password"], "pass_2") + t.Assert(one["nickname"], "name_2") + }) } func Test_Model_NullField(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport *string - } - data := g.Map{ - "id": 1, - "passport": nil, - } - result, err := db.Model(table).Data(data).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - - var user *User - err = one.Struct(&user) - t.AssertNil(err) - t.Assert(user.Id, data["id"]) - t.Assert(user.Passport, data["passport"]) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport *string + } + data := g.Map{ + "id": 1, + "passport": nil, + } + result, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + + var user *User + err = one.Struct(&user) + t.AssertNil(err) + t.Assert(user.Id, data["id"]) + t.Assert(user.Passport, data["passport"]) + }) } func Test_Model_Empty_Slice_Argument(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Where(`id`, g.Slice{}).All() - t.AssertNil(err) - t.Assert(len(result), 0) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Where(`id in(?)`, g.Slice{}).All() - t.AssertNil(err) - t.Assert(len(result), 0) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(`id`, g.Slice{}).All() + t.AssertNil(err) + t.Assert(len(result), 0) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where(`id in(?)`, g.Slice{}).All() + t.AssertNil(err) + t.Assert(len(result), 0) + }) } func Test_Model_HasTable(t *testing.T) { - table := createTable() - defer dropTable(table) + table := createTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - t.AssertNil(db.GetCore().ClearCacheAll(ctx)) - result, err := db.GetCore().HasTable(table) - t.Assert(result, true) - t.AssertNil(err) - }) + gtest.C(t, func(t *gtest.T) { + t.AssertNil(db.GetCore().ClearCacheAll(ctx)) + result, err := db.GetCore().HasTable(table) + t.Assert(result, true) + t.AssertNil(err) + }) - gtest.C(t, func(t *gtest.T) { - t.AssertNil(db.GetCore().ClearCacheAll(ctx)) - result, err := db.GetCore().HasTable("table12321") - t.Assert(result, false) - t.AssertNil(err) - }) + gtest.C(t, func(t *gtest.T) { + t.AssertNil(db.GetCore().ClearCacheAll(ctx)) + result, err := db.GetCore().HasTable("table12321") + t.Assert(result, false) + t.AssertNil(err) + }) } func Test_Model_HasField(t *testing.T) { - table := createTable() - defer dropTable(table) + table := createTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).HasField("id") - t.Assert(result, true) - t.AssertNil(err) - }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).HasField("id") + t.Assert(result, true) + t.AssertNil(err) + }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).HasField("id123") - t.Assert(result, false) - t.AssertNil(err) - }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).HasField("id123") + t.Assert(result, false) + t.AssertNil(err) + }) } func createTableForTimeZoneTest() string { - tableName := "user_" + gtime.Now().TimestampNanoStr() - if _, err := db.Exec(ctx, fmt.Sprintf(` + tableName := "user_" + gtime.Now().TimestampNanoStr() + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE %s ( id int(10) unsigned NOT NULL AUTO_INCREMENT, passport varchar(45) NULL, @@ -2521,698 +2521,698 @@ func createTableForTimeZoneTest() string { PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; `, tableName, - )); err != nil { - gtest.Fatal(err) - } - return tableName + )); err != nil { + gtest.Fatal(err) + } + return tableName } // https://github.com/gogf/gf/issues/1012 func Test_TimeZoneInsert(t *testing.T) { - tableName := createTableForTimeZoneTest() - defer dropTable(tableName) - - tokyoLoc, err := time.LoadLocation("Asia/Tokyo") - gtest.AssertNil(err) - - CreateTime := "2020-11-22 12:23:45" - UpdateTime := "2020-11-22 13:23:46" - DeleteTime := "2020-11-22 14:23:47" - type User struct { - Id int `json:"id"` - CreatedAt *gtime.Time `json:"created_at"` - UpdatedAt gtime.Time `json:"updated_at"` - DeletedAt time.Time `json:"deleted_at"` - } - t1, _ := time.ParseInLocation("2006-01-02 15:04:05", CreateTime, tokyoLoc) - t2, _ := time.ParseInLocation("2006-01-02 15:04:05", UpdateTime, tokyoLoc) - t3, _ := time.ParseInLocation("2006-01-02 15:04:05", DeleteTime, tokyoLoc) - u := &User{ - Id: 1, - CreatedAt: gtime.New(t1.UTC()), - UpdatedAt: *gtime.New(t2.UTC()), - DeletedAt: t3.UTC(), - } - - gtest.C(t, func(t *gtest.T) { - _, err = db.Model(tableName).Unscoped().Insert(u) - t.AssertNil(err) - userEntity := &User{} - err = db.Model(tableName).Where("id", 1).Unscoped().Scan(&userEntity) - t.AssertNil(err) - t.Assert(userEntity.CreatedAt.String(), "2020-11-22 11:23:45") - t.Assert(userEntity.UpdatedAt.String(), "2020-11-22 12:23:46") - t.Assert(gtime.NewFromTime(userEntity.DeletedAt).String(), "2020-11-22 13:23:47") - }) + tableName := createTableForTimeZoneTest() + defer dropTable(tableName) + + tokyoLoc, err := time.LoadLocation("Asia/Tokyo") + gtest.AssertNil(err) + + CreateTime := "2020-11-22 12:23:45" + UpdateTime := "2020-11-22 13:23:46" + DeleteTime := "2020-11-22 14:23:47" + type User struct { + Id int `json:"id"` + CreatedAt *gtime.Time `json:"created_at"` + UpdatedAt gtime.Time `json:"updated_at"` + DeletedAt time.Time `json:"deleted_at"` + } + t1, _ := time.ParseInLocation("2006-01-02 15:04:05", CreateTime, tokyoLoc) + t2, _ := time.ParseInLocation("2006-01-02 15:04:05", UpdateTime, tokyoLoc) + t3, _ := time.ParseInLocation("2006-01-02 15:04:05", DeleteTime, tokyoLoc) + u := &User{ + Id: 1, + CreatedAt: gtime.New(t1.UTC()), + UpdatedAt: *gtime.New(t2.UTC()), + DeletedAt: t3.UTC(), + } + + gtest.C(t, func(t *gtest.T) { + _, err = db.Model(tableName).Unscoped().Insert(u) + t.AssertNil(err) + userEntity := &User{} + err = db.Model(tableName).Where("id", 1).Unscoped().Scan(&userEntity) + t.AssertNil(err) + t.Assert(userEntity.CreatedAt.String(), "2020-11-22 11:23:45") + t.Assert(userEntity.UpdatedAt.String(), "2020-11-22 12:23:46") + t.Assert(gtime.NewFromTime(userEntity.DeletedAt).String(), "2020-11-22 13:23:47") + }) } func Test_Model_Fields_Map_Struct(t *testing.T) { - table := createInitTable() - defer dropTable(table) - // map - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Fields(g.Map{ - "ID": 1, - "PASSPORT": 1, - "NONE_EXIST": 1, - }).Where("id", 1).One() - t.AssertNil(err) - t.Assert(len(result), 2) - t.Assert(result["id"], 1) - t.Assert(result["passport"], "user_1") - }) - // struct - gtest.C(t, func(t *gtest.T) { - type A struct { - ID int - PASSPORT string - XXX_TYPE int - } - a := A{} - err := db.Model(table).Fields(a).Where("id", 1).Scan(&a) - t.AssertNil(err) - t.Assert(a.ID, 1) - t.Assert(a.PASSPORT, "user_1") - t.Assert(a.XXX_TYPE, 0) - }) - // *struct - gtest.C(t, func(t *gtest.T) { - type A struct { - ID int - PASSPORT string - XXX_TYPE int - } - var a *A - err := db.Model(table).Fields(a).Where("id", 1).Scan(&a) - t.AssertNil(err) - t.Assert(a.ID, 1) - t.Assert(a.PASSPORT, "user_1") - t.Assert(a.XXX_TYPE, 0) - }) - // **struct - gtest.C(t, func(t *gtest.T) { - type A struct { - ID int - PASSPORT string - XXX_TYPE int - } - var a *A - err := db.Model(table).Fields(&a).Where("id", 1).Scan(&a) - t.AssertNil(err) - t.Assert(a.ID, 1) - t.Assert(a.PASSPORT, "user_1") - t.Assert(a.XXX_TYPE, 0) - }) + table := createInitTable() + defer dropTable(table) + // map + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Fields(g.Map{ + "ID": 1, + "PASSPORT": 1, + "NONE_EXIST": 1, + }).Where("id", 1).One() + t.AssertNil(err) + t.Assert(len(result), 2) + t.Assert(result["id"], 1) + t.Assert(result["passport"], "user_1") + }) + // struct + gtest.C(t, func(t *gtest.T) { + type A struct { + ID int + PASSPORT string + XXX_TYPE int + } + a := A{} + err := db.Model(table).Fields(a).Where("id", 1).Scan(&a) + t.AssertNil(err) + t.Assert(a.ID, 1) + t.Assert(a.PASSPORT, "user_1") + t.Assert(a.XXX_TYPE, 0) + }) + // *struct + gtest.C(t, func(t *gtest.T) { + type A struct { + ID int + PASSPORT string + XXX_TYPE int + } + var a *A + err := db.Model(table).Fields(a).Where("id", 1).Scan(&a) + t.AssertNil(err) + t.Assert(a.ID, 1) + t.Assert(a.PASSPORT, "user_1") + t.Assert(a.XXX_TYPE, 0) + }) + // **struct + gtest.C(t, func(t *gtest.T) { + type A struct { + ID int + PASSPORT string + XXX_TYPE int + } + var a *A + err := db.Model(table).Fields(&a).Where("id", 1).Scan(&a) + t.AssertNil(err) + t.Assert(a.ID, 1) + t.Assert(a.PASSPORT, "user_1") + t.Assert(a.XXX_TYPE, 0) + }) } func Test_Model_Min_Max_Avg_Sum(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Min("id") - t.AssertNil(err) - t.Assert(result, 1) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Max("id") - t.AssertNil(err) - t.Assert(result, TableSize) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Avg("id") - t.AssertNil(err) - t.Assert(result, 5.5) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Sum("id") - t.AssertNil(err) - t.Assert(result, 55) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Min("id") + t.AssertNil(err) + t.Assert(result, 1) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Max("id") + t.AssertNil(err) + t.Assert(result, TableSize) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Avg("id") + t.AssertNil(err) + t.Assert(result, 5.5) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Sum("id") + t.AssertNil(err) + t.Assert(result, 55) + }) } func Test_Model_CountColumn(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).CountColumn("id") - t.AssertNil(err) - t.Assert(result, TableSize) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).WhereIn("id", g.Slice{1, 2, 3}).CountColumn("id") - t.AssertNil(err) - t.Assert(result, 3) - }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).CountColumn("id") + t.AssertNil(err) + t.Assert(result, TableSize) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).WhereIn("id", g.Slice{1, 2, 3}).CountColumn("id") + t.AssertNil(err) + t.Assert(result, 3) + }) } func Test_Model_InsertAndGetId(t *testing.T) { - table := createTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - id, err := db.Model(table).Data(g.Map{ - "id": 1, - "passport": "user_1", - "password": "pass_1", - "nickname": "name_1", - }).InsertAndGetId() - t.AssertNil(err) - t.Assert(id, 1) - }) - gtest.C(t, func(t *gtest.T) { - id, err := db.Model(table).Data(g.Map{ - "passport": "user_2", - "password": "pass_2", - "nickname": "name_2", - }).InsertAndGetId() - t.AssertNil(err) - t.Assert(id, 2) - }) + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + id, err := db.Model(table).Data(g.Map{ + "id": 1, + "passport": "user_1", + "password": "pass_1", + "nickname": "name_1", + }).InsertAndGetId() + t.AssertNil(err) + t.Assert(id, 1) + }) + gtest.C(t, func(t *gtest.T) { + id, err := db.Model(table).Data(g.Map{ + "passport": "user_2", + "password": "pass_2", + "nickname": "name_2", + }).InsertAndGetId() + t.AssertNil(err) + t.Assert(id, 2) + }) } func Test_Model_Increment_Decrement(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Where("id", 1).Increment("id", 100) - t.AssertNil(err) - rows, _ := result.RowsAffected() - t.Assert(rows, 1) - }) - gtest.C(t, func(t *gtest.T) { - result, err := db.Model(table).Where("id", 101).Decrement("id", 10) - t.AssertNil(err) - rows, _ := result.RowsAffected() - t.Assert(rows, 1) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 91).Count() - t.AssertNil(err) - t.Assert(count, int64(1)) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("id", 1).Increment("id", 100) + t.AssertNil(err) + rows, _ := result.RowsAffected() + t.Assert(rows, 1) + }) + gtest.C(t, func(t *gtest.T) { + result, err := db.Model(table).Where("id", 101).Decrement("id", 10) + t.AssertNil(err) + rows, _ := result.RowsAffected() + t.Assert(rows, 1) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 91).Count() + t.AssertNil(err) + t.Assert(count, int64(1)) + }) } func Test_Model_OnDuplicate(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - // string type 1. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicate("passport,password").Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["password"], data["password"]) - t.Assert(one["nickname"], "name_1") - }) - - // string type 2. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicate("passport", "password").Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["password"], data["password"]) - t.Assert(one["nickname"], "name_1") - }) - - // slice. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicate(g.Slice{"passport", "password"}).Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["password"], data["password"]) - t.Assert(one["nickname"], "name_1") - }) - - // map. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicate(g.Map{ - "passport": "nickname", - "password": "nickname", - }).Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["nickname"]) - t.Assert(one["password"], data["nickname"]) - t.Assert(one["nickname"], "name_1") - }) - - // map+raw. - gtest.C(t, func(t *gtest.T) { - data := g.MapStrStr{ - "id": "1", - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicate(g.Map{ - "passport": gdb.Raw("CONCAT(VALUES(`passport`), '1')"), - "password": gdb.Raw("CONCAT(VALUES(`password`), '2')"), - }).Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]+"1") - t.Assert(one["password"], data["password"]+"2") - t.Assert(one["nickname"], "name_1") - }) + table := createInitTable() + defer dropTable(table) + + // string type 1. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicate("passport,password").Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["password"], data["password"]) + t.Assert(one["nickname"], "name_1") + }) + + // string type 2. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicate("passport", "password").Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["password"], data["password"]) + t.Assert(one["nickname"], "name_1") + }) + + // slice. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicate(g.Slice{"passport", "password"}).Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["password"], data["password"]) + t.Assert(one["nickname"], "name_1") + }) + + // map. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicate(g.Map{ + "passport": "nickname", + "password": "nickname", + }).Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["nickname"]) + t.Assert(one["password"], data["nickname"]) + t.Assert(one["nickname"], "name_1") + }) + + // map+raw. + gtest.C(t, func(t *gtest.T) { + data := g.MapStrStr{ + "id": "1", + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicate(g.Map{ + "passport": gdb.Raw("CONCAT(VALUES(`passport`), '1')"), + "password": gdb.Raw("CONCAT(VALUES(`password`), '2')"), + }).Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]+"1") + t.Assert(one["password"], data["password"]+"2") + t.Assert(one["nickname"], "name_1") + }) } func Test_Model_OnDuplicateEx(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - // string type 1. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicateEx("nickname,create_time").Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["password"], data["password"]) - t.Assert(one["nickname"], "name_1") - }) - - // string type 2. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicateEx("nickname", "create_time").Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["password"], data["password"]) - t.Assert(one["nickname"], "name_1") - }) - - // slice. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicateEx(g.Slice{"nickname", "create_time"}).Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["password"], data["password"]) - t.Assert(one["nickname"], "name_1") - }) - - // map. - gtest.C(t, func(t *gtest.T) { - data := g.Map{ - "id": 1, - "passport": "pp1", - "password": "pw1", - "nickname": "n1", - "create_time": "2016-06-06", - } - _, err := db.Model(table).OnDuplicateEx(g.Map{ - "nickname": "nickname", - "create_time": "nickname", - }).Data(data).Save() - t.AssertNil(err) - one, err := db.Model(table).WherePri(1).One() - t.AssertNil(err) - t.Assert(one["passport"], data["passport"]) - t.Assert(one["password"], data["password"]) - t.Assert(one["nickname"], "name_1") - }) + table := createInitTable() + defer dropTable(table) + + // string type 1. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicateEx("nickname,create_time").Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["password"], data["password"]) + t.Assert(one["nickname"], "name_1") + }) + + // string type 2. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicateEx("nickname", "create_time").Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["password"], data["password"]) + t.Assert(one["nickname"], "name_1") + }) + + // slice. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicateEx(g.Slice{"nickname", "create_time"}).Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["password"], data["password"]) + t.Assert(one["nickname"], "name_1") + }) + + // map. + gtest.C(t, func(t *gtest.T) { + data := g.Map{ + "id": 1, + "passport": "pp1", + "password": "pw1", + "nickname": "n1", + "create_time": "2016-06-06", + } + _, err := db.Model(table).OnDuplicateEx(g.Map{ + "nickname": "nickname", + "create_time": "nickname", + }).Data(data).Save() + t.AssertNil(err) + one, err := db.Model(table).WherePri(1).One() + t.AssertNil(err) + t.Assert(one["passport"], data["passport"]) + t.Assert(one["password"], data["password"]) + t.Assert(one["nickname"], "name_1") + }) } func Test_Model_Raw(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - all, err := db. - Raw(fmt.Sprintf("select * from %s where id in (?)", table), g.Slice{1, 5, 7, 8, 9, 10}). - WhereLT("id", 8). - WhereIn("id", g.Slice{1, 2, 3, 4, 5, 6, 7}). - OrderDesc("id"). - Limit(2). - All() - t.AssertNil(err) - t.Assert(len(all), 2) - t.Assert(all[0]["id"], 7) - t.Assert(all[1]["id"], 5) - }) - - gtest.C(t, func(t *gtest.T) { - count, err := db. - Raw(fmt.Sprintf("select * from %s where id in (?)", table), g.Slice{1, 5, 7, 8, 9, 10}). - WhereLT("id", 8). - WhereIn("id", g.Slice{1, 2, 3, 4, 5, 6, 7}). - OrderDesc("id"). - Limit(2). - Count() - t.AssertNil(err) - t.Assert(count, int64(6)) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + all, err := db. + Raw(fmt.Sprintf("select * from %s where id in (?)", table), g.Slice{1, 5, 7, 8, 9, 10}). + WhereLT("id", 8). + WhereIn("id", g.Slice{1, 2, 3, 4, 5, 6, 7}). + OrderDesc("id"). + Limit(2). + All() + t.AssertNil(err) + t.Assert(len(all), 2) + t.Assert(all[0]["id"], 7) + t.Assert(all[1]["id"], 5) + }) + + gtest.C(t, func(t *gtest.T) { + count, err := db. + Raw(fmt.Sprintf("select * from %s where id in (?)", table), g.Slice{1, 5, 7, 8, 9, 10}). + WhereLT("id", 8). + WhereIn("id", g.Slice{1, 2, 3, 4, 5, 6, 7}). + OrderDesc("id"). + Limit(2). + Count() + t.AssertNil(err) + t.Assert(count, int64(6)) + }) } func Test_Model_Handler(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - m := db.Model(table).Safe().Handler( - func(m *gdb.Model) *gdb.Model { - return m.Page(0, 3) - }, - func(m *gdb.Model) *gdb.Model { - return m.Where("id", g.Slice{1, 2, 3, 4, 5, 6}) - }, - func(m *gdb.Model) *gdb.Model { - return m.OrderDesc("id") - }, - ) - all, err := m.All() - t.AssertNil(err) - t.Assert(len(all), 3) - t.Assert(all[0]["id"], 6) - t.Assert(all[2]["id"], 4) - }) + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + m := db.Model(table).Safe().Handler( + func(m *gdb.Model) *gdb.Model { + return m.Page(0, 3) + }, + func(m *gdb.Model) *gdb.Model { + return m.Where("id", g.Slice{1, 2, 3, 4, 5, 6}) + }, + func(m *gdb.Model) *gdb.Model { + return m.OrderDesc("id") + }, + ) + all, err := m.All() + t.AssertNil(err) + t.Assert(len(all), 3) + t.Assert(all[0]["id"], 6) + t.Assert(all[2]["id"], 4) + }) } func Test_Model_FieldCount(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Fields("id").FieldCount("id", "total").Group("id").OrderAsc("id").All() - t.AssertNil(err) - t.Assert(len(all), TableSize) - t.Assert(all[0]["id"], 1) - t.Assert(all[0]["total"].Int(), 1) - }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Fields("id").FieldCount("id", "total").Group("id").OrderAsc("id").All() + t.AssertNil(err) + t.Assert(len(all), TableSize) + t.Assert(all[0]["id"], 1) + t.Assert(all[0]["total"].Int(), 1) + }) } func Test_Model_FieldMax(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Fields("id").FieldMax("id", "total").Group("id").OrderAsc("id").All() - t.AssertNil(err) - t.Assert(len(all), TableSize) - t.Assert(all[0]["id"], 1) - t.Assert(all[0]["total"].Int(), 1) - }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Fields("id").FieldMax("id", "total").Group("id").OrderAsc("id").All() + t.AssertNil(err) + t.Assert(len(all), TableSize) + t.Assert(all[0]["id"], 1) + t.Assert(all[0]["total"].Int(), 1) + }) } func Test_Model_FieldMin(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Fields("id").FieldMin("id", "total").Group("id").OrderAsc("id").All() - t.AssertNil(err) - t.Assert(len(all), TableSize) - t.Assert(all[0]["id"], 1) - t.Assert(all[0]["total"].Int(), 1) - }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Fields("id").FieldMin("id", "total").Group("id").OrderAsc("id").All() + t.AssertNil(err) + t.Assert(len(all), TableSize) + t.Assert(all[0]["id"], 1) + t.Assert(all[0]["total"].Int(), 1) + }) } func Test_Model_FieldAvg(t *testing.T) { - table := createInitTable() - defer dropTable(table) + table := createInitTable() + defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - all, err := db.Model(table).Fields("id").FieldAvg("id", "total").Group("id").OrderAsc("id").All() - t.AssertNil(err) - t.Assert(len(all), TableSize) - t.Assert(all[0]["id"], 1) - t.Assert(all[0]["total"].Int(), 1) - }) + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(table).Fields("id").FieldAvg("id", "total").Group("id").OrderAsc("id").All() + t.AssertNil(err) + t.Assert(len(all), TableSize) + t.Assert(all[0]["id"], 1) + t.Assert(all[0]["total"].Int(), 1) + }) } func Test_Model_OmitEmptyWhere(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - // Basic type where. - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 0).Count() - t.AssertNil(err) - t.Assert(count, int64(0)) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).OmitEmptyWhere().Where("id", 0).Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).OmitEmptyWhere().Where("id", 0).Where("nickname", "").Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) - // Slice where. - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", g.Slice{1, 2, 3}).Count() - t.AssertNil(err) - t.Assert(count, int64(3)) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", g.Slice{}).Count() - t.AssertNil(err) - t.Assert(count, int64(0)) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).OmitEmptyWhere().Where("id", g.Slice{}).Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", g.Slice{}).OmitEmptyWhere().Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) - // Struct Where. - gtest.C(t, func(t *gtest.T) { - type Input struct { - Id []int - Name []string - } - count, err := db.Model(table).Where(Input{}).Count() - t.AssertNil(err) - t.Assert(count, int64(0)) - }) - gtest.C(t, func(t *gtest.T) { - type Input struct { - Id []int - Name []string - } - count, err := db.Model(table).Where(Input{}).OmitEmptyWhere().Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) - // Map Where. - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where(g.Map{ - "id": []int{}, - "nickname": []string{}, - }).Count() - t.AssertNil(err) - t.Assert(count, int64(0)) - }) - gtest.C(t, func(t *gtest.T) { - type Input struct { - Id []int - } - count, err := db.Model(table).Where(g.Map{ - "id": []int{}, - }).OmitEmptyWhere().Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) + table := createInitTable() + defer dropTable(table) + + // Basic type where. + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 0).Count() + t.AssertNil(err) + t.Assert(count, int64(0)) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).OmitEmptyWhere().Where("id", 0).Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).OmitEmptyWhere().Where("id", 0).Where("nickname", "").Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) + // Slice where. + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", g.Slice{1, 2, 3}).Count() + t.AssertNil(err) + t.Assert(count, int64(3)) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", g.Slice{}).Count() + t.AssertNil(err) + t.Assert(count, int64(0)) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).OmitEmptyWhere().Where("id", g.Slice{}).Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", g.Slice{}).OmitEmptyWhere().Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) + // Struct Where. + gtest.C(t, func(t *gtest.T) { + type Input struct { + Id []int + Name []string + } + count, err := db.Model(table).Where(Input{}).Count() + t.AssertNil(err) + t.Assert(count, int64(0)) + }) + gtest.C(t, func(t *gtest.T) { + type Input struct { + Id []int + Name []string + } + count, err := db.Model(table).Where(Input{}).OmitEmptyWhere().Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) + // Map Where. + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where(g.Map{ + "id": []int{}, + "nickname": []string{}, + }).Count() + t.AssertNil(err) + t.Assert(count, int64(0)) + }) + gtest.C(t, func(t *gtest.T) { + type Input struct { + Id []int + } + count, err := db.Model(table).Where(g.Map{ + "id": []int{}, + }).OmitEmptyWhere().Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) } // https://github.com/gogf/gf/issues/1387 func Test_Model_GTime_DefaultValue(t *testing.T) { - table := createTable() - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - type User struct { - Id int - Passport string - Password string - Nickname string - CreateTime *gtime.Time - } - data := User{ - Id: 1, - Passport: "user_1", - Password: "pass_1", - Nickname: "name_1", - } - // Insert - _, err := db.Model(table).Data(data).Insert() - t.AssertNil(err) - - // Select - var ( - user *User - ) - err = db.Model(table).Scan(&user) - t.AssertNil(err) - t.Assert(user.Passport, data.Passport) - t.Assert(user.Password, data.Password) - t.Assert(user.CreateTime, data.CreateTime) - t.Assert(user.Nickname, data.Nickname) - - // Insert - user.Id = 2 - _, err = db.Model(table).Data(user).Insert() - t.AssertNil(err) - }) + table := createTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + type User struct { + Id int + Passport string + Password string + Nickname string + CreateTime *gtime.Time + } + data := User{ + Id: 1, + Passport: "user_1", + Password: "pass_1", + Nickname: "name_1", + } + // Insert + _, err := db.Model(table).Data(data).Insert() + t.AssertNil(err) + + // Select + var ( + user *User + ) + err = db.Model(table).Scan(&user) + t.AssertNil(err) + t.Assert(user.Passport, data.Passport) + t.Assert(user.Password, data.Password) + t.Assert(user.CreateTime, data.CreateTime) + t.Assert(user.Nickname, data.Nickname) + + // Insert + user.Id = 2 + _, err = db.Model(table).Data(user).Insert() + t.AssertNil(err) + }) } // Using filter does 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.Model(table).Data(data).Insert() - t.AssertNil(err) - 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.Model(table).Data(data).Insert() - t.AssertNil(err) - n, _ := result.LastInsertId() - t.Assert(n, 2) - - t.Assert(data[0]["uid"], 1) - t.Assert(data[1]["uid"], 2) - }) + // 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.Model(table).Data(data).Insert() + t.AssertNil(err) + 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.Model(table).Data(data).Insert() + t.AssertNil(err) + n, _ := result.LastInsertId() + t.Assert(n, 2) + + t.Assert(data[0]["uid"], 1) + t.Assert(data[1]["uid"], 2) + }) } func Test_Model_Embedded_Filter(t *testing.T) { - table := createTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - type Base struct { - Id int - Uid int - CreateTime string - NoneExist string - } - type User struct { - Base - Passport string - Password string - Nickname string - } - result, err := db.Model(table).Data(User{ - Passport: "john-test", - Password: "123456", - Nickname: "John", - Base: Base{ - Id: 100, - Uid: 100, - CreateTime: gtime.Now().String(), - }, - }).Insert() - t.AssertNil(err) - n, _ := result.RowsAffected() - t.Assert(n, 1) - - var user *User - err = db.Model(table).Fields(user).Where("id=100").Scan(&user) - t.AssertNil(err) - t.Assert(user.Passport, "john-test") - t.Assert(user.Id, 100) - }) + table := createTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + type Base struct { + Id int + Uid int + CreateTime string + NoneExist string + } + type User struct { + Base + Passport string + Password string + Nickname string + } + result, err := db.Model(table).Data(User{ + Passport: "john-test", + Password: "123456", + Nickname: "John", + Base: Base{ + Id: 100, + Uid: 100, + CreateTime: gtime.Now().String(), + }, + }).Insert() + t.AssertNil(err) + n, _ := result.RowsAffected() + t.Assert(n, 1) + + var user *User + err = db.Model(table).Fields(user).Where("id=100").Scan(&user) + t.AssertNil(err) + t.Assert(user.Passport, "john-test") + t.Assert(user.Id, 100) + }) } // This is no longer used as the filter feature is automatically enabled from GoFrame v1.16.0. @@ -3242,29 +3242,29 @@ func Test_Model_Embedded_Filter(t *testing.T) { // } func Test_Model_Fields_AutoFilterInJoinStatement(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - var err error - table1 := "user" - table2 := "score" - table3 := "info" - if _, err := db.Exec(ctx, fmt.Sprintf(` + gtest.C(t, func(t *gtest.T) { + var err error + table1 := "user" + table2 := "score" + table3 := "info" + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE IF NOT EXISTS %s ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(500) NOT NULL DEFAULT '', PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1; `, table1, - )); err != nil { - t.AssertNil(err) - } - defer dropTable(table1) - _, err = db.Model(table1).Insert(g.Map{ - "id": 1, - "name": "john", - }) - t.AssertNil(err) - - if _, err := db.Exec(ctx, fmt.Sprintf(` + )); err != nil { + t.AssertNil(err) + } + defer dropTable(table1) + _, err = db.Model(table1).Insert(g.Map{ + "id": 1, + "name": "john", + }) + t.AssertNil(err) + + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE IF NOT EXISTS %s ( id int(11) NOT NULL AUTO_INCREMENT, user_id int(11) NOT NULL DEFAULT 0, @@ -3272,18 +3272,18 @@ func Test_Model_Fields_AutoFilterInJoinStatement(t *testing.T) { PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1; `, table2, - )); err != nil { - t.AssertNil(err) - } - defer dropTable(table2) - _, err = db.Model(table2).Insert(g.Map{ - "id": 1, - "user_id": 1, - "number": "n", - }) - t.AssertNil(err) - - if _, err := db.Exec(ctx, fmt.Sprintf(` + )); err != nil { + t.AssertNil(err) + } + defer dropTable(table2) + _, err = db.Model(table2).Insert(g.Map{ + "id": 1, + "user_id": 1, + "number": "n", + }) + t.AssertNil(err) + + if _, err := db.Exec(ctx, fmt.Sprintf(` CREATE TABLE IF NOT EXISTS %s ( id int(11) NOT NULL AUTO_INCREMENT, user_id int(11) NOT NULL DEFAULT 0, @@ -3291,558 +3291,558 @@ func Test_Model_Fields_AutoFilterInJoinStatement(t *testing.T) { PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1; `, table3, - )); err != nil { - t.AssertNil(err) - } - defer dropTable(table3) - _, err = db.Model(table3).Insert(g.Map{ - "id": 1, - "user_id": 1, - "description": "brief", - }) - t.AssertNil(err) - - one, err := db.Model("user"). - Where("user.id", 1). - Fields("score.number,user.name"). - LeftJoin("score", "user.id=score.user_id"). - LeftJoin("info", "info.id=info.user_id"). - Order("user.id asc"). - One() - t.AssertNil(err) - t.Assert(len(one), 2) - t.Assert(one["name"].String(), "john") - t.Assert(one["number"].String(), "n") - - one, err = db.Model("user"). - LeftJoin("score", "user.id=score.user_id"). - LeftJoin("info", "info.id=info.user_id"). - Fields("score.number,user.name"). - One() - t.AssertNil(err) - t.Assert(len(one), 2) - t.Assert(one["name"].String(), "john") - t.Assert(one["number"].String(), "n") - }) + )); err != nil { + t.AssertNil(err) + } + defer dropTable(table3) + _, err = db.Model(table3).Insert(g.Map{ + "id": 1, + "user_id": 1, + "description": "brief", + }) + t.AssertNil(err) + + one, err := db.Model("user"). + Where("user.id", 1). + Fields("score.number,user.name"). + LeftJoin("score", "user.id=score.user_id"). + LeftJoin("info", "info.id=info.user_id"). + Order("user.id asc"). + One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["name"].String(), "john") + t.Assert(one["number"].String(), "n") + + one, err = db.Model("user"). + LeftJoin("score", "user.id=score.user_id"). + LeftJoin("info", "info.id=info.user_id"). + Fields("score.number,user.name"). + One() + t.AssertNil(err) + t.Assert(len(one), 2) + t.Assert(one["name"].String(), "john") + t.Assert(one["number"].String(), "n") + }) } // https://github.com/gogf/gf/issues/1159 func Test_ScanList_NoRecreate_PtrAttribute(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - type S1 struct { - Id int - Name string - Age int - Score int - } - type S3 struct { - One *S1 - } - var ( - s []*S3 - err error - ) - r1 := gdb.Result{ - gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), - }, - gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), - }, - } - err = r1.ScanList(&s, "One") - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - - r2 := gdb.Result{ - gdb.Record{ - "id": gdb.NewValue(1), - "age": gdb.NewValue(20), - }, - gdb.Record{ - "id": gdb.NewValue(2), - "age": gdb.NewValue(21), - }, - } - err = r2.ScanList(&s, "One", "One", "id:Id") - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 20) - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 21) - }) + gtest.C(t, func(t *gtest.T) { + type S1 struct { + Id int + Name string + Age int + Score int + } + type S3 struct { + One *S1 + } + var ( + s []*S3 + err error + ) + r1 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), + }, + gdb.Record{ + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), + }, + } + err = r1.ScanList(&s, "One") + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + + r2 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(1), + "age": gdb.NewValue(20), + }, + gdb.Record{ + "id": gdb.NewValue(2), + "age": gdb.NewValue(21), + }, + } + err = r2.ScanList(&s, "One", "One", "id:Id") + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 20) + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 21) + }) } // https://github.com/gogf/gf/issues/1159 func Test_ScanList_NoRecreate_StructAttribute(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - type S1 struct { - Id int - Name string - Age int - Score int - } - type S3 struct { - One S1 - } - var ( - s []*S3 - err error - ) - r1 := gdb.Result{ - gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), - }, - gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), - }, - } - err = r1.ScanList(&s, "One") - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - - r2 := gdb.Result{ - gdb.Record{ - "id": gdb.NewValue(1), - "age": gdb.NewValue(20), - }, - gdb.Record{ - "id": gdb.NewValue(2), - "age": gdb.NewValue(21), - }, - } - err = r2.ScanList(&s, "One", "One", "id:Id") - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 20) - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 21) - }) + gtest.C(t, func(t *gtest.T) { + type S1 struct { + Id int + Name string + Age int + Score int + } + type S3 struct { + One S1 + } + var ( + s []*S3 + err error + ) + r1 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), + }, + gdb.Record{ + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), + }, + } + err = r1.ScanList(&s, "One") + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + + r2 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(1), + "age": gdb.NewValue(20), + }, + gdb.Record{ + "id": gdb.NewValue(2), + "age": gdb.NewValue(21), + }, + } + err = r2.ScanList(&s, "One", "One", "id:Id") + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 20) + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 21) + }) } // https://github.com/gogf/gf/issues/1159 func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - type S1 struct { - Id int - Name string - Age int - Score int - } - type S2 struct { - Id int - Pid int - Name string - Age int - Score int - } - type S3 struct { - One *S1 - Many []*S2 - } - var ( - s []*S3 - err error - ) - r1 := gdb.Result{ - gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), - }, - gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), - }, - } - err = r1.ScanList(&s, "One") - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - - r2 := gdb.Result{ - gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(30), - "name": gdb.NewValue("john"), - }, - gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(31), - "name": gdb.NewValue("smith"), - }, - } - err = r2.ScanList(&s, "Many", "One", "pid:Id") - // fmt.Printf("%+v", err) - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(len(s[0].Many), 2) - t.Assert(s[0].Many[0].Name, "john") - t.Assert(s[0].Many[0].Age, 30) - t.Assert(s[0].Many[1].Name, "smith") - t.Assert(s[0].Many[1].Age, 31) - - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - t.Assert(len(s[1].Many), 0) - - r3 := gdb.Result{ - gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(40), - }, - gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(41), - }, - } - err = r3.ScanList(&s, "Many", "One", "pid:Id") - // fmt.Printf("%+v", err) - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(len(s[0].Many), 2) - t.Assert(s[0].Many[0].Name, "john") - t.Assert(s[0].Many[0].Age, 40) - t.Assert(s[0].Many[1].Name, "smith") - t.Assert(s[0].Many[1].Age, 41) - - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - t.Assert(len(s[1].Many), 0) - }) + gtest.C(t, func(t *gtest.T) { + type S1 struct { + Id int + Name string + Age int + Score int + } + type S2 struct { + Id int + Pid int + Name string + Age int + Score int + } + type S3 struct { + One *S1 + Many []*S2 + } + var ( + s []*S3 + err error + ) + r1 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), + }, + gdb.Record{ + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), + }, + } + err = r1.ScanList(&s, "One") + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + + r2 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(30), + "name": gdb.NewValue("john"), + }, + gdb.Record{ + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(31), + "name": gdb.NewValue("smith"), + }, + } + err = r2.ScanList(&s, "Many", "One", "pid:Id") + // fmt.Printf("%+v", err) + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(len(s[0].Many), 2) + t.Assert(s[0].Many[0].Name, "john") + t.Assert(s[0].Many[0].Age, 30) + t.Assert(s[0].Many[1].Name, "smith") + t.Assert(s[0].Many[1].Age, 31) + + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + t.Assert(len(s[1].Many), 0) + + r3 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(40), + }, + gdb.Record{ + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(41), + }, + } + err = r3.ScanList(&s, "Many", "One", "pid:Id") + // fmt.Printf("%+v", err) + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(len(s[0].Many), 2) + t.Assert(s[0].Many[0].Name, "john") + t.Assert(s[0].Many[0].Age, 40) + t.Assert(s[0].Many[1].Name, "smith") + t.Assert(s[0].Many[1].Age, 41) + + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + t.Assert(len(s[1].Many), 0) + }) } // https://github.com/gogf/gf/issues/1159 func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - type S1 struct { - Id int - Name string - Age int - Score int - } - type S2 struct { - Id int - Pid int - Name string - Age int - Score int - } - type S3 struct { - One S1 - Many []S2 - } - var ( - s []S3 - err error - ) - r1 := gdb.Result{ - gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), - }, - gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), - }, - } - err = r1.ScanList(&s, "One") - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - - r2 := gdb.Result{ - gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(30), - "name": gdb.NewValue("john"), - }, - gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(31), - "name": gdb.NewValue("smith"), - }, - } - err = r2.ScanList(&s, "Many", "One", "pid:Id") - // fmt.Printf("%+v", err) - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(len(s[0].Many), 2) - t.Assert(s[0].Many[0].Name, "john") - t.Assert(s[0].Many[0].Age, 30) - t.Assert(s[0].Many[1].Name, "smith") - t.Assert(s[0].Many[1].Age, 31) - - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - t.Assert(len(s[1].Many), 0) - - r3 := gdb.Result{ - gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(40), - }, - gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(41), - }, - } - err = r3.ScanList(&s, "Many", "One", "pid:Id") - // fmt.Printf("%+v", err) - t.AssertNil(err) - t.Assert(len(s), 2) - t.Assert(s[0].One.Name, "john") - t.Assert(s[0].One.Age, 16) - t.Assert(len(s[0].Many), 2) - t.Assert(s[0].Many[0].Name, "john") - t.Assert(s[0].Many[0].Age, 40) - t.Assert(s[0].Many[1].Name, "smith") - t.Assert(s[0].Many[1].Age, 41) - - t.Assert(s[1].One.Name, "smith") - t.Assert(s[1].One.Age, 18) - t.Assert(len(s[1].Many), 0) - }) + gtest.C(t, func(t *gtest.T) { + type S1 struct { + Id int + Name string + Age int + Score int + } + type S2 struct { + Id int + Pid int + Name string + Age int + Score int + } + type S3 struct { + One S1 + Many []S2 + } + var ( + s []S3 + err error + ) + r1 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), + }, + gdb.Record{ + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), + }, + } + err = r1.ScanList(&s, "One") + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + + r2 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(30), + "name": gdb.NewValue("john"), + }, + gdb.Record{ + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(31), + "name": gdb.NewValue("smith"), + }, + } + err = r2.ScanList(&s, "Many", "One", "pid:Id") + // fmt.Printf("%+v", err) + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(len(s[0].Many), 2) + t.Assert(s[0].Many[0].Name, "john") + t.Assert(s[0].Many[0].Age, 30) + t.Assert(s[0].Many[1].Name, "smith") + t.Assert(s[0].Many[1].Age, 31) + + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + t.Assert(len(s[1].Many), 0) + + r3 := gdb.Result{ + gdb.Record{ + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(40), + }, + gdb.Record{ + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(41), + }, + } + err = r3.ScanList(&s, "Many", "One", "pid:Id") + // fmt.Printf("%+v", err) + t.AssertNil(err) + t.Assert(len(s), 2) + t.Assert(s[0].One.Name, "john") + t.Assert(s[0].One.Age, 16) + t.Assert(len(s[0].Many), 2) + t.Assert(s[0].Many[0].Name, "john") + t.Assert(s[0].Many[0].Age, 40) + t.Assert(s[0].Many[1].Name, "smith") + t.Assert(s[0].Many[1].Age, 41) + + t.Assert(s[1].One.Name, "smith") + t.Assert(s[1].One.Age, 18) + t.Assert(len(s[1].Many), 0) + }) } func TestResult_Structs1(t *testing.T) { - type A struct { - Id int `orm:"id"` - } - type B struct { - *A - Name string - } - gtest.C(t, func(t *gtest.T) { - r := gdb.Result{ - gdb.Record{"id": gdb.NewValue(nil), "name": gdb.NewValue("john")}, - gdb.Record{"id": gdb.NewValue(1), "name": gdb.NewValue("smith")}, - } - array := make([]*B, 2) - err := r.Structs(&array) - t.AssertNil(err) - t.Assert(array[0].Id, 0) - t.Assert(array[1].Id, 1) - t.Assert(array[0].Name, "john") - t.Assert(array[1].Name, "smith") - }) + type A struct { + Id int `orm:"id"` + } + type B struct { + *A + Name string + } + gtest.C(t, func(t *gtest.T) { + r := gdb.Result{ + gdb.Record{"id": gdb.NewValue(nil), "name": gdb.NewValue("john")}, + gdb.Record{"id": gdb.NewValue(1), "name": gdb.NewValue("smith")}, + } + array := make([]*B, 2) + err := r.Structs(&array) + t.AssertNil(err) + t.Assert(array[0].Id, 0) + t.Assert(array[1].Id, 1) + t.Assert(array[0].Name, "john") + t.Assert(array[1].Name, "smith") + }) } func Test_Builder_OmitEmptyWhere(t *testing.T) { - table := createInitTable() - defer dropTable(table) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 1).Count() - t.AssertNil(err) - t.Assert(count, int64(1)) - }) - gtest.C(t, func(t *gtest.T) { - count, err := db.Model(table).Where("id", 0).OmitEmptyWhere().Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) - gtest.C(t, func(t *gtest.T) { - builder := db.Model(table).OmitEmptyWhere().Builder() - count, err := db.Model(table).Where( - builder.Where("id", 0), - ).Count() - t.AssertNil(err) - t.Assert(count, int64(TableSize)) - }) + table := createInitTable() + defer dropTable(table) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 1).Count() + t.AssertNil(err) + t.Assert(count, int64(1)) + }) + gtest.C(t, func(t *gtest.T) { + count, err := db.Model(table).Where("id", 0).OmitEmptyWhere().Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) + gtest.C(t, func(t *gtest.T) { + builder := db.Model(table).OmitEmptyWhere().Builder() + count, err := db.Model(table).Where( + builder.Where("id", 0), + ).Count() + t.AssertNil(err) + t.Assert(count, int64(TableSize)) + }) } func Test_Scan_Nil_Result_Error(t *testing.T) { - table := createInitTable() - defer dropTable(table) - - type S struct { - Id int - Name string - Age int - Score int - } - gtest.C(t, func(t *gtest.T) { - var s *S - err := db.Model(table).Where("id", 1).Scan(&s) - t.AssertNil(err) - t.Assert(s.Id, 1) - }) - gtest.C(t, func(t *gtest.T) { - var s *S - err := db.Model(table).Where("id", 100).Scan(&s) - t.AssertNil(err) - t.Assert(s, nil) - }) - gtest.C(t, func(t *gtest.T) { - var s S - err := db.Model(table).Where("id", 100).Scan(&s) - t.Assert(err, sql.ErrNoRows) - }) - gtest.C(t, func(t *gtest.T) { - var ss []*S - err := db.Model(table).Scan(&ss) - t.AssertNil(err) - t.Assert(len(ss), TableSize) - }) - // If the result is empty, it returns error. - gtest.C(t, func(t *gtest.T) { - var ss = make([]*S, 10) - err := db.Model(table).WhereGT("id", 100).Scan(&ss) - t.Assert(err, sql.ErrNoRows) - }) + table := createInitTable() + defer dropTable(table) + + type S struct { + Id int + Name string + Age int + Score int + } + gtest.C(t, func(t *gtest.T) { + var s *S + err := db.Model(table).Where("id", 1).Scan(&s) + t.AssertNil(err) + t.Assert(s.Id, 1) + }) + gtest.C(t, func(t *gtest.T) { + var s *S + err := db.Model(table).Where("id", 100).Scan(&s) + t.AssertNil(err) + t.Assert(s, nil) + }) + gtest.C(t, func(t *gtest.T) { + var s S + err := db.Model(table).Where("id", 100).Scan(&s) + t.Assert(err, sql.ErrNoRows) + }) + gtest.C(t, func(t *gtest.T) { + var ss []*S + err := db.Model(table).Scan(&ss) + t.AssertNil(err) + t.Assert(len(ss), TableSize) + }) + // If the result is empty, it returns error. + gtest.C(t, func(t *gtest.T) { + var ss = make([]*S, 10) + err := db.Model(table).WhereGT("id", 100).Scan(&ss) + t.Assert(err, sql.ErrNoRows) + }) } func Test_Model_FixGdbJoin(t *testing.T) { - array := gstr.SplitAndTrim(gtest.DataContent(`fix_gdb_join.sql`), ";") - for _, v := range array { - if _, err := db.Exec(ctx, v); err != nil { - gtest.Error(err) - } - } - defer dropTable(`common_resource`) - defer dropTable(`managed_resource`) - defer dropTable(`rules_template`) - defer dropTable(`resource_mark`) - gtest.C(t, func(t *gtest.T) { - t.AssertNil(db.GetCore().ClearCacheAll(ctx)) - sqlSlice, err := gdb.CatchSQL(ctx, func(ctx context.Context) error { - orm := db.Model(`managed_resource`).Ctx(ctx). - LeftJoinOnField(`common_resource`, `resource_id`). - LeftJoinOnFields(`resource_mark`, `resource_mark_id`, `=`, `id`). - LeftJoinOnFields(`rules_template`, `rule_template_id`, `=`, `template_id`). - FieldsPrefix( - `managed_resource`, - "resource_id", "user", "status", "status_message", "safe_publication", "rule_template_id", - "created_at", "comments", "expired_at", "resource_mark_id", "instance_id", "resource_name", - "pay_mode"). - FieldsPrefix(`resource_mark`, "mark_name", "color"). - FieldsPrefix(`rules_template`, "name"). - FieldsPrefix(`common_resource`, `src_instance_id`, "database_kind", "source_type", "ip", "port") - all, err := orm.OrderAsc("src_instance_id").All() - t.Assert(len(all), 4) - t.Assert(all[0]["pay_mode"], 1) - t.Assert(all[0]["src_instance_id"], 2) - t.Assert(all[3]["instance_id"], "dmcins-jxy0x75m") - t.Assert(all[3]["src_instance_id"], "vdb-6b6m3u1u") - t.Assert(all[3]["resource_mark_id"], "11") - return err - }) - t.AssertNil(err) - - t.Assert(gtest.DataContent(`fix_gdb_join_expect.sql`), sqlSlice[len(sqlSlice)-1]) - }) + array := gstr.SplitAndTrim(gtest.DataContent(`fix_gdb_join.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable(`common_resource`) + defer dropTable(`managed_resource`) + defer dropTable(`rules_template`) + defer dropTable(`resource_mark`) + gtest.C(t, func(t *gtest.T) { + t.AssertNil(db.GetCore().ClearCacheAll(ctx)) + sqlSlice, err := gdb.CatchSQL(ctx, func(ctx context.Context) error { + orm := db.Model(`managed_resource`).Ctx(ctx). + LeftJoinOnField(`common_resource`, `resource_id`). + LeftJoinOnFields(`resource_mark`, `resource_mark_id`, `=`, `id`). + LeftJoinOnFields(`rules_template`, `rule_template_id`, `=`, `template_id`). + FieldsPrefix( + `managed_resource`, + "resource_id", "user", "status", "status_message", "safe_publication", "rule_template_id", + "created_at", "comments", "expired_at", "resource_mark_id", "instance_id", "resource_name", + "pay_mode"). + FieldsPrefix(`resource_mark`, "mark_name", "color"). + FieldsPrefix(`rules_template`, "name"). + FieldsPrefix(`common_resource`, `src_instance_id`, "database_kind", "source_type", "ip", "port") + all, err := orm.OrderAsc("src_instance_id").All() + t.Assert(len(all), 4) + t.Assert(all[0]["pay_mode"], 1) + t.Assert(all[0]["src_instance_id"], 2) + t.Assert(all[3]["instance_id"], "dmcins-jxy0x75m") + t.Assert(all[3]["src_instance_id"], "vdb-6b6m3u1u") + t.Assert(all[3]["resource_mark_id"], "11") + return err + }) + t.AssertNil(err) + + t.Assert(gtest.DataContent(`fix_gdb_join_expect.sql`), sqlSlice[len(sqlSlice)-1]) + }) } func Test_Model_Year_Date_Time_DateTime_Timestamp(t *testing.T) { - table := "date_time_example" - array := gstr.SplitAndTrim(gtest.DataContent(`date_time_example.sql`), ";") - for _, v := range array { - if _, err := db.Exec(ctx, v); err != nil { - gtest.Error(err) - } - } - defer dropTable(table) - - gtest.C(t, func(t *gtest.T) { - // insert. - var now = gtime.Now() - _, err := db.Model("date_time_example").Insert(g.Map{ - "year": now, - "date": now, - "time": now, - "datetime": now, - "timestamp": now, - }) - t.AssertNil(err) - // select. - one, err := db.Model("date_time_example").One() - t.AssertNil(err) - t.Assert(one["year"].String(), now.Format("Y")) - t.Assert(one["date"].String(), now.Format("Y-m-d")) - t.Assert(one["time"].String(), now.Format("H:i:s")) - t.AssertLT(one["datetime"].GTime().Sub(now).Seconds(), 5) - t.AssertLT(one["timestamp"].GTime().Sub(now).Seconds(), 5) - }) + table := "date_time_example" + array := gstr.SplitAndTrim(gtest.DataContent(`date_time_example.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + // insert. + var now = gtime.Now() + _, err := db.Model("date_time_example").Insert(g.Map{ + "year": now, + "date": now, + "time": now, + "datetime": now, + "timestamp": now, + }) + t.AssertNil(err) + // select. + one, err := db.Model("date_time_example").One() + t.AssertNil(err) + t.Assert(one["year"].String(), now.Format("Y")) + t.Assert(one["date"].String(), now.Format("Y-m-d")) + t.Assert(one["time"].String(), now.Format("H:i:s")) + t.AssertLT(one["datetime"].GTime().Sub(now).Seconds(), 5) + t.AssertLT(one["timestamp"].GTime().Sub(now).Seconds(), 5) + }) } func Test_OrderBy_Statement_Generated(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - array := gstr.SplitAndTrim(gtest.DataContent(`fix_gdb_order_by.sql`), ";") - for _, v := range array { - if _, err := db.Exec(ctx, v); err != nil { - gtest.Error(err) - } - } - defer dropTable(`employee`) - sqlArray, _ := gdb.CatchSQL(ctx, func(ctx context.Context) error { - g.DB("default").Ctx(ctx).Model("employee").Order("name asc", "age desc").All() - return nil - }) - rawSql := strings.ReplaceAll(sqlArray[len(sqlArray)-1], " ", "") - expectSql := strings.ReplaceAll("SELECT * FROM `employee` ORDER BY `name` asc, `age` desc", " ", "") - t.Assert(rawSql, expectSql) - }) + gtest.C(t, func(t *gtest.T) { + array := gstr.SplitAndTrim(gtest.DataContent(`fix_gdb_order_by.sql`), ";") + for _, v := range array { + if _, err := db.Exec(ctx, v); err != nil { + gtest.Error(err) + } + } + defer dropTable(`employee`) + sqlArray, _ := gdb.CatchSQL(ctx, func(ctx context.Context) error { + g.DB("default").Ctx(ctx).Model("employee").Order("name asc", "age desc").All() + return nil + }) + rawSql := strings.ReplaceAll(sqlArray[len(sqlArray)-1], " ", "") + expectSql := strings.ReplaceAll("SELECT * FROM `employee` ORDER BY `name` asc, `age` desc", " ", "") + t.Assert(rawSql, expectSql) + }) } func Test_Fields_Raw(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - table := createInitTable() - defer dropTable(table) - one, err := db.Model(table).Fields(gdb.Raw("1")).One() - t.AssertNil(err) - t.Assert(one["1"], 1) - - one, err = db.Model(table).Fields(gdb.Raw("2")).One() - t.AssertNil(err) - t.Assert(one["2"], 2) - - one, err = db.Model(table).Fields(gdb.Raw("2")).Where("id", 2).One() - t.AssertNil(err) - t.Assert(one["2"], 2) - - one, err = db.Model(table).Fields(gdb.Raw("2")).Where("id", 10000000000).One() - t.AssertNil(err) - t.Assert(len(one), 0) - }) + gtest.C(t, func(t *gtest.T) { + table := createInitTable() + defer dropTable(table) + one, err := db.Model(table).Fields(gdb.Raw("1")).One() + t.AssertNil(err) + t.Assert(one["1"], 1) + + one, err = db.Model(table).Fields(gdb.Raw("2")).One() + t.AssertNil(err) + t.Assert(one["2"], 2) + + one, err = db.Model(table).Fields(gdb.Raw("2")).Where("id", 2).One() + t.AssertNil(err) + t.Assert(one["2"], 2) + + one, err = db.Model(table).Fields(gdb.Raw("2")).Where("id", 10000000000).One() + t.AssertNil(err) + t.Assert(len(one), 0) + }) } diff --git a/contrib/drivers/pgsql/pgsql_convert.go b/contrib/drivers/pgsql/pgsql_convert.go index 9734c2321ea..c83a1e02918 100644 --- a/contrib/drivers/pgsql/pgsql_convert.go +++ b/contrib/drivers/pgsql/pgsql_convert.go @@ -7,130 +7,130 @@ package pgsql import ( - "context" - "reflect" - "strings" + "context" + "reflect" + "strings" - "github.com/lib/pq" + "github.com/lib/pq" - "github.com/gogf/gf/v2/database/gdb" - "github.com/gogf/gf/v2/frame/g" - "github.com/gogf/gf/v2/text/gregex" - "github.com/gogf/gf/v2/text/gstr" - "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" ) // ConvertValueForField converts value to database acceptable value. func (d *Driver) ConvertValueForField(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) { - if g.IsNil(fieldValue) { - return d.Core.ConvertValueForField(ctx, fieldType, fieldValue) - } - - var fieldValueKind = reflect.TypeOf(fieldValue).Kind() - - if fieldValueKind == reflect.Slice { - // For pgsql, json or jsonb require '[]' - if !gstr.Contains(fieldType, "json") { - fieldValue = gstr.ReplaceByMap(gconv.String(fieldValue), - map[string]string{ - "[": "{", - "]": "}", - }, - ) - } - } - return d.Core.ConvertValueForField(ctx, fieldType, fieldValue) + if g.IsNil(fieldValue) { + return d.Core.ConvertValueForField(ctx, fieldType, fieldValue) + } + + var fieldValueKind = reflect.TypeOf(fieldValue).Kind() + + if fieldValueKind == reflect.Slice { + // For pgsql, json or jsonb require '[]' + if !gstr.Contains(fieldType, "json") { + fieldValue = gstr.ReplaceByMap(gconv.String(fieldValue), + map[string]string{ + "[": "{", + "]": "}", + }, + ) + } + } + return d.Core.ConvertValueForField(ctx, fieldType, fieldValue) } // CheckLocalTypeForField checks and returns corresponding local golang type for given db type. func (d *Driver) CheckLocalTypeForField(ctx context.Context, fieldType string, fieldValue interface{}) (gdb.LocalType, error) { - var typeName string - match, _ := gregex.MatchString(`(.+?)\((.+)\)`, fieldType) - if len(match) == 3 { - typeName = gstr.Trim(match[1]) - } else { - typeName = fieldType - } - typeName = strings.ToLower(typeName) - switch typeName { - case - // For pgsql, int2 = smallint. - "int2", - // For pgsql, int4 = integer - "int4": - return gdb.LocalTypeInt, nil - - case - // For pgsql, int8 = bigint - "int8": - return gdb.LocalTypeInt64, nil - - case - "_int2", - "_int4": - return gdb.LocalTypeIntSlice, nil - - case - "_int8": - return gdb.LocalTypeInt64Slice, nil - - case - "_varchar", "_text": - return gdb.LocalTypeStringSlice, nil - - default: - return d.Core.CheckLocalTypeForField(ctx, fieldType, fieldValue) - } + var typeName string + match, _ := gregex.MatchString(`(.+?)\((.+)\)`, fieldType) + if len(match) == 3 { + typeName = gstr.Trim(match[1]) + } else { + typeName = fieldType + } + typeName = strings.ToLower(typeName) + switch typeName { + case + // For pgsql, int2 = smallint. + "int2", + // For pgsql, int4 = integer + "int4": + return gdb.LocalTypeInt, nil + + case + // For pgsql, int8 = bigint + "int8": + return gdb.LocalTypeInt64, nil + + case + "_int2", + "_int4": + return gdb.LocalTypeIntSlice, nil + + case + "_int8": + return gdb.LocalTypeInt64Slice, nil + + case + "_varchar", "_text": + return gdb.LocalTypeStringSlice, nil + + default: + return d.Core.CheckLocalTypeForField(ctx, fieldType, fieldValue) + } } // ConvertValueForLocal converts value to local Golang type of value according field type name from database. // The parameter `fieldType` is in lower case, like: // `float(5,2)`, `unsigned double(5,2)`, `decimal(10,2)`, `char(45)`, `varchar(100)`, etc. func (d *Driver) ConvertValueForLocal(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) { - typeName, _ := gregex.ReplaceString(`\(.+\)`, "", fieldType) - typeName = strings.ToLower(typeName) - switch typeName { - // For pgsql, int2 = smallint and int4 = integer. - case "int2", "int4": - return gconv.Int(gconv.String(fieldValue)), nil - - // For pgsql, int8 = bigint. - case "int8": - return gconv.Int64(gconv.String(fieldValue)), nil - - // Int32 slice. - case - "_int2", "_int4": - return gconv.Ints( - gstr.ReplaceByMap(gconv.String(fieldValue), - map[string]string{ - "{": "[", - "}": "]", - }, - ), - ), nil - - // Int64 slice. - case - "_int8": - return gconv.Int64s( - gstr.ReplaceByMap(gconv.String(fieldValue), - map[string]string{ - "{": "[", - "}": "]", - }, - ), - ), nil - - // String slice. - case "_varchar", "_text": - var result = make(pq.StringArray, 0) - if err := result.Scan(fieldValue); err != nil { - return nil, err - } - return []string(result), nil - - default: - return d.Core.ConvertValueForLocal(ctx, fieldType, fieldValue) - } + typeName, _ := gregex.ReplaceString(`\(.+\)`, "", fieldType) + typeName = strings.ToLower(typeName) + switch typeName { + // For pgsql, int2 = smallint and int4 = integer. + case "int2", "int4": + return gconv.Int(gconv.String(fieldValue)), nil + + // For pgsql, int8 = bigint. + case "int8": + return gconv.Int64(gconv.String(fieldValue)), nil + + // Int32 slice. + case + "_int2", "_int4": + return gconv.Ints( + gstr.ReplaceByMap(gconv.String(fieldValue), + map[string]string{ + "{": "[", + "}": "]", + }, + ), + ), nil + + // Int64 slice. + case + "_int8": + return gconv.Int64s( + gstr.ReplaceByMap(gconv.String(fieldValue), + map[string]string{ + "{": "[", + "}": "]", + }, + ), + ), nil + + // String slice. + case "_varchar", "_text": + var result = make(pq.StringArray, 0) + if err := result.Scan(fieldValue); err != nil { + return nil, err + } + return []string(result), nil + + default: + return d.Core.ConvertValueForLocal(ctx, fieldType, fieldValue) + } } From 7d79aea6217f5893639addc8260fa49987d492be Mon Sep 17 00:00:00 2001 From: John Guo Date: Thu, 9 Jan 2025 13:59:38 +0800 Subject: [PATCH 04/48] up --- database/gdb/gdb.go | 2 ++ database/gdb/gdb_core.go | 7 +++++-- database/gdb/gdb_core_underlying.go | 16 +++++++++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/database/gdb/gdb.go b/database/gdb/gdb.go index e3419719260..c522b09e631 100644 --- a/database/gdb/gdb.go +++ b/database/gdb/gdb.go @@ -517,6 +517,7 @@ type Core struct { links *gmap.Map // links caches all created links by node. logger glog.ILogger // Logger for logging functionality. config *ConfigNode // Current config node. + localTypeMap *gmap.StrAnyMap // Local type map for database field type conversion. dynamicConfig dynamicConfig // Dynamic configurations, which can be changed in runtime. innerMemCache *gcache.Cache // Internal memory cache for storing temporary data. } @@ -926,6 +927,7 @@ func newDBByConfigNode(node *ConfigNode, group string) (db DB, err error) { links: gmap.New(true), logger: glog.New(), config: node, + localTypeMap: gmap.NewStrAnyMap(true), innerMemCache: gcache.New(), dynamicConfig: dynamicConfig{ MaxIdleConnCount: node.MaxIdleConnCount, diff --git a/database/gdb/gdb_core.go b/database/gdb/gdb_core.go index 12ff302fb6f..c4a0bde58d9 100644 --- a/database/gdb/gdb_core.go +++ b/database/gdb/gdb_core.go @@ -222,6 +222,9 @@ func (c *Core) GetScan(ctx context.Context, pointer interface{}, sql string, arg case reflect.Struct: return c.db.GetCore().doGetStruct(ctx, pointer, sql, args...) + + default: + } return gerror.NewCodef( gcode.CodeInvalidParameter, @@ -236,12 +239,12 @@ func (c *Core) GetScan(ctx context.Context, pointer interface{}, sql string, arg func (c *Core) GetValue(ctx context.Context, sql string, args ...interface{}) (Value, error) { one, err := c.db.GetOne(ctx, sql, args...) if err != nil { - return nil, err + return NewValue(nil), err } for _, v := range one { return v, nil } - return nil, nil + return NewValue(nil), nil } // GetCount queries and returns the count from database. diff --git a/database/gdb/gdb_core_underlying.go b/database/gdb/gdb_core_underlying.go index 8150765835f..40d40c7d2a3 100644 --- a/database/gdb/gdb_core_underlying.go +++ b/database/gdb/gdb_core_underlying.go @@ -466,7 +466,7 @@ func (c *Core) RowsToResult(ctx context.Context, rows *sql.Rows) (Result, error) if convertedValue, err = c.columnValueToLocalValue(ctx, value, columnType); err != nil { return nil, err } - localType, err = c.db.CheckLocalTypeForField(ctx, columnType.DatabaseTypeName(), value) + localType, err = c.getLocalTypeForFieldWithCache(ctx, columnType.DatabaseTypeName()) if err != nil { return nil, err } @@ -481,6 +481,20 @@ func (c *Core) RowsToResult(ctx context.Context, rows *sql.Rows) (Result, error) return result, nil } +func (c *Core) getLocalTypeForFieldWithCache(ctx context.Context, fieldType string) (localType LocalType, err error) { + v := c.localTypeMap.GetOrSetFuncLock(fieldType, func() interface{} { + localType, err = c.db.CheckLocalTypeForField(ctx, fieldType, nil) + if err != nil { + return nil + } + return localType + }) + if err != nil { + return LocalTypeUndefined, err + } + return v.(LocalType), nil +} + // OrderRandomFunction returns the SQL function for random ordering. func (c *Core) OrderRandomFunction() string { return "RAND()" From 63166253ba86b103dd76ee0c25ef930eb42afc19 Mon Sep 17 00:00:00 2001 From: John Guo Date: Thu, 9 Jan 2025 14:05:56 +0800 Subject: [PATCH 05/48] up --- database/gdb/gdb_core_underlying.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/database/gdb/gdb_core_underlying.go b/database/gdb/gdb_core_underlying.go index 40d40c7d2a3..7c0bddbe30e 100644 --- a/database/gdb/gdb_core_underlying.go +++ b/database/gdb/gdb_core_underlying.go @@ -466,7 +466,7 @@ func (c *Core) RowsToResult(ctx context.Context, rows *sql.Rows) (Result, error) if convertedValue, err = c.columnValueToLocalValue(ctx, value, columnType); err != nil { return nil, err } - localType, err = c.getLocalTypeForFieldWithCache(ctx, columnType.DatabaseTypeName()) + localType, err = c.getLocalTypeForFieldWithCache(ctx, columnType.DatabaseTypeName(), convertedValue) if err != nil { return nil, err } @@ -481,9 +481,11 @@ func (c *Core) RowsToResult(ctx context.Context, rows *sql.Rows) (Result, error) return result, nil } -func (c *Core) getLocalTypeForFieldWithCache(ctx context.Context, fieldType string) (localType LocalType, err error) { - v := c.localTypeMap.GetOrSetFuncLock(fieldType, func() interface{} { - localType, err = c.db.CheckLocalTypeForField(ctx, fieldType, nil) +func (c *Core) getLocalTypeForFieldWithCache( + ctx context.Context, fieldType string, fieldValue any, +) (localType LocalType, err error) { + v := c.localTypeMap.GetOrSetFuncLock(fieldType, func() any { + localType, err = c.db.CheckLocalTypeForField(ctx, fieldType, fieldValue) if err != nil { return nil } From 19c8036db086e34d3dddfef04b9acafd461cfafd Mon Sep 17 00:00:00 2001 From: John Guo Date: Thu, 9 Jan 2025 14:11:59 +0800 Subject: [PATCH 06/48] up --- .github/workflows/ci-main.yml | 6 +++--- .github/workflows/ci-sub.yml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-main.yml b/.github/workflows/ci-main.yml index a2860760fff..a389175270a 100644 --- a/.github/workflows/ci-main.yml +++ b/.github/workflows/ci-main.yml @@ -29,7 +29,7 @@ concurrency: env: TZ: "Asia/Shanghai" # for unit testing cases of some components that only execute on the latest go version. - LATEST_GO_VERSION: "1.23" + LATEST_GO_VERSION: "1.24" jobs: code-test: @@ -40,7 +40,7 @@ jobs: # 1. Update the `LATEST_GO_VERSION` env variable. # 2. Update the `Report Coverage` action. # 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥 - go-version: [ "1.20", "1.21", "1.22", "1.23" ] + go-version: [ "1.22", "1.23", "1.24"] goarch: [ "386", "amd64" ] runs-on: ubuntu-20.04 @@ -268,7 +268,7 @@ jobs: - name: Report Coverage uses: codecov/codecov-action@v4 # Only report coverage on the latest go version and amd64 arch - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && matrix.go-version == '1.23' && matrix.goarch == 'amd64' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && matrix.go-version == '1.24' && matrix.goarch == 'amd64' }} with: flags: go-${{ matrix.go-version }}-${{ matrix.goarch }} token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/ci-sub.yml b/.github/workflows/ci-sub.yml index 5b98814ef36..8f4f0acf824 100644 --- a/.github/workflows/ci-sub.yml +++ b/.github/workflows/ci-sub.yml @@ -30,7 +30,7 @@ concurrency: env: TZ: "Asia/Shanghai" # for unit testing cases of some components that only execute on the latest go version. - LATEST_GO_VERSION: "1.23" + LATEST_GO_VERSION: "1.24" jobs: code-test: @@ -40,7 +40,7 @@ jobs: # When adding new go version to the list, make sure: # 1. Update the `LATEST_GO_VERSION` env variable. # 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥 - go-version: [ "1.20", "1.21", "1.22", "1.23" ] + go-version: [ "1.22", "1.23", "1.24" ] goarch: [ "386", "amd64" ] runs-on: ubuntu-latest From 2ae16842ef50d58cc8005598fcd29a61f88ff1df Mon Sep 17 00:00:00 2001 From: John Guo Date: Thu, 9 Jan 2025 14:14:40 +0800 Subject: [PATCH 07/48] up --- .github/workflows/ci-main.yml | 6 +++--- .github/workflows/ci-sub.yml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-main.yml b/.github/workflows/ci-main.yml index a389175270a..777a73c3dbf 100644 --- a/.github/workflows/ci-main.yml +++ b/.github/workflows/ci-main.yml @@ -29,7 +29,7 @@ concurrency: env: TZ: "Asia/Shanghai" # for unit testing cases of some components that only execute on the latest go version. - LATEST_GO_VERSION: "1.24" + LATEST_GO_VERSION: "1.23" jobs: code-test: @@ -40,7 +40,7 @@ jobs: # 1. Update the `LATEST_GO_VERSION` env variable. # 2. Update the `Report Coverage` action. # 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥 - go-version: [ "1.22", "1.23", "1.24"] + go-version: [ "1.22", "1.23" ] goarch: [ "386", "amd64" ] runs-on: ubuntu-20.04 @@ -268,7 +268,7 @@ jobs: - name: Report Coverage uses: codecov/codecov-action@v4 # Only report coverage on the latest go version and amd64 arch - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && matrix.go-version == '1.24' && matrix.goarch == 'amd64' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && matrix.go-version == '1.23' && matrix.goarch == 'amd64' }} with: flags: go-${{ matrix.go-version }}-${{ matrix.goarch }} token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/ci-sub.yml b/.github/workflows/ci-sub.yml index 8f4f0acf824..6a1244385c1 100644 --- a/.github/workflows/ci-sub.yml +++ b/.github/workflows/ci-sub.yml @@ -30,7 +30,7 @@ concurrency: env: TZ: "Asia/Shanghai" # for unit testing cases of some components that only execute on the latest go version. - LATEST_GO_VERSION: "1.24" + LATEST_GO_VERSION: "1.23" jobs: code-test: @@ -40,7 +40,7 @@ jobs: # When adding new go version to the list, make sure: # 1. Update the `LATEST_GO_VERSION` env variable. # 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥 - go-version: [ "1.22", "1.23", "1.24" ] + go-version: [ "1.22", "1.23" ] goarch: [ "386", "amd64" ] runs-on: ubuntu-latest From 185316c5c1bd8a5417818870658f140e90f91f6e Mon Sep 17 00:00:00 2001 From: John Guo Date: Thu, 9 Jan 2025 14:21:45 +0800 Subject: [PATCH 08/48] up --- database/gdb/gdb_core_structure.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/database/gdb/gdb_core_structure.go b/database/gdb/gdb_core_structure.go index 65b385a0215..a954e03f97e 100644 --- a/database/gdb/gdb_core_structure.go +++ b/database/gdb/gdb_core_structure.go @@ -236,9 +236,9 @@ func (c *Core) CheckLocalTypeForField(ctx context.Context, fieldType string, _ i typePattern = gstr.Trim(match[2]) } else { var array = gstr.SplitAndTrim(fieldType, " ") - if gstr.Equal(array[0], "unsigned") { + if len(array) > 1 && gstr.Equal(array[0], "unsigned") { typeName = array[1] - } else { + } else if len(array) > 0 { typeName = array[0] } } From 73b5bfaccca026c7ac367f1c48d16be4df08c8a3 Mon Sep 17 00:00:00 2001 From: John Guo Date: Thu, 9 Jan 2025 14:37:27 +0800 Subject: [PATCH 09/48] up --- contrib/drivers/mysql/testdata/issues/4086.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/drivers/mysql/testdata/issues/4086.sql b/contrib/drivers/mysql/testdata/issues/4086.sql index 53a3646ecc8..5e7ba66e1c5 100644 --- a/contrib/drivers/mysql/testdata/issues/4086.sql +++ b/contrib/drivers/mysql/testdata/issues/4086.sql @@ -4,7 +4,7 @@ CREATE TABLE `issue4086` ( `recommend_ids` json DEFAULT NULL, `photos` json DEFAULT NULL, PRIMARY KEY (`proxy_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +) ENGINE=InnoDB; INSERT INTO `issue4086` (`proxy_id`, `recommend_ids`, `photos`) VALUES (1, '[584, 585]', 'null'); INSERT INTO `issue4086` (`proxy_id`, `recommend_ids`, `photos`) VALUES (2, '[]', NULL); \ No newline at end of file From da5fc0ec4b5fc100b4dc7ebf6e03fc95aa296dc6 Mon Sep 17 00:00:00 2001 From: John Guo Date: Thu, 9 Jan 2025 14:46:59 +0800 Subject: [PATCH 10/48] up --- .../sqlite/sqlite_z_unit_model_test.go | 125 +++++++++--------- .../sqlitecgo/sqlitecgo_z_unit_model_test.go | 125 +++++++++--------- 2 files changed, 124 insertions(+), 126 deletions(-) diff --git a/contrib/drivers/sqlite/sqlite_z_unit_model_test.go b/contrib/drivers/sqlite/sqlite_z_unit_model_test.go index 19e97bfa51a..4d05f516e96 100644 --- a/contrib/drivers/sqlite/sqlite_z_unit_model_test.go +++ b/contrib/drivers/sqlite/sqlite_z_unit_model_test.go @@ -17,7 +17,6 @@ import ( "github.com/gogf/gf/v2/container/garray" "github.com/gogf/gf/v2/container/gmap" - "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/errors/gcode" @@ -3989,14 +3988,14 @@ func Test_ScanList_NoRecreate_PtrAttribute(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gvar.New(1), - "name": gvar.New("john"), - "age": gvar.New(16), + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), }, gdb.Record{ - "id": gvar.New(2), - "name": gvar.New("smith"), - "age": gvar.New(18), + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), }, } err = r1.ScanList(&s, "One") @@ -4009,12 +4008,12 @@ func Test_ScanList_NoRecreate_PtrAttribute(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gvar.New(1), - "age": gvar.New(20), + "id": gdb.NewValue(1), + "age": gdb.NewValue(20), }, gdb.Record{ - "id": gvar.New(2), - "age": gvar.New(21), + "id": gdb.NewValue(2), + "age": gdb.NewValue(21), }, } err = r2.ScanList(&s, "One", "One", "id:Id") @@ -4045,14 +4044,14 @@ func Test_ScanList_NoRecreate_StructAttribute(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gvar.New(1), - "name": gvar.New("john"), - "age": gvar.New(16), + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), }, gdb.Record{ - "id": gvar.New(2), - "name": gvar.New("smith"), - "age": gvar.New(18), + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), }, } err = r1.ScanList(&s, "One") @@ -4065,12 +4064,12 @@ func Test_ScanList_NoRecreate_StructAttribute(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gvar.New(1), - "age": gvar.New(20), + "id": gdb.NewValue(1), + "age": gdb.NewValue(20), }, gdb.Record{ - "id": gvar.New(2), - "age": gvar.New(21), + "id": gdb.NewValue(2), + "age": gdb.NewValue(21), }, } err = r2.ScanList(&s, "One", "One", "id:Id") @@ -4109,14 +4108,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gvar.New(1), - "name": gvar.New("john"), - "age": gvar.New(16), + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), }, gdb.Record{ - "id": gvar.New(2), - "name": gvar.New("smith"), - "age": gvar.New(18), + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), }, } err = r1.ScanList(&s, "One") @@ -4129,16 +4128,16 @@ func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gvar.New(100), - "pid": gvar.New(1), - "age": gvar.New(30), - "name": gvar.New("john"), + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(30), + "name": gdb.NewValue("john"), }, gdb.Record{ - "id": gvar.New(200), - "pid": gvar.New(1), - "age": gvar.New(31), - "name": gvar.New("smith"), + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(31), + "name": gdb.NewValue("smith"), }, } err = r2.ScanList(&s, "Many", "One", "pid:Id") @@ -4159,14 +4158,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { r3 := gdb.Result{ gdb.Record{ - "id": gvar.New(100), - "pid": gvar.New(1), - "age": gvar.New(40), + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(40), }, gdb.Record{ - "id": gvar.New(200), - "pid": gvar.New(1), - "age": gvar.New(41), + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(41), }, } err = r3.ScanList(&s, "Many", "One", "pid:Id") @@ -4213,14 +4212,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gvar.New(1), - "name": gvar.New("john"), - "age": gvar.New(16), + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), }, gdb.Record{ - "id": gvar.New(2), - "name": gvar.New("smith"), - "age": gvar.New(18), + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), }, } err = r1.ScanList(&s, "One") @@ -4233,16 +4232,16 @@ func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gvar.New(100), - "pid": gvar.New(1), - "age": gvar.New(30), - "name": gvar.New("john"), + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(30), + "name": gdb.NewValue("john"), }, gdb.Record{ - "id": gvar.New(200), - "pid": gvar.New(1), - "age": gvar.New(31), - "name": gvar.New("smith"), + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(31), + "name": gdb.NewValue("smith"), }, } err = r2.ScanList(&s, "Many", "One", "pid:Id") @@ -4263,14 +4262,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { r3 := gdb.Result{ gdb.Record{ - "id": gvar.New(100), - "pid": gvar.New(1), - "age": gvar.New(40), + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(40), }, gdb.Record{ - "id": gvar.New(200), - "pid": gvar.New(1), - "age": gvar.New(41), + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(41), }, } err = r3.ScanList(&s, "Many", "One", "pid:Id") @@ -4301,8 +4300,8 @@ func TestResult_Structs1(t *testing.T) { } gtest.C(t, func(t *gtest.T) { r := gdb.Result{ - gdb.Record{"id": gvar.New(nil), "name": gvar.New("john")}, - gdb.Record{"id": gvar.New(nil), "name": gvar.New("smith")}, + gdb.Record{"id": gdb.NewValue(nil), "name": gdb.NewValue("john")}, + gdb.Record{"id": gdb.NewValue(nil), "name": gdb.NewValue("smith")}, } array := make([]*B, 2) err := r.Structs(&array) diff --git a/contrib/drivers/sqlitecgo/sqlitecgo_z_unit_model_test.go b/contrib/drivers/sqlitecgo/sqlitecgo_z_unit_model_test.go index 613ef9c64b3..187d08aebf8 100644 --- a/contrib/drivers/sqlitecgo/sqlitecgo_z_unit_model_test.go +++ b/contrib/drivers/sqlitecgo/sqlitecgo_z_unit_model_test.go @@ -17,7 +17,6 @@ import ( "github.com/gogf/gf/v2/container/garray" "github.com/gogf/gf/v2/container/gmap" - "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/errors/gcode" @@ -4037,14 +4036,14 @@ func Test_ScanList_NoRecreate_PtrAttribute(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gvar.New(1), - "name": gvar.New("john"), - "age": gvar.New(16), + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), }, gdb.Record{ - "id": gvar.New(2), - "name": gvar.New("smith"), - "age": gvar.New(18), + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), }, } err = r1.ScanList(&s, "One") @@ -4057,12 +4056,12 @@ func Test_ScanList_NoRecreate_PtrAttribute(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gvar.New(1), - "age": gvar.New(20), + "id": gdb.NewValue(1), + "age": gdb.NewValue(20), }, gdb.Record{ - "id": gvar.New(2), - "age": gvar.New(21), + "id": gdb.NewValue(2), + "age": gdb.NewValue(21), }, } err = r2.ScanList(&s, "One", "One", "id:Id") @@ -4093,14 +4092,14 @@ func Test_ScanList_NoRecreate_StructAttribute(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gvar.New(1), - "name": gvar.New("john"), - "age": gvar.New(16), + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), }, gdb.Record{ - "id": gvar.New(2), - "name": gvar.New("smith"), - "age": gvar.New(18), + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), }, } err = r1.ScanList(&s, "One") @@ -4113,12 +4112,12 @@ func Test_ScanList_NoRecreate_StructAttribute(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gvar.New(1), - "age": gvar.New(20), + "id": gdb.NewValue(1), + "age": gdb.NewValue(20), }, gdb.Record{ - "id": gvar.New(2), - "age": gvar.New(21), + "id": gdb.NewValue(2), + "age": gdb.NewValue(21), }, } err = r2.ScanList(&s, "One", "One", "id:Id") @@ -4157,14 +4156,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gvar.New(1), - "name": gvar.New("john"), - "age": gvar.New(16), + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), }, gdb.Record{ - "id": gvar.New(2), - "name": gvar.New("smith"), - "age": gvar.New(18), + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), }, } err = r1.ScanList(&s, "One") @@ -4177,16 +4176,16 @@ func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gvar.New(100), - "pid": gvar.New(1), - "age": gvar.New(30), - "name": gvar.New("john"), + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(30), + "name": gdb.NewValue("john"), }, gdb.Record{ - "id": gvar.New(200), - "pid": gvar.New(1), - "age": gvar.New(31), - "name": gvar.New("smith"), + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(31), + "name": gdb.NewValue("smith"), }, } err = r2.ScanList(&s, "Many", "One", "pid:Id") @@ -4207,14 +4206,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { r3 := gdb.Result{ gdb.Record{ - "id": gvar.New(100), - "pid": gvar.New(1), - "age": gvar.New(40), + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(40), }, gdb.Record{ - "id": gvar.New(200), - "pid": gvar.New(1), - "age": gvar.New(41), + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(41), }, } err = r3.ScanList(&s, "Many", "One", "pid:Id") @@ -4261,14 +4260,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gvar.New(1), - "name": gvar.New("john"), - "age": gvar.New(16), + "id": gdb.NewValue(1), + "name": gdb.NewValue("john"), + "age": gdb.NewValue(16), }, gdb.Record{ - "id": gvar.New(2), - "name": gvar.New("smith"), - "age": gvar.New(18), + "id": gdb.NewValue(2), + "name": gdb.NewValue("smith"), + "age": gdb.NewValue(18), }, } err = r1.ScanList(&s, "One") @@ -4281,16 +4280,16 @@ func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gvar.New(100), - "pid": gvar.New(1), - "age": gvar.New(30), - "name": gvar.New("john"), + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(30), + "name": gdb.NewValue("john"), }, gdb.Record{ - "id": gvar.New(200), - "pid": gvar.New(1), - "age": gvar.New(31), - "name": gvar.New("smith"), + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(31), + "name": gdb.NewValue("smith"), }, } err = r2.ScanList(&s, "Many", "One", "pid:Id") @@ -4311,14 +4310,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { r3 := gdb.Result{ gdb.Record{ - "id": gvar.New(100), - "pid": gvar.New(1), - "age": gvar.New(40), + "id": gdb.NewValue(100), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(40), }, gdb.Record{ - "id": gvar.New(200), - "pid": gvar.New(1), - "age": gvar.New(41), + "id": gdb.NewValue(200), + "pid": gdb.NewValue(1), + "age": gdb.NewValue(41), }, } err = r3.ScanList(&s, "Many", "One", "pid:Id") @@ -4349,8 +4348,8 @@ func TestResult_Structs1(t *testing.T) { } gtest.C(t, func(t *gtest.T) { r := gdb.Result{ - gdb.Record{"id": gvar.New(nil), "name": gvar.New("john")}, - gdb.Record{"id": gvar.New(nil), "name": gvar.New("smith")}, + gdb.Record{"id": gdb.NewValue(nil), "name": gdb.NewValue("john")}, + gdb.Record{"id": gdb.NewValue(nil), "name": gdb.NewValue("smith")}, } array := make([]*B, 2) err := r.Structs(&array) From 67bb75a2d99ff22bb6332866204f301ab047f7dd Mon Sep 17 00:00:00 2001 From: John Guo Date: Thu, 27 Feb 2025 16:57:37 +0800 Subject: [PATCH 11/48] fix: 4086 --- .../mysql/mysql_z_unit_feature_hook_test.go | 3 +- .../drivers/mysql/mysql_z_unit_issue_test.go | 3 +- .../drivers/mysql/mysql_z_unit_model_test.go | 125 +++++++++--------- database/gdb/gdb.go | 51 +++---- database/gdb/gdb_core.go | 5 +- database/gdb/gdb_core_underlying.go | 8 +- database/gdb/gdb_type_result.go | 7 +- database/gdb/gdb_type_value.go | 19 --- database/gdb/internal/defines/defines.go | 36 ----- database/gdb/internal/fieldvar/fieldvar.go | 63 --------- .../gdb/internal/fieldvar/fieldvar_basic.go | 99 -------------- .../gdb/internal/fieldvar/fieldvar_copy.go | 30 ----- database/gdb/internal/fieldvar/fieldvar_is.go | 51 ------- .../gdb/internal/fieldvar/fieldvar_map.go | 65 --------- .../gdb/internal/fieldvar/fieldvar_scan.go | 18 --- .../gdb/internal/fieldvar/fieldvar_set.go | 14 -- .../gdb/internal/fieldvar/fieldvar_slice.go | 86 ------------ .../gdb/internal/fieldvar/fieldvar_struct.go | 23 ---- .../gdb/internal/fieldvar/fieldvar_time.go | 34 ----- 19 files changed, 101 insertions(+), 639 deletions(-) delete mode 100644 database/gdb/gdb_type_value.go delete mode 100644 database/gdb/internal/defines/defines.go delete mode 100644 database/gdb/internal/fieldvar/fieldvar.go delete mode 100644 database/gdb/internal/fieldvar/fieldvar_basic.go delete mode 100644 database/gdb/internal/fieldvar/fieldvar_copy.go delete mode 100644 database/gdb/internal/fieldvar/fieldvar_is.go delete mode 100644 database/gdb/internal/fieldvar/fieldvar_map.go delete mode 100644 database/gdb/internal/fieldvar/fieldvar_scan.go delete mode 100644 database/gdb/internal/fieldvar/fieldvar_set.go delete mode 100644 database/gdb/internal/fieldvar/fieldvar_slice.go delete mode 100644 database/gdb/internal/fieldvar/fieldvar_struct.go delete mode 100644 database/gdb/internal/fieldvar/fieldvar_time.go diff --git a/contrib/drivers/mysql/mysql_z_unit_feature_hook_test.go b/contrib/drivers/mysql/mysql_z_unit_feature_hook_test.go index 4d91ca8ae04..1330c158c25 100644 --- a/contrib/drivers/mysql/mysql_z_unit_feature_hook_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_feature_hook_test.go @@ -12,6 +12,7 @@ import ( "fmt" "testing" + "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/test/gtest" @@ -29,7 +30,7 @@ func Test_Model_Hook_Select(t *testing.T) { return } for i, record := range result { - record["test"] = gdb.NewValue(100 + record["id"].Int()) + record["test"] = gvar.New(100 + record["id"].Int()) result[i] = record } return diff --git a/contrib/drivers/mysql/mysql_z_unit_issue_test.go b/contrib/drivers/mysql/mysql_z_unit_issue_test.go index 68a23087f6f..cac6c93bef9 100644 --- a/contrib/drivers/mysql/mysql_z_unit_issue_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_issue_test.go @@ -14,6 +14,7 @@ import ( "testing" "time" + "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gtime" @@ -1508,7 +1509,7 @@ func Test_Issue3968(t *testing.T) { } if result != nil { for i, _ := range result { - result[i]["location"] = gdb.NewValue("ny") + result[i]["location"] = gvar.New("ny") } } return diff --git a/contrib/drivers/mysql/mysql_z_unit_model_test.go b/contrib/drivers/mysql/mysql_z_unit_model_test.go index 2d5fd0bd28e..1f78a109108 100644 --- a/contrib/drivers/mysql/mysql_z_unit_model_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_model_test.go @@ -17,6 +17,7 @@ import ( "time" "github.com/gogf/gf/v2/container/garray" + "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/frame/g" @@ -3366,14 +3367,14 @@ func Test_ScanList_NoRecreate_PtrAttribute(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), + "id": gvar.New(1), + "name": gvar.New("john"), + "age": gvar.New(16), }, gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), + "id": gvar.New(2), + "name": gvar.New("smith"), + "age": gvar.New(18), }, } err = r1.ScanList(&s, "One") @@ -3386,12 +3387,12 @@ func Test_ScanList_NoRecreate_PtrAttribute(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "age": gdb.NewValue(20), + "id": gvar.New(1), + "age": gvar.New(20), }, gdb.Record{ - "id": gdb.NewValue(2), - "age": gdb.NewValue(21), + "id": gvar.New(2), + "age": gvar.New(21), }, } err = r2.ScanList(&s, "One", "One", "id:Id") @@ -3422,14 +3423,14 @@ func Test_ScanList_NoRecreate_StructAttribute(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), + "id": gvar.New(1), + "name": gvar.New("john"), + "age": gvar.New(16), }, gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), + "id": gvar.New(2), + "name": gvar.New("smith"), + "age": gvar.New(18), }, } err = r1.ScanList(&s, "One") @@ -3442,12 +3443,12 @@ func Test_ScanList_NoRecreate_StructAttribute(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "age": gdb.NewValue(20), + "id": gvar.New(1), + "age": gvar.New(20), }, gdb.Record{ - "id": gdb.NewValue(2), - "age": gdb.NewValue(21), + "id": gvar.New(2), + "age": gvar.New(21), }, } err = r2.ScanList(&s, "One", "One", "id:Id") @@ -3486,14 +3487,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), + "id": gvar.New(1), + "name": gvar.New("john"), + "age": gvar.New(16), }, gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), + "id": gvar.New(2), + "name": gvar.New("smith"), + "age": gvar.New(18), }, } err = r1.ScanList(&s, "One") @@ -3506,16 +3507,16 @@ func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(30), - "name": gdb.NewValue("john"), + "id": gvar.New(100), + "pid": gvar.New(1), + "age": gvar.New(30), + "name": gvar.New("john"), }, gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(31), - "name": gdb.NewValue("smith"), + "id": gvar.New(200), + "pid": gvar.New(1), + "age": gvar.New(31), + "name": gvar.New("smith"), }, } err = r2.ScanList(&s, "Many", "One", "pid:Id") @@ -3536,14 +3537,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { r3 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(40), + "id": gvar.New(100), + "pid": gvar.New(1), + "age": gvar.New(40), }, gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(41), + "id": gvar.New(200), + "pid": gvar.New(1), + "age": gvar.New(41), }, } err = r3.ScanList(&s, "Many", "One", "pid:Id") @@ -3590,14 +3591,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), + "id": gvar.New(1), + "name": gvar.New("john"), + "age": gvar.New(16), }, gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), + "id": gvar.New(2), + "name": gvar.New("smith"), + "age": gvar.New(18), }, } err = r1.ScanList(&s, "One") @@ -3610,16 +3611,16 @@ func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(30), - "name": gdb.NewValue("john"), + "id": gvar.New(100), + "pid": gvar.New(1), + "age": gvar.New(30), + "name": gvar.New("john"), }, gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(31), - "name": gdb.NewValue("smith"), + "id": gvar.New(200), + "pid": gvar.New(1), + "age": gvar.New(31), + "name": gvar.New("smith"), }, } err = r2.ScanList(&s, "Many", "One", "pid:Id") @@ -3640,14 +3641,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { r3 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(40), + "id": gvar.New(100), + "pid": gvar.New(1), + "age": gvar.New(40), }, gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(41), + "id": gvar.New(200), + "pid": gvar.New(1), + "age": gvar.New(41), }, } err = r3.ScanList(&s, "Many", "One", "pid:Id") @@ -3678,8 +3679,8 @@ func TestResult_Structs1(t *testing.T) { } gtest.C(t, func(t *gtest.T) { r := gdb.Result{ - gdb.Record{"id": gdb.NewValue(nil), "name": gdb.NewValue("john")}, - gdb.Record{"id": gdb.NewValue(1), "name": gdb.NewValue("smith")}, + gdb.Record{"id": gvar.New(nil), "name": gvar.New("john")}, + gdb.Record{"id": gvar.New(1), "name": gvar.New("smith")}, } array := make([]*B, 2) err := r.Structs(&array) diff --git a/database/gdb/gdb.go b/database/gdb/gdb.go index c522b09e631..a1ea177dd24 100644 --- a/database/gdb/gdb.go +++ b/database/gdb/gdb.go @@ -17,8 +17,7 @@ import ( "github.com/gogf/gf/v2/container/garray" "github.com/gogf/gf/v2/container/gmap" "github.com/gogf/gf/v2/container/gtype" - "github.com/gogf/gf/v2/database/gdb/internal/defines" - "github.com/gogf/gf/v2/database/gdb/internal/fieldvar" + "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/os/gcache" @@ -669,7 +668,7 @@ type ( Raw string // Value is the field value type. - Value = *fieldvar.Var + Value = *gvar.Var // Record is the row record of the table. Record map[string]Value @@ -770,30 +769,32 @@ const ( SqlTypeStmtQueryRowContext SqlType = "DB.Statement.QueryRowContext" ) -type LocalType = defines.LocalType +// LocalType is a type that defines the local storage type of a field value. +// It is used to specify how the field value should be processed locally. +type LocalType string const ( - LocalTypeUndefined = defines.LocalTypeUndefined - LocalTypeString = defines.LocalTypeString - LocalTypeTime = defines.LocalTypeTime - LocalTypeDate = defines.LocalTypeDate - LocalTypeDatetime = defines.LocalTypeDatetime - LocalTypeInt = defines.LocalTypeInt - LocalTypeUint = defines.LocalTypeUint - LocalTypeInt64 = defines.LocalTypeInt64 - LocalTypeUint64 = defines.LocalTypeUint64 - LocalTypeIntSlice = defines.LocalTypeIntSlice - LocalTypeInt64Slice = defines.LocalTypeInt64Slice - LocalTypeUint64Slice = defines.LocalTypeUint64Slice - LocalTypeStringSlice = defines.LocalTypeStringSlice - LocalTypeInt64Bytes = defines.LocalTypeInt64Bytes - LocalTypeUint64Bytes = defines.LocalTypeUint64Bytes - LocalTypeFloat32 = defines.LocalTypeFloat32 - LocalTypeFloat64 = defines.LocalTypeFloat64 - LocalTypeBytes = defines.LocalTypeBytes - LocalTypeBool = defines.LocalTypeBool - LocalTypeJson = defines.LocalTypeJson - LocalTypeJsonb = defines.LocalTypeJsonb + LocalTypeUndefined LocalType = "" + LocalTypeString LocalType = "string" + LocalTypeTime LocalType = "time" + LocalTypeDate LocalType = "date" + LocalTypeDatetime LocalType = "datetime" + LocalTypeInt LocalType = "int" + LocalTypeUint LocalType = "uint" + LocalTypeInt64 LocalType = "int64" + LocalTypeUint64 LocalType = "uint64" + LocalTypeIntSlice LocalType = "[]int" + LocalTypeInt64Slice LocalType = "[]int64" + LocalTypeUint64Slice LocalType = "[]uint64" + LocalTypeStringSlice LocalType = "[]string" + LocalTypeInt64Bytes LocalType = "int64-bytes" + LocalTypeUint64Bytes LocalType = "uint64-bytes" + LocalTypeFloat32 LocalType = "float32" + LocalTypeFloat64 LocalType = "float64" + LocalTypeBytes LocalType = "[]byte" + LocalTypeBool LocalType = "bool" + LocalTypeJson LocalType = "json" + LocalTypeJsonb LocalType = "jsonb" ) const ( diff --git a/database/gdb/gdb_core.go b/database/gdb/gdb_core.go index 33174a47209..ef85df24d79 100644 --- a/database/gdb/gdb_core.go +++ b/database/gdb/gdb_core.go @@ -16,6 +16,7 @@ import ( "github.com/gogf/gf/v2/container/gmap" "github.com/gogf/gf/v2/container/gset" + "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/internal/intlog" @@ -239,12 +240,12 @@ func (c *Core) GetScan(ctx context.Context, pointer interface{}, sql string, arg func (c *Core) GetValue(ctx context.Context, sql string, args ...interface{}) (Value, error) { one, err := c.db.GetOne(ctx, sql, args...) if err != nil { - return NewValue(nil), err + return gvar.New(nil), err } for _, v := range one { return v, nil } - return NewValue(nil), nil + return gvar.New(nil), nil } // GetCount queries and returns the count from database. diff --git a/database/gdb/gdb_core_underlying.go b/database/gdb/gdb_core_underlying.go index 512af51a5d1..849ce29cd56 100644 --- a/database/gdb/gdb_core_underlying.go +++ b/database/gdb/gdb_core_underlying.go @@ -13,6 +13,7 @@ import ( "fmt" "reflect" + "github.com/gogf/gf/v2/container/gvar" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/trace" @@ -480,16 +481,11 @@ func (c *Core) RowsToResult(ctx context.Context, rows *sql.Rows) (Result, error) var ( convertedValue interface{} columnType = columnTypes[i] - localType = LocalTypeUndefined ) if convertedValue, err = c.columnValueToLocalValue(ctx, value, columnType); err != nil { return nil, err } - localType, err = c.getLocalTypeForFieldWithCache(ctx, columnType.DatabaseTypeName(), convertedValue) - if err != nil { - return nil, err - } - record[columnTypes[i].Name()] = NewValueWithType(convertedValue, localType) + record[columnTypes[i].Name()] = gvar.New(convertedValue) } } result = append(result, record) diff --git a/database/gdb/gdb_type_result.go b/database/gdb/gdb_type_result.go index 48775759f5d..03e7051d3a9 100644 --- a/database/gdb/gdb_type_result.go +++ b/database/gdb/gdb_type_result.go @@ -10,6 +10,7 @@ import ( "database/sql" "math" + "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/util/gconv" @@ -102,13 +103,11 @@ func (r Result) MapKeyValue(key string) map[string]Value { s string m = make(map[string]Value) tempMap = make(map[string][]interface{}) - localType LocalType hasMultiValues bool ) for _, item := range r { if k, ok := item[key]; ok { s = k.String() - localType = k.LocalType() tempMap[s] = append(tempMap[s], item) if len(tempMap[s]) > 1 { hasMultiValues = true @@ -117,9 +116,9 @@ func (r Result) MapKeyValue(key string) map[string]Value { } for k, v := range tempMap { if hasMultiValues { - m[k] = NewValue(v) + m[k] = gvar.New(v) } else { - m[k] = NewValueWithType(v[0], localType) + m[k] = gvar.New(v[0]) } } return m diff --git a/database/gdb/gdb_type_value.go b/database/gdb/gdb_type_value.go deleted file mode 100644 index 0a8f119b022..00000000000 --- a/database/gdb/gdb_type_value.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package gdb - -import "github.com/gogf/gf/v2/database/gdb/internal/fieldvar" - -// NewValue creates and returns a new Value object. -func NewValue(value any) Value { - return fieldvar.New(value) -} - -// NewValueWithType creates and returns a new Value object with specified local type. -func NewValueWithType(value any, localType LocalType) Value { - return fieldvar.NewWithType(value, localType) -} diff --git a/database/gdb/internal/defines/defines.go b/database/gdb/internal/defines/defines.go deleted file mode 100644 index 090aa55b74d..00000000000 --- a/database/gdb/internal/defines/defines.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -// Package defines provides some common definitions for gdb package. -package defines - -// LocalType is a type that defines the local storage type of a field value. -// It is used to specify how the field value should be processed locally. -type LocalType string - -const ( - LocalTypeUndefined LocalType = "" - LocalTypeString LocalType = "string" - LocalTypeTime LocalType = "time" - LocalTypeDate LocalType = "date" - LocalTypeDatetime LocalType = "datetime" - LocalTypeInt LocalType = "int" - LocalTypeUint LocalType = "uint" - LocalTypeInt64 LocalType = "int64" - LocalTypeUint64 LocalType = "uint64" - LocalTypeIntSlice LocalType = "[]int" - LocalTypeInt64Slice LocalType = "[]int64" - LocalTypeUint64Slice LocalType = "[]uint64" - LocalTypeStringSlice LocalType = "[]string" - LocalTypeInt64Bytes LocalType = "int64-bytes" - LocalTypeUint64Bytes LocalType = "uint64-bytes" - LocalTypeFloat32 LocalType = "float32" - LocalTypeFloat64 LocalType = "float64" - LocalTypeBytes LocalType = "[]byte" - LocalTypeBool LocalType = "bool" - LocalTypeJson LocalType = "json" - LocalTypeJsonb LocalType = "jsonb" -) diff --git a/database/gdb/internal/fieldvar/fieldvar.go b/database/gdb/internal/fieldvar/fieldvar.go deleted file mode 100644 index 41b36997fd9..00000000000 --- a/database/gdb/internal/fieldvar/fieldvar.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -// Package fieldvar provides a variable wrapper for field value in database operations. -// It is used for field value storage and conversion in database operations. -package fieldvar - -import ( - "github.com/gogf/gf/v2/database/gdb/internal/defines" - "github.com/gogf/gf/v2/internal/json" -) - -// Var is a wrapper for any type of value, which is used for field variable. -// Note that, do not embed *gvar.Var into Var but use it as an attribute, as there issue in nil pointer receiver -// when calling methods that is not defined directly on Var. -type Var struct { - value any - localType defines.LocalType -} - -// New creates and returns a new Var object. -func New(value any) *Var { - return &Var{ - value: value, - } -} - -// NewWithType creates and returns a new Var object with specified local type. -func NewWithType(value any, localType defines.LocalType) *Var { - return &Var{ - value: value, - localType: localType, - } -} - -// LocalType returns the local type of the value. -func (v *Var) LocalType() defines.LocalType { - return v.localType -} - -// MarshalJSON implements the interface MarshalJSON for json.Marshal. -func (v *Var) MarshalJSON() ([]byte, error) { - return json.Marshal(v.Val()) -} - -// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. -func (v *Var) UnmarshalJSON(b []byte) error { - var i interface{} - if err := json.UnmarshalUseNumber(b, &i); err != nil { - return err - } - v.Set(i) - return nil -} - -// UnmarshalValue is an interface implement which sets any type of value for Var. -func (v *Var) UnmarshalValue(value interface{}) error { - v.Set(value) - return nil -} diff --git a/database/gdb/internal/fieldvar/fieldvar_basic.go b/database/gdb/internal/fieldvar/fieldvar_basic.go deleted file mode 100644 index a1750204dd3..00000000000 --- a/database/gdb/internal/fieldvar/fieldvar_basic.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package fieldvar - -import ( - "github.com/gogf/gf/v2/util/gconv" -) - -// Val returns the current value of `v`. -func (v *Var) Val() interface{} { - if v == nil { - return nil - } - return v.value -} - -// Interface is alias of Val. -func (v *Var) Interface() interface{} { - return v.Val() -} - -// Bytes converts and returns `v` as []byte. -func (v *Var) Bytes() []byte { - return gconv.Bytes(v.Val()) -} - -// String converts and returns `v` as string. -func (v *Var) String() string { - return gconv.String(v.Val()) -} - -// Bool converts and returns `v` as bool. -func (v *Var) Bool() bool { - return gconv.Bool(v.Val()) -} - -// Int converts and returns `v` as int. -func (v *Var) Int() int { - return gconv.Int(v.Val()) -} - -// Int8 converts and returns `v` as int8. -func (v *Var) Int8() int8 { - return gconv.Int8(v.Val()) -} - -// Int16 converts and returns `v` as int16. -func (v *Var) Int16() int16 { - return gconv.Int16(v.Val()) -} - -// Int32 converts and returns `v` as int32. -func (v *Var) Int32() int32 { - return gconv.Int32(v.Val()) -} - -// Int64 converts and returns `v` as int64. -func (v *Var) Int64() int64 { - return gconv.Int64(v.Val()) -} - -// Uint converts and returns `v` as uint. -func (v *Var) Uint() uint { - return gconv.Uint(v.Val()) -} - -// Uint8 converts and returns `v` as uint8. -func (v *Var) Uint8() uint8 { - return gconv.Uint8(v.Val()) -} - -// Uint16 converts and returns `v` as uint16. -func (v *Var) Uint16() uint16 { - return gconv.Uint16(v.Val()) -} - -// Uint32 converts and returns `v` as uint32. -func (v *Var) Uint32() uint32 { - return gconv.Uint32(v.Val()) -} - -// Uint64 converts and returns `v` as uint64. -func (v *Var) Uint64() uint64 { - return gconv.Uint64(v.Val()) -} - -// Float32 converts and returns `v` as float32. -func (v *Var) Float32() float32 { - return gconv.Float32(v.Val()) -} - -// Float64 converts and returns `v` as float64. -func (v *Var) Float64() float64 { - return gconv.Float64(v.Val()) -} diff --git a/database/gdb/internal/fieldvar/fieldvar_copy.go b/database/gdb/internal/fieldvar/fieldvar_copy.go deleted file mode 100644 index 38bc00da3bc..00000000000 --- a/database/gdb/internal/fieldvar/fieldvar_copy.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package fieldvar - -import ( - "github.com/gogf/gf/v2/internal/deepcopy" - "github.com/gogf/gf/v2/util/gutil" -) - -// Copy does a deep copy of current Var and returns a pointer to this Var. -func (v *Var) Copy() *Var { - return NewWithType(gutil.Copy(v.Val()), v.localType) -} - -// Clone does a shallow copy of current Var and returns a pointer to this Var. -func (v *Var) Clone() *Var { - return NewWithType(v.Val(), v.localType) -} - -// DeepCopy implements interface for deep copy of current type. -func (v *Var) DeepCopy() interface{} { - if v == nil { - return nil - } - return NewWithType(deepcopy.Copy(v.Val()), v.localType) -} diff --git a/database/gdb/internal/fieldvar/fieldvar_is.go b/database/gdb/internal/fieldvar/fieldvar_is.go deleted file mode 100644 index 3c8c17a3a4c..00000000000 --- a/database/gdb/internal/fieldvar/fieldvar_is.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package fieldvar - -import ( - "github.com/gogf/gf/v2/internal/utils" -) - -// IsNil checks whether `v` is nil. -func (v *Var) IsNil() bool { - return utils.IsNil(v.Val()) -} - -// IsEmpty checks whether `v` is empty. -func (v *Var) IsEmpty() bool { - return utils.IsEmpty(v.Val()) -} - -// IsInt checks whether `v` is type of int. -func (v *Var) IsInt() bool { - return utils.IsInt(v.Val()) -} - -// IsUint checks whether `v` is type of uint. -func (v *Var) IsUint() bool { - return utils.IsUint(v.Val()) -} - -// IsFloat checks whether `v` is type of float. -func (v *Var) IsFloat() bool { - return utils.IsFloat(v.Val()) -} - -// IsSlice checks whether `v` is type of slice. -func (v *Var) IsSlice() bool { - return utils.IsSlice(v.Val()) -} - -// IsMap checks whether `v` is type of map. -func (v *Var) IsMap() bool { - return utils.IsMap(v.Val()) -} - -// IsStruct checks whether `v` is type of struct. -func (v *Var) IsStruct() bool { - return utils.IsStruct(v.Val()) -} diff --git a/database/gdb/internal/fieldvar/fieldvar_map.go b/database/gdb/internal/fieldvar/fieldvar_map.go deleted file mode 100644 index ab96919da8a..00000000000 --- a/database/gdb/internal/fieldvar/fieldvar_map.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package fieldvar - -import "github.com/gogf/gf/v2/util/gconv" - -// MapOption specifies the option for map converting. -type MapOption = gconv.MapOption - -// Map converts and returns `v` as map[string]interface{}. -func (v *Var) Map(option ...MapOption) map[string]interface{} { - return gconv.Map(v.Val(), option...) -} - -// MapStrAny is like function Map, but implements the interface of MapStrAny. -func (v *Var) MapStrAny(option ...MapOption) map[string]interface{} { - return v.Map(option...) -} - -// MapStrStr converts and returns `v` as map[string]string. -func (v *Var) MapStrStr(option ...MapOption) map[string]string { - return gconv.MapStrStr(v.Val(), option...) -} - -// MapStrVar converts and returns `v` as map[string]Var. -func (v *Var) MapStrVar(option ...MapOption) map[string]*Var { - m := v.Map(option...) - if len(m) > 0 { - vMap := make(map[string]*Var, len(m)) - for k, v := range m { - vMap[k] = New(v) - } - return vMap - } - return nil -} - -// Maps converts and returns `v` as map[string]string. -// See gconv.Maps. -func (v *Var) Maps(option ...MapOption) []map[string]interface{} { - return gconv.Maps(v.Val(), option...) -} - -// MapToMap converts any map type variable `params` to another map type variable `pointer`. -// See gconv.MapToMap. -func (v *Var) MapToMap(pointer interface{}, mapping ...map[string]string) (err error) { - return gconv.MapToMap(v.Val(), pointer, mapping...) -} - -// MapToMaps converts any map type variable `params` to another map type variable `pointer`. -// See gconv.MapToMaps. -func (v *Var) MapToMaps(pointer interface{}, mapping ...map[string]string) (err error) { - return gconv.MapToMaps(v.Val(), pointer, mapping...) -} - -// MapToMapsDeep converts any map type variable `params` to another map type variable -// `pointer` recursively. -// See gconv.MapToMapsDeep. -func (v *Var) MapToMapsDeep(pointer interface{}, mapping ...map[string]string) (err error) { - return gconv.MapToMaps(v.Val(), pointer, mapping...) -} diff --git a/database/gdb/internal/fieldvar/fieldvar_scan.go b/database/gdb/internal/fieldvar/fieldvar_scan.go deleted file mode 100644 index 3da52ab78d4..00000000000 --- a/database/gdb/internal/fieldvar/fieldvar_scan.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package fieldvar - -import ( - "github.com/gogf/gf/v2/util/gconv" -) - -// Scan automatically checks the type of `pointer` and converts value of Var to `pointer`. -// -// See gconv.Scan. -func (v *Var) Scan(pointer interface{}, mapping ...map[string]string) error { - return gconv.Scan(v.Val(), pointer, mapping...) -} diff --git a/database/gdb/internal/fieldvar/fieldvar_set.go b/database/gdb/internal/fieldvar/fieldvar_set.go deleted file mode 100644 index e31f9a449f5..00000000000 --- a/database/gdb/internal/fieldvar/fieldvar_set.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package fieldvar - -// Set sets `value` to `v`, and returns the old value. -func (v *Var) Set(value interface{}) (old interface{}) { - old = v.value - v.value = value - return -} diff --git a/database/gdb/internal/fieldvar/fieldvar_slice.go b/database/gdb/internal/fieldvar/fieldvar_slice.go deleted file mode 100644 index b418e27141c..00000000000 --- a/database/gdb/internal/fieldvar/fieldvar_slice.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package fieldvar - -import ( - "github.com/gogf/gf/v2/database/gdb/internal/defines" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/util/gconv" -) - -// Ints converts and returns `v` as []int. -func (v *Var) Ints() []int { - return gconv.Ints(v.Val()) -} - -// Int64s converts and returns `v` as []int64. -func (v *Var) Int64s() []int64 { - return gconv.Int64s(v.Val()) -} - -// Uints converts and returns `v` as []uint. -func (v *Var) Uints() []uint { - return gconv.Uints(v.Val()) -} - -// Uint64s converts and returns `v` as []uint64. -func (v *Var) Uint64s() []uint64 { - return gconv.Uint64s(v.Val()) -} - -// Floats is alias of Float64s. -func (v *Var) Floats() []float64 { - return gconv.Floats(v.Val()) -} - -// Float32s converts and returns `v` as []float32. -func (v *Var) Float32s() []float32 { - return gconv.Float32s(v.Val()) -} - -// Float64s converts and returns `v` as []float64. -func (v *Var) Float64s() []float64 { - return gconv.Float64s(v.Val()) -} - -// Strings converts and returns `v` as []string. -func (v *Var) Strings() []string { - if v.localType == defines.LocalTypeJson { - var s []string - _ = json.Unmarshal(v.Bytes(), &s) - return s - } - return gconv.Strings(v.Val()) -} - -// Interfaces converts and returns `v` as []interfaces{}. -func (v *Var) Interfaces() []interface{} { - return gconv.Interfaces(v.Val()) -} - -// Slice is alias of Interfaces. -func (v *Var) Slice() []interface{} { - return v.Interfaces() -} - -// Array is alias of Interfaces. -func (v *Var) Array() []interface{} { - return v.Interfaces() -} - -// Vars converts and returns `v` as []Var. -func (v *Var) Vars() []*Var { - array := gconv.Interfaces(v.Val()) - if len(array) == 0 { - return nil - } - vars := make([]*Var, len(array)) - for k, v := range array { - vars[k] = New(v) - } - return vars -} diff --git a/database/gdb/internal/fieldvar/fieldvar_struct.go b/database/gdb/internal/fieldvar/fieldvar_struct.go deleted file mode 100644 index 930cc474be2..00000000000 --- a/database/gdb/internal/fieldvar/fieldvar_struct.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package fieldvar - -import ( - "github.com/gogf/gf/v2/util/gconv" -) - -// Struct maps value of `v` to `pointer`. -// The parameter `pointer` should be a pointer to a struct instance. -// The parameter `mapping` is used to specify the key-to-attribute mapping rules. -func (v *Var) Struct(pointer interface{}, mapping ...map[string]string) error { - return gconv.Struct(v.Val(), pointer, mapping...) -} - -// Structs converts and returns `v` as given struct slice. -func (v *Var) Structs(pointer interface{}, mapping ...map[string]string) error { - return gconv.Structs(v.Val(), pointer, mapping...) -} diff --git a/database/gdb/internal/fieldvar/fieldvar_time.go b/database/gdb/internal/fieldvar/fieldvar_time.go deleted file mode 100644 index 8939009c8d9..00000000000 --- a/database/gdb/internal/fieldvar/fieldvar_time.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package fieldvar - -import ( - "time" - - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/util/gconv" -) - -// Time converts and returns `v` as time.Time. -// The parameter `format` specifies the format of the time string using gtime, -// Example: Y-m-d H:i:s. -func (v *Var) Time(format ...string) time.Time { - return gconv.Time(v.Val(), format...) -} - -// Duration converts and returns `v` as time.Duration. -// If value of `v` is string, then it uses time.ParseDuration for conversion. -func (v *Var) Duration() time.Duration { - return gconv.Duration(v.Val()) -} - -// GTime converts and returns `v` as *gtime.Time. -// The parameter `format` specifies the format of the time string using gtime, -// Example: Y-m-d H:i:s. -func (v *Var) GTime(format ...string) *gtime.Time { - return gconv.GTime(v.Val(), format...) -} From 896edfb4ddd60d72e474c0fe3e500e71df2b447f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 27 Feb 2025 08:58:15 +0000 Subject: [PATCH 12/48] Apply gci import order changes --- database/gdb/gdb_core_underlying.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/gdb/gdb_core_underlying.go b/database/gdb/gdb_core_underlying.go index 849ce29cd56..a2aaedca389 100644 --- a/database/gdb/gdb_core_underlying.go +++ b/database/gdb/gdb_core_underlying.go @@ -13,11 +13,11 @@ import ( "fmt" "reflect" - "github.com/gogf/gf/v2/container/gvar" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/trace" "github.com/gogf/gf/v2" + "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/internal/intlog" From ce2cf3c04b98bcd43b8f57db2ce9c48ecc5698b0 Mon Sep 17 00:00:00 2001 From: John Guo Date: Fri, 28 Feb 2025 11:54:12 +0800 Subject: [PATCH 13/48] up --- contrib/drivers/mysql/db_utils_test.go | 169 ++++++++++++++++++ .../drivers/mysql/mysql_z_unit_issue_test.go | 26 +++ util/gconv/gconv_basic.go | 23 --- util/gconv/gconv_slice_any.go | 24 ++- util/gconv/gconv_slice_float.go | 67 ++++--- util/gconv/gconv_slice_int.go | 85 ++++++--- util/gconv/gconv_slice_str.go | 32 ++-- util/gconv/gconv_slice_uint.go | 112 ++++++------ 8 files changed, 377 insertions(+), 161 deletions(-) create mode 100644 contrib/drivers/mysql/db_utils_test.go diff --git a/contrib/drivers/mysql/db_utils_test.go b/contrib/drivers/mysql/db_utils_test.go new file mode 100644 index 00000000000..04fa21eb7a5 --- /dev/null +++ b/contrib/drivers/mysql/db_utils_test.go @@ -0,0 +1,169 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package mysql_test + +import ( + "database/sql" + "fmt" + "reflect" + "strings" + "testing" + + "github.com/gogf/gf/v2/test/gtest" +) + +// DBConfig represents database configuration +type DBConfig struct { + Username string + Password string + Host string + DBName string +} + +// QueryAndScan executes a query and scans the results into a slice of struct pointers +// Parameters: +// - query: SQL query string +// - args: Query arguments +// - dest: Pointer to slice of struct pointers where results will be stored +// +// Returns error if any occurs during the process +func QueryAndScan(config DBConfig, query string, args []interface{}, dest interface{}) error { + // Validate input parameters + destValue := reflect.ValueOf(dest) + if destValue.Kind() != reflect.Ptr || destValue.Elem().Kind() != reflect.Slice { + return fmt.Errorf("dest must be a pointer to slice") + } + + // Connect to database + dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?parseTime=true", + config.Username, + config.Password, + config.Host, + config.DBName, + ) + + db, err := sql.Open("mysql", dsn) + if err != nil { + return fmt.Errorf("failed to connect to database: %v", err) + } + defer db.Close() + + // Execute query + rows, err := db.Query(query, args...) + if err != nil { + return fmt.Errorf("failed to execute query: %v", err) + } + defer rows.Close() + + // Get column names + columns, err := rows.Columns() + if err != nil { + return fmt.Errorf("failed to get column names: %v", err) + } + + // Get the type of slice elements + sliceType := destValue.Elem().Type() + elementType := sliceType.Elem() + if elementType.Kind() == reflect.Ptr { + elementType = elementType.Elem() + } + + // Create a map of field names to struct fields + fieldMap := make(map[string]int) + for i := 0; i < elementType.NumField(); i++ { + field := elementType.Field(i) + // Check orm tag first, then json tag, then field name + tagName := field.Tag.Get("orm") + if tagName == "" { + tagName = field.Tag.Get("json") + } + if tagName == "" { + tagName = strings.ToLower(field.Name) + } + fieldMap[tagName] = i + } + + // Prepare slice to store results + sliceValue := destValue.Elem() + + // Scan rows + for rows.Next() { + // Create a new struct instance + newElem := reflect.New(elementType) + + // Create scan destinations that point directly to struct fields + scanDest := make([]interface{}, len(columns)) + for i, colName := range columns { + if fieldIndex, ok := fieldMap[colName]; ok { + field := newElem.Elem().Field(fieldIndex) + if field.CanAddr() { + scanDest[i] = field.Addr().Interface() + } else { + // For fields that can't be addressed, use a temporary variable + var v interface{} + scanDest[i] = &v + } + } else { + // Column doesn't map to any field, use a placeholder + var v interface{} + scanDest[i] = &v + } + } + + // Scan the row directly into struct fields + if err := rows.Scan(scanDest...); err != nil { + return fmt.Errorf("failed to scan row: %v", err) + } + + // Append the new element to the result slice + if sliceType.Elem().Kind() == reflect.Ptr { + sliceValue.Set(reflect.Append(sliceValue, newElem)) + } else { + sliceValue.Set(reflect.Append(sliceValue, newElem.Elem())) + } + } + + // Check for errors from iterating over rows + if err := rows.Err(); err != nil { + return fmt.Errorf("error iterating over rows: %v", err) + } + + return nil +} + +func Test_Issue4086_2(t *testing.T) { + config := DBConfig{ + Username: "root", + Password: "12345678", + Host: "127.0.0.1", + DBName: "test1", + } + gtest.C(t, func(t *gtest.T) { + type ProxyParam struct { + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` + Photos []string `json:"photos" orm:"photos"` + } + + var proxyParamList []*ProxyParam + + err := QueryAndScan(config, "SELECT * FROM issue4086", nil, &proxyParamList) + fmt.Println(err) + t.Assert(proxyParamList, []*ProxyParam{ + { + ProxyId: 1, + RecommendIds: []int64{584, 585}, + Photos: nil, + }, + { + ProxyId: 2, + RecommendIds: []int64{}, + Photos: nil, + }, + }) + }) +} diff --git a/contrib/drivers/mysql/mysql_z_unit_issue_test.go b/contrib/drivers/mysql/mysql_z_unit_issue_test.go index cac6c93bef9..5abc11ab2f4 100644 --- a/contrib/drivers/mysql/mysql_z_unit_issue_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_issue_test.go @@ -1741,6 +1741,32 @@ func Test_Issue4086(t *testing.T) { }, }) }) + + gtest.C(t, func(t *gtest.T) { + type ProxyParam struct { + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` + Photos []int64 `json:"photos" orm:"photos"` + } + + var proxyParamList []*ProxyParam + err := db.Model(table).Ctx(ctx).Scan(&proxyParamList) + t.AssertNil(err) + t.Assert(len(proxyParamList), 2) + t.Assert(proxyParamList, []*ProxyParam{ + { + ProxyId: 1, + RecommendIds: []int64{584, 585}, + Photos: nil, + }, + { + ProxyId: 2, + RecommendIds: []int64{}, + Photos: nil, + }, + }) + }) + gtest.C(t, func(t *gtest.T) { type ProxyParam struct { ProxyId int64 `json:"proxyId" orm:"proxy_id"` diff --git a/util/gconv/gconv_basic.go b/util/gconv/gconv_basic.go index 56a10e07577..5eff3b78b18 100644 --- a/util/gconv/gconv_basic.go +++ b/util/gconv/gconv_basic.go @@ -311,26 +311,3 @@ func doBool(any any) (bool, error) { } } } - -// checkJsonAndUnmarshalUseNumber checks if given `any` is JSON formatted string value and does converting using `json.UnmarshalUseNumber`. -func checkJsonAndUnmarshalUseNumber(any any, target any) bool { - switch r := any.(type) { - case []byte: - if json.Valid(r) { - if err := json.UnmarshalUseNumber(r, &target); err != nil { - return false - } - return true - } - - case string: - anyAsBytes := []byte(r) - if json.Valid(anyAsBytes) { - if err := json.UnmarshalUseNumber(anyAsBytes, &target); err != nil { - return false - } - return true - } - } - return false -} diff --git a/util/gconv/gconv_slice_any.go b/util/gconv/gconv_slice_any.go index 00ecee0c224..f6104433020 100644 --- a/util/gconv/gconv_slice_any.go +++ b/util/gconv/gconv_slice_any.go @@ -65,13 +65,22 @@ func Interfaces(any interface{}) []interface{} { } case []uint8: if json.Valid(value) { - _ = json.UnmarshalUseNumber(value, &array) - } else { - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v + if _ = json.UnmarshalUseNumber(value, &array); array != nil { + return array } } + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array + } + } + case []uint16: array = make([]interface{}, len(value)) for k, v := range value { @@ -108,10 +117,7 @@ func Interfaces(any interface{}) []interface{} { if v, ok := any.(localinterface.IInterfaces); ok { return v.Interfaces() } - // JSON format string value converting. - if checkJsonAndUnmarshalUseNumber(any, &array) { - return array - } + // Not a common type, it then uses reflection for conversion. originValueAndKind := reflection.OriginValueAndKind(any) switch originValueAndKind.OriginKind { diff --git a/util/gconv/gconv_slice_float.go b/util/gconv/gconv_slice_float.go index bca5af6b04b..f497fa92bb1 100644 --- a/util/gconv/gconv_slice_float.go +++ b/util/gconv/gconv_slice_float.go @@ -11,6 +11,7 @@ import ( "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" + "github.com/gogf/gf/v2/internal/utils" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) @@ -43,11 +44,6 @@ func Float32s(any interface{}) []float32 { array []float32 = nil ) switch value := any.(type) { - case string: - if value == "" { - return []float32{} - } - return []float32{Float32(value)} case []string: array = make([]float32, len(value)) for k, v := range value { @@ -84,13 +80,27 @@ func Float32s(any interface{}) []float32 { } case []uint8: if json.Valid(value) { - _ = json.UnmarshalUseNumber(value, &array) - } else { - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) + if _ = json.UnmarshalUseNumber(value, &array); array != nil { + return array } } + array = make([]float32, len(value)) + for k, v := range value { + array[k] = Float32(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array + } + } + if value == "" { + return []float32{} + } + if utils.IsNumeric(value) { + return []float32{Float32(value)} + } case []uint16: array = make([]float32, len(value)) for k, v := range value { @@ -133,10 +143,6 @@ func Float32s(any interface{}) []float32 { if v, ok := any.(localinterface.IInterfaces); ok { return Float32s(v.Interfaces()) } - // JSON format string value converting. - if checkJsonAndUnmarshalUseNumber(any, &array) { - return array - } // Not a common type, it then uses reflection for conversion. originValueAndKind := reflection.OriginValueAndKind(any) switch originValueAndKind.OriginKind { @@ -167,11 +173,6 @@ func Float64s(any interface{}) []float64 { array []float64 = nil ) switch value := any.(type) { - case string: - if value == "" { - return []float64{} - } - return []float64{Float64(value)} case []string: array = make([]float64, len(value)) for k, v := range value { @@ -208,13 +209,27 @@ func Float64s(any interface{}) []float64 { } case []uint8: if json.Valid(value) { - _ = json.UnmarshalUseNumber(value, &array) - } else { - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) + if _ = json.UnmarshalUseNumber(value, &array); array != nil { + return array } } + array = make([]float64, len(value)) + for k, v := range value { + array[k] = Float64(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array + } + } + if value == "" { + return []float64{} + } + if utils.IsNumeric(value) { + return []float64{Float64(value)} + } case []uint16: array = make([]float64, len(value)) for k, v := range value { @@ -257,10 +272,6 @@ func Float64s(any interface{}) []float64 { if v, ok := any.(localinterface.IInterfaces); ok { return Floats(v.Interfaces()) } - // JSON format string value converting. - if checkJsonAndUnmarshalUseNumber(any, &array) { - return array - } // Not a common type, it then uses reflection for conversion. originValueAndKind := reflection.OriginValueAndKind(any) switch originValueAndKind.OriginKind { diff --git a/util/gconv/gconv_slice_int.go b/util/gconv/gconv_slice_int.go index 929acfa147e..dc8ef41f40a 100644 --- a/util/gconv/gconv_slice_int.go +++ b/util/gconv/gconv_slice_int.go @@ -11,6 +11,7 @@ import ( "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" + "github.com/gogf/gf/v2/internal/utils" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) @@ -72,13 +73,27 @@ func Ints(any interface{}) []int { } case []uint8: if json.Valid(value) { - _ = json.UnmarshalUseNumber(value, &array) - } else { - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) + if _ = json.UnmarshalUseNumber(value, &array); array != nil { + return array } } + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array + } + } + if value == "" { + return []int{} + } + if utils.IsNumeric(value) { + return []int{Int(value)} + } case []uint16: array = make([]int, len(value)) for k, v := range value { @@ -133,10 +148,6 @@ func Ints(any interface{}) []int { if v, ok := any.(localinterface.IInterfaces); ok { return Ints(v.Interfaces()) } - // JSON format string value converting. - if checkJsonAndUnmarshalUseNumber(any, &array) { - return array - } // Not a common type, it then uses reflection for conversion. originValueAndKind := reflection.OriginValueAndKind(any) switch originValueAndKind.OriginKind { @@ -201,13 +212,27 @@ func Int32s(any interface{}) []int32 { } case []uint8: if json.Valid(value) { - _ = json.UnmarshalUseNumber(value, &array) - } else { - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) + if _ = json.UnmarshalUseNumber(value, &array); array != nil { + return array + } + } + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array } } + if value == "" { + return []int32{} + } + if utils.IsNumeric(value) { + return []int32{Int32(value)} + } case []uint16: array = make([]int32, len(value)) for k, v := range value { @@ -262,10 +287,6 @@ func Int32s(any interface{}) []int32 { if v, ok := any.(localinterface.IInterfaces); ok { return Int32s(v.Interfaces()) } - // JSON format string value converting. - if checkJsonAndUnmarshalUseNumber(any, &array) { - return array - } // Not a common type, it then uses reflection for conversion. originValueAndKind := reflection.OriginValueAndKind(any) switch originValueAndKind.OriginKind { @@ -330,13 +351,27 @@ func Int64s(any interface{}) []int64 { } case []uint8: if json.Valid(value) { - _ = json.UnmarshalUseNumber(value, &array) - } else { - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) + if _ = json.UnmarshalUseNumber(value, &array); array != nil { + return array + } + } + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array } } + if value == "" { + return []int64{} + } + if utils.IsNumeric(value) { + return []int64{Int64(value)} + } case []uint16: array = make([]int64, len(value)) for k, v := range value { @@ -391,10 +426,6 @@ func Int64s(any interface{}) []int64 { if v, ok := any.(localinterface.IInterfaces); ok { return Int64s(v.Interfaces()) } - // JSON format string value converting. - if checkJsonAndUnmarshalUseNumber(any, &array) { - return array - } // Not a common type, it then uses reflection for conversion. originValueAndKind := reflection.OriginValueAndKind(any) switch originValueAndKind.OriginKind { diff --git a/util/gconv/gconv_slice_str.go b/util/gconv/gconv_slice_str.go index 405e72ca522..2640be0d021 100644 --- a/util/gconv/gconv_slice_str.go +++ b/util/gconv/gconv_slice_str.go @@ -60,28 +60,26 @@ func Strings(any interface{}) []string { } case []uint8: if json.Valid(value) { - _ = json.UnmarshalUseNumber(value, &array) - } - if array == nil { - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) + if _ = json.UnmarshalUseNumber(value, &array); array != nil { + return array } - return array } + array = make([]string, len(value)) + for k, v := range value { + array[k] = String(v) + } + return array case string: byteValue := []byte(value) if json.Valid(byteValue) { - _ = json.UnmarshalUseNumber(byteValue, &array) - } - if array == nil { - if value == "" { - return []string{} + if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array } - // Prevent strings from being null - // See Issue 3465 for details - return []string{value} } + if value == "" { + return []string{} + } + return []string{value} case []uint16: array = make([]string, len(value)) for k, v := range value { @@ -134,10 +132,6 @@ func Strings(any interface{}) []string { if v, ok := any.(localinterface.IInterfaces); ok { return Strings(v.Interfaces()) } - // JSON format string value converting. - if checkJsonAndUnmarshalUseNumber(any, &array) { - return array - } // Not a common type, it then uses reflection for conversion. originValueAndKind := reflection.OriginValueAndKind(any) switch originValueAndKind.OriginKind { diff --git a/util/gconv/gconv_slice_uint.go b/util/gconv/gconv_slice_uint.go index 8ab15dbf7fa..1b5160e4d71 100644 --- a/util/gconv/gconv_slice_uint.go +++ b/util/gconv/gconv_slice_uint.go @@ -8,7 +8,6 @@ package gconv import ( "reflect" - "strings" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" @@ -36,20 +35,10 @@ func Uints(any interface{}) []uint { if any == nil { return nil } - var ( array []uint = nil ) switch value := any.(type) { - case string: - value = strings.TrimSpace(value) - if value == "" { - return []uint{} - } - if utils.IsNumeric(value) { - return []uint{Uint(value)} - } - case []string: array = make([]uint, len(value)) for k, v := range value { @@ -79,13 +68,27 @@ func Uints(any interface{}) []uint { array = value case []uint8: if json.Valid(value) { - _ = json.UnmarshalUseNumber(value, &array) - } else { - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) + if _ = json.UnmarshalUseNumber(value, &array); array != nil { + return array } } + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array + } + } + if value == "" { + return []uint{} + } + if utils.IsNumeric(value) { + return []uint{Uint(value)} + } case []uint16: array = make([]uint, len(value)) for k, v := range value { @@ -143,10 +146,6 @@ func Uints(any interface{}) []uint { if v, ok := any.(localinterface.IInterfaces); ok { return Uints(v.Interfaces()) } - // JSON format string value converting. - if checkJsonAndUnmarshalUseNumber(any, &array) { - return array - } // Not a common type, it then uses reflection for conversion. originValueAndKind := reflection.OriginValueAndKind(any) switch originValueAndKind.OriginKind { @@ -177,14 +176,6 @@ func Uint32s(any interface{}) []uint32 { array []uint32 = nil ) switch value := any.(type) { - case string: - value = strings.TrimSpace(value) - if value == "" { - return []uint32{} - } - if utils.IsNumeric(value) { - return []uint32{Uint32(value)} - } case []string: array = make([]uint32, len(value)) for k, v := range value { @@ -217,13 +208,27 @@ func Uint32s(any interface{}) []uint32 { } case []uint8: if json.Valid(value) { - _ = json.UnmarshalUseNumber(value, &array) - } else { - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) + if _ = json.UnmarshalUseNumber(value, &array); array != nil { + return array } } + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array + } + } + if value == "" { + return []uint32{} + } + if utils.IsNumeric(value) { + return []uint32{Uint32(value)} + } case []uint16: array = make([]uint32, len(value)) for k, v := range value { @@ -277,10 +282,6 @@ func Uint32s(any interface{}) []uint32 { if v, ok := any.(localinterface.IInterfaces); ok { return Uint32s(v.Interfaces()) } - // JSON format string value converting. - if checkJsonAndUnmarshalUseNumber(any, &array) { - return array - } // Not a common type, it then uses reflection for conversion. originValueAndKind := reflection.OriginValueAndKind(any) switch originValueAndKind.OriginKind { @@ -311,15 +312,6 @@ func Uint64s(any interface{}) []uint64 { array []uint64 = nil ) switch value := any.(type) { - case string: - value = strings.TrimSpace(value) - if value == "" { - return []uint64{} - } - if utils.IsNumeric(value) { - return []uint64{Uint64(value)} - } - case []string: array = make([]uint64, len(value)) for k, v := range value { @@ -352,13 +344,27 @@ func Uint64s(any interface{}) []uint64 { } case []uint8: if json.Valid(value) { - _ = json.UnmarshalUseNumber(value, &array) - } else { - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) + if _ = json.UnmarshalUseNumber(value, &array); array != nil { + return array + } + } + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array } } + if value == "" { + return []uint64{} + } + if utils.IsNumeric(value) { + return []uint64{Uint64(value)} + } case []uint16: array = make([]uint64, len(value)) for k, v := range value { @@ -411,10 +417,6 @@ func Uint64s(any interface{}) []uint64 { if v, ok := any.(localinterface.IInterfaces); ok { return Uint64s(v.Interfaces()) } - // JSON format string value converting. - if checkJsonAndUnmarshalUseNumber(any, &array) { - return array - } // Not a common type, it then uses reflection for conversion. originValueAndKind := reflection.OriginValueAndKind(any) switch originValueAndKind.OriginKind { From e31163038e6a237aa3ff3782562e35f3c99c655e Mon Sep 17 00:00:00 2001 From: John Guo Date: Fri, 28 Feb 2025 12:17:24 +0800 Subject: [PATCH 14/48] up --- contrib/drivers/mysql/db_utils_test.go | 169 ------------------ .../drivers/mysql/mysql_z_unit_issue_test.go | 37 +++- util/gconv/gconv_basic.go | 7 +- util/gconv/gconv_float.go | 5 +- util/gconv/gconv_int.go | 3 +- util/gconv/gconv_slice_any.go | 11 +- util/gconv/gconv_slice_float.go | 19 +- util/gconv/gconv_slice_int.go | 27 ++- util/gconv/gconv_slice_str.go | 11 +- util/gconv/gconv_slice_uint.go | 27 ++- util/gconv/gconv_time.go | 3 +- util/gconv/gconv_uint.go | 11 +- 12 files changed, 133 insertions(+), 197 deletions(-) delete mode 100644 contrib/drivers/mysql/db_utils_test.go diff --git a/contrib/drivers/mysql/db_utils_test.go b/contrib/drivers/mysql/db_utils_test.go deleted file mode 100644 index 04fa21eb7a5..00000000000 --- a/contrib/drivers/mysql/db_utils_test.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package mysql_test - -import ( - "database/sql" - "fmt" - "reflect" - "strings" - "testing" - - "github.com/gogf/gf/v2/test/gtest" -) - -// DBConfig represents database configuration -type DBConfig struct { - Username string - Password string - Host string - DBName string -} - -// QueryAndScan executes a query and scans the results into a slice of struct pointers -// Parameters: -// - query: SQL query string -// - args: Query arguments -// - dest: Pointer to slice of struct pointers where results will be stored -// -// Returns error if any occurs during the process -func QueryAndScan(config DBConfig, query string, args []interface{}, dest interface{}) error { - // Validate input parameters - destValue := reflect.ValueOf(dest) - if destValue.Kind() != reflect.Ptr || destValue.Elem().Kind() != reflect.Slice { - return fmt.Errorf("dest must be a pointer to slice") - } - - // Connect to database - dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?parseTime=true", - config.Username, - config.Password, - config.Host, - config.DBName, - ) - - db, err := sql.Open("mysql", dsn) - if err != nil { - return fmt.Errorf("failed to connect to database: %v", err) - } - defer db.Close() - - // Execute query - rows, err := db.Query(query, args...) - if err != nil { - return fmt.Errorf("failed to execute query: %v", err) - } - defer rows.Close() - - // Get column names - columns, err := rows.Columns() - if err != nil { - return fmt.Errorf("failed to get column names: %v", err) - } - - // Get the type of slice elements - sliceType := destValue.Elem().Type() - elementType := sliceType.Elem() - if elementType.Kind() == reflect.Ptr { - elementType = elementType.Elem() - } - - // Create a map of field names to struct fields - fieldMap := make(map[string]int) - for i := 0; i < elementType.NumField(); i++ { - field := elementType.Field(i) - // Check orm tag first, then json tag, then field name - tagName := field.Tag.Get("orm") - if tagName == "" { - tagName = field.Tag.Get("json") - } - if tagName == "" { - tagName = strings.ToLower(field.Name) - } - fieldMap[tagName] = i - } - - // Prepare slice to store results - sliceValue := destValue.Elem() - - // Scan rows - for rows.Next() { - // Create a new struct instance - newElem := reflect.New(elementType) - - // Create scan destinations that point directly to struct fields - scanDest := make([]interface{}, len(columns)) - for i, colName := range columns { - if fieldIndex, ok := fieldMap[colName]; ok { - field := newElem.Elem().Field(fieldIndex) - if field.CanAddr() { - scanDest[i] = field.Addr().Interface() - } else { - // For fields that can't be addressed, use a temporary variable - var v interface{} - scanDest[i] = &v - } - } else { - // Column doesn't map to any field, use a placeholder - var v interface{} - scanDest[i] = &v - } - } - - // Scan the row directly into struct fields - if err := rows.Scan(scanDest...); err != nil { - return fmt.Errorf("failed to scan row: %v", err) - } - - // Append the new element to the result slice - if sliceType.Elem().Kind() == reflect.Ptr { - sliceValue.Set(reflect.Append(sliceValue, newElem)) - } else { - sliceValue.Set(reflect.Append(sliceValue, newElem.Elem())) - } - } - - // Check for errors from iterating over rows - if err := rows.Err(); err != nil { - return fmt.Errorf("error iterating over rows: %v", err) - } - - return nil -} - -func Test_Issue4086_2(t *testing.T) { - config := DBConfig{ - Username: "root", - Password: "12345678", - Host: "127.0.0.1", - DBName: "test1", - } - gtest.C(t, func(t *gtest.T) { - type ProxyParam struct { - ProxyId int64 `json:"proxyId" orm:"proxy_id"` - RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` - Photos []string `json:"photos" orm:"photos"` - } - - var proxyParamList []*ProxyParam - - err := QueryAndScan(config, "SELECT * FROM issue4086", nil, &proxyParamList) - fmt.Println(err) - t.Assert(proxyParamList, []*ProxyParam{ - { - ProxyId: 1, - RecommendIds: []int64{584, 585}, - Photos: nil, - }, - { - ProxyId: 2, - RecommendIds: []int64{}, - Photos: nil, - }, - }) - }) -} diff --git a/contrib/drivers/mysql/mysql_z_unit_issue_test.go b/contrib/drivers/mysql/mysql_z_unit_issue_test.go index 5abc11ab2f4..7f7f0a85401 100644 --- a/contrib/drivers/mysql/mysql_z_unit_issue_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_issue_test.go @@ -1719,9 +1719,9 @@ func Test_Issue4086(t *testing.T) { gtest.C(t, func(t *gtest.T) { type ProxyParam struct { - ProxyId int64 `json:"proxyId" orm:"proxy_id"` - RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` - Photos []string `json:"photos" orm:"photos"` + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` + Photos []int64 `json:"photos" orm:"photos"` } var proxyParamList []*ProxyParam @@ -1744,9 +1744,34 @@ func Test_Issue4086(t *testing.T) { gtest.C(t, func(t *gtest.T) { type ProxyParam struct { - ProxyId int64 `json:"proxyId" orm:"proxy_id"` - RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` - Photos []int64 `json:"photos" orm:"photos"` + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` + Photos []float32 `json:"photos" orm:"photos"` + } + + var proxyParamList []*ProxyParam + err := db.Model(table).Ctx(ctx).Scan(&proxyParamList) + t.AssertNil(err) + t.Assert(len(proxyParamList), 2) + t.Assert(proxyParamList, []*ProxyParam{ + { + ProxyId: 1, + RecommendIds: []int64{584, 585}, + Photos: nil, + }, + { + ProxyId: 2, + RecommendIds: []int64{}, + Photos: nil, + }, + }) + }) + + gtest.C(t, func(t *gtest.T) { + type ProxyParam struct { + ProxyId int64 `json:"proxyId" orm:"proxy_id"` + RecommendIds []int64 `json:"recommendIds" orm:"recommend_ids"` + Photos []string `json:"photos" orm:"photos"` } var proxyParamList []*ProxyParam diff --git a/util/gconv/gconv_basic.go b/util/gconv/gconv_basic.go index 5eff3b78b18..03449231e3d 100644 --- a/util/gconv/gconv_basic.go +++ b/util/gconv/gconv_basic.go @@ -17,6 +17,7 @@ import ( "github.com/gogf/gf/v2/encoding/gbinary" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" "github.com/gogf/gf/v2/os/gtime" @@ -43,7 +44,7 @@ func Bytes(any any) []byte { } func doBytes(any any) ([]byte, error) { - if any == nil { + if empty.IsNil(any) { return nil, nil } switch value := any.(type) { @@ -133,7 +134,7 @@ func String(any any) string { } func doString(any any) (string, error) { - if any == nil { + if empty.IsNil(any) { return "", nil } switch value := any.(type) { @@ -254,7 +255,7 @@ func Bool(any any) bool { } func doBool(any any) (bool, error) { - if any == nil { + if empty.IsNil(any) { return false, nil } switch value := any.(type) { diff --git a/util/gconv/gconv_float.go b/util/gconv/gconv_float.go index 2f7204a5cf9..fac2d1c9871 100644 --- a/util/gconv/gconv_float.go +++ b/util/gconv/gconv_float.go @@ -13,6 +13,7 @@ import ( "github.com/gogf/gf/v2/encoding/gbinary" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) @@ -23,7 +24,7 @@ func Float32(any any) float32 { } func doFloat32(any any) (float32, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } switch value := any.(type) { @@ -86,7 +87,7 @@ func Float64(any any) float64 { } func doFloat64(any any) (float64, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } switch value := any.(type) { diff --git a/util/gconv/gconv_int.go b/util/gconv/gconv_int.go index 7e1e6a129dd..a3f833ae690 100644 --- a/util/gconv/gconv_int.go +++ b/util/gconv/gconv_int.go @@ -14,6 +14,7 @@ import ( "github.com/gogf/gf/v2/encoding/gbinary" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) @@ -92,7 +93,7 @@ func Int64(any any) int64 { } func doInt64(any any) (int64, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } if v, ok := any.(int64); ok { diff --git a/util/gconv/gconv_slice_any.go b/util/gconv/gconv_slice_any.go index f6104433020..12de2ae3015 100644 --- a/util/gconv/gconv_slice_any.go +++ b/util/gconv/gconv_slice_any.go @@ -7,8 +7,11 @@ package gconv import ( + "bytes" "reflect" + "strings" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" @@ -21,7 +24,7 @@ func SliceAny(any interface{}) []interface{} { // Interfaces converts `any` to []interface{}. func Interfaces(any interface{}) []interface{} { - if any == nil { + if empty.IsNil(any) { return nil } var array []interface{} @@ -68,6 +71,9 @@ func Interfaces(any interface{}) []interface{} { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]interface{}, len(value)) for k, v := range value { @@ -79,6 +85,9 @@ func Interfaces(any interface{}) []interface{} { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } case []uint16: diff --git a/util/gconv/gconv_slice_float.go b/util/gconv/gconv_slice_float.go index f497fa92bb1..9d23d700249 100644 --- a/util/gconv/gconv_slice_float.go +++ b/util/gconv/gconv_slice_float.go @@ -7,8 +7,11 @@ package gconv import ( + "bytes" "reflect" + "strings" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" "github.com/gogf/gf/v2/internal/utils" @@ -37,7 +40,7 @@ func Floats(any interface{}) []float64 { // Float32s converts `any` to []float32. func Float32s(any interface{}) []float32 { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -83,6 +86,9 @@ func Float32s(any interface{}) []float32 { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]float32, len(value)) for k, v := range value { @@ -94,6 +100,9 @@ func Float32s(any interface{}) []float32 { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []float32{} @@ -166,7 +175,7 @@ func Float32s(any interface{}) []float32 { // Float64s converts `any` to []float64. func Float64s(any interface{}) []float64 { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -212,6 +221,9 @@ func Float64s(any interface{}) []float64 { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]float64, len(value)) for k, v := range value { @@ -223,6 +235,9 @@ func Float64s(any interface{}) []float64 { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []float64{} diff --git a/util/gconv/gconv_slice_int.go b/util/gconv/gconv_slice_int.go index dc8ef41f40a..4b2931e08bf 100644 --- a/util/gconv/gconv_slice_int.go +++ b/util/gconv/gconv_slice_int.go @@ -7,8 +7,11 @@ package gconv import ( + "bytes" "reflect" + "strings" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" "github.com/gogf/gf/v2/internal/utils" @@ -32,7 +35,7 @@ func SliceInt64(any interface{}) []int64 { // Ints converts `any` to []int. func Ints(any interface{}) []int { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -76,6 +79,9 @@ func Ints(any interface{}) []int { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]int, len(value)) for k, v := range value { @@ -87,6 +93,9 @@ func Ints(any interface{}) []int { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []int{} @@ -171,7 +180,7 @@ func Ints(any interface{}) []int { // Int32s converts `any` to []int32. func Int32s(any interface{}) []int32 { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -215,6 +224,9 @@ func Int32s(any interface{}) []int32 { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]int32, len(value)) for k, v := range value { @@ -226,6 +238,9 @@ func Int32s(any interface{}) []int32 { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []int32{} @@ -310,7 +325,7 @@ func Int32s(any interface{}) []int32 { // Int64s converts `any` to []int64. func Int64s(any interface{}) []int64 { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -354,6 +369,9 @@ func Int64s(any interface{}) []int64 { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]int64, len(value)) for k, v := range value { @@ -365,6 +383,9 @@ func Int64s(any interface{}) []int64 { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []int64{} diff --git a/util/gconv/gconv_slice_str.go b/util/gconv/gconv_slice_str.go index 2640be0d021..ff2157b3c7a 100644 --- a/util/gconv/gconv_slice_str.go +++ b/util/gconv/gconv_slice_str.go @@ -7,8 +7,11 @@ package gconv import ( + "bytes" "reflect" + "strings" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" @@ -21,7 +24,7 @@ func SliceStr(any interface{}) []string { // Strings converts `any` to []string. func Strings(any interface{}) []string { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -63,6 +66,9 @@ func Strings(any interface{}) []string { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]string, len(value)) for k, v := range value { @@ -75,6 +81,9 @@ func Strings(any interface{}) []string { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []string{} diff --git a/util/gconv/gconv_slice_uint.go b/util/gconv/gconv_slice_uint.go index 1b5160e4d71..00ae9e491b2 100644 --- a/util/gconv/gconv_slice_uint.go +++ b/util/gconv/gconv_slice_uint.go @@ -7,8 +7,11 @@ package gconv import ( + "bytes" "reflect" + "strings" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/internal/reflection" "github.com/gogf/gf/v2/internal/utils" @@ -32,7 +35,7 @@ func SliceUint64(any interface{}) []uint64 { // Uints converts `any` to []uint. func Uints(any interface{}) []uint { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -71,6 +74,9 @@ func Uints(any interface{}) []uint { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]uint, len(value)) for k, v := range value { @@ -82,6 +88,9 @@ func Uints(any interface{}) []uint { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []uint{} @@ -169,7 +178,7 @@ func Uints(any interface{}) []uint { // Uint32s converts `any` to []uint32. func Uint32s(any interface{}) []uint32 { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -211,6 +220,9 @@ func Uint32s(any interface{}) []uint32 { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]uint32, len(value)) for k, v := range value { @@ -222,6 +234,9 @@ func Uint32s(any interface{}) []uint32 { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []uint32{} @@ -305,7 +320,7 @@ func Uint32s(any interface{}) []uint32 { // Uint64s converts `any` to []uint64. func Uint64s(any interface{}) []uint64 { - if any == nil { + if empty.IsNil(any) { return nil } var ( @@ -347,6 +362,9 @@ func Uint64s(any interface{}) []uint64 { if _ = json.UnmarshalUseNumber(value, &array); array != nil { return array } + if bytes.EqualFold([]byte("null"), value) { + return nil + } } array = make([]uint64, len(value)) for k, v := range value { @@ -358,6 +376,9 @@ func Uint64s(any interface{}) []uint64 { if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { return array } + if strings.EqualFold(value, "null") { + return nil + } } if value == "" { return []uint64{} diff --git a/util/gconv/gconv_time.go b/util/gconv/gconv_time.go index d42a0639518..202b5b557a6 100644 --- a/util/gconv/gconv_time.go +++ b/util/gconv/gconv_time.go @@ -9,6 +9,7 @@ package gconv import ( "time" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/internal/utils" "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" @@ -50,7 +51,7 @@ func Duration(any interface{}) time.Duration { // If no `format` given, it converts `any` using gtime.NewFromTimeStamp if `any` is numeric, // or using gtime.StrToTime if `any` is string. func GTime(any interface{}, format ...string) *gtime.Time { - if any == nil { + if empty.IsNil(any) { return nil } if v, ok := any.(localinterface.IGTime); ok { diff --git a/util/gconv/gconv_uint.go b/util/gconv/gconv_uint.go index 367a71a79a2..75e876f51b7 100644 --- a/util/gconv/gconv_uint.go +++ b/util/gconv/gconv_uint.go @@ -14,6 +14,7 @@ import ( "github.com/gogf/gf/v2/encoding/gbinary" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/empty" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) @@ -24,7 +25,7 @@ func Uint(any any) uint { } func doUint(any any) (uint, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } if v, ok := any.(uint); ok { @@ -41,7 +42,7 @@ func Uint8(any any) uint8 { } func doUint8(any any) (uint8, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } if v, ok := any.(uint8); ok { @@ -58,7 +59,7 @@ func Uint16(any any) uint16 { } func doUint16(any any) (uint16, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } if v, ok := any.(uint16); ok { @@ -75,7 +76,7 @@ func Uint32(any any) uint32 { } func doUint32(any any) (uint32, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } if v, ok := any.(uint32); ok { @@ -92,7 +93,7 @@ func Uint64(any any) uint64 { } func doUint64(any any) (uint64, error) { - if any == nil { + if empty.IsNil(any) { return 0, nil } if v, ok := any.(uint64); ok { From 0757ab7f4665c188a28223e59f7f92c5f9707f18 Mon Sep 17 00:00:00 2001 From: John Guo Date: Fri, 28 Feb 2025 12:22:00 +0800 Subject: [PATCH 15/48] up --- net/ghttp/ghttp_z_unit_feature_router_strict_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ghttp/ghttp_z_unit_feature_router_strict_test.go b/net/ghttp/ghttp_z_unit_feature_router_strict_test.go index ef4fa12112b..1944c5fb474 100644 --- a/net/ghttp/ghttp_z_unit_feature_router_strict_test.go +++ b/net/ghttp/ghttp_z_unit_feature_router_strict_test.go @@ -505,7 +505,6 @@ func (t *testNullStringIssue3465) Test(ctx context.Context, req *testNullStringI // https://github.com/gogf/gf/issues/3465 func Test_NullString_Issue3465(t *testing.T) { - s := g.Server(guid.S()) s.Use(ghttp.MiddlewareHandlerResponse) s.Group("/", func(group *ghttp.RouterGroup) { @@ -524,7 +523,7 @@ func Test_NullString_Issue3465(t *testing.T) { "name": "null", } - expect1 := `{"code":0,"message":"OK","data":{"name":["null"]}}` + expect1 := `{"code":0,"message":"OK","data":{"name":null}}` t.Assert(client.GetContent(ctx, "/test", data1), expect1) data2 := map[string]any{ From dd8817f8b1cf59aafc27f59c00dcfd2ce189d7eb Mon Sep 17 00:00:00 2001 From: John Guo Date: Fri, 28 Feb 2025 12:24:28 +0800 Subject: [PATCH 16/48] up --- contrib/drivers/mysql/mysql_z_unit_model_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/drivers/mysql/mysql_z_unit_model_test.go b/contrib/drivers/mysql/mysql_z_unit_model_test.go index 1f78a109108..e4190e66312 100644 --- a/contrib/drivers/mysql/mysql_z_unit_model_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_model_test.go @@ -758,7 +758,7 @@ func Test_Model_Value_WithCache(t *testing.T) { t.AssertNil(err) t.Assert(value.Int(), 0) }) - return + gtest.C(t, func(t *gtest.T) { result, err := db.Model(table).Data(g.MapStrAny{ "id": 1, From dae543c1403f83952f7b515e77c264dcfdbe4e31 Mon Sep 17 00:00:00 2001 From: John Guo Date: Fri, 28 Feb 2025 12:26:47 +0800 Subject: [PATCH 17/48] up --- .../sqlite/sqlite_z_unit_model_test.go | 125 +++++++++--------- .../sqlitecgo/sqlitecgo_z_unit_model_test.go | 125 +++++++++--------- 2 files changed, 126 insertions(+), 124 deletions(-) diff --git a/contrib/drivers/sqlite/sqlite_z_unit_model_test.go b/contrib/drivers/sqlite/sqlite_z_unit_model_test.go index 6b657206ebe..03e8465c7fc 100644 --- a/contrib/drivers/sqlite/sqlite_z_unit_model_test.go +++ b/contrib/drivers/sqlite/sqlite_z_unit_model_test.go @@ -17,6 +17,7 @@ import ( "github.com/gogf/gf/v2/container/garray" "github.com/gogf/gf/v2/container/gmap" + "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/errors/gcode" @@ -3988,14 +3989,14 @@ func Test_ScanList_NoRecreate_PtrAttribute(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), + "id": gvar.New(1), + "name": gvar.New("john"), + "age": gvar.New(16), }, gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), + "id": gvar.New(2), + "name": gvar.New("smith"), + "age": gvar.New(18), }, } err = r1.ScanList(&s, "One") @@ -4008,12 +4009,12 @@ func Test_ScanList_NoRecreate_PtrAttribute(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "age": gdb.NewValue(20), + "id": gvar.New(1), + "age": gvar.New(20), }, gdb.Record{ - "id": gdb.NewValue(2), - "age": gdb.NewValue(21), + "id": gvar.New(2), + "age": gvar.New(21), }, } err = r2.ScanList(&s, "One", "One", "id:Id") @@ -4044,14 +4045,14 @@ func Test_ScanList_NoRecreate_StructAttribute(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), + "id": gvar.New(1), + "name": gvar.New("john"), + "age": gvar.New(16), }, gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), + "id": gvar.New(2), + "name": gvar.New("smith"), + "age": gvar.New(18), }, } err = r1.ScanList(&s, "One") @@ -4064,12 +4065,12 @@ func Test_ScanList_NoRecreate_StructAttribute(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "age": gdb.NewValue(20), + "id": gvar.New(1), + "age": gvar.New(20), }, gdb.Record{ - "id": gdb.NewValue(2), - "age": gdb.NewValue(21), + "id": gvar.New(2), + "age": gvar.New(21), }, } err = r2.ScanList(&s, "One", "One", "id:Id") @@ -4108,14 +4109,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), + "id": gvar.New(1), + "name": gvar.New("john"), + "age": gvar.New(16), }, gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), + "id": gvar.New(2), + "name": gvar.New("smith"), + "age": gvar.New(18), }, } err = r1.ScanList(&s, "One") @@ -4128,16 +4129,16 @@ func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(30), - "name": gdb.NewValue("john"), + "id": gvar.New(100), + "pid": gvar.New(1), + "age": gvar.New(30), + "name": gvar.New("john"), }, gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(31), - "name": gdb.NewValue("smith"), + "id": gvar.New(200), + "pid": gvar.New(1), + "age": gvar.New(31), + "name": gvar.New("smith"), }, } err = r2.ScanList(&s, "Many", "One", "pid:Id") @@ -4158,14 +4159,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { r3 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(40), + "id": gvar.New(100), + "pid": gvar.New(1), + "age": gvar.New(40), }, gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(41), + "id": gvar.New(200), + "pid": gvar.New(1), + "age": gvar.New(41), }, } err = r3.ScanList(&s, "Many", "One", "pid:Id") @@ -4212,14 +4213,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), + "id": gvar.New(1), + "name": gvar.New("john"), + "age": gvar.New(16), }, gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), + "id": gvar.New(2), + "name": gvar.New("smith"), + "age": gvar.New(18), }, } err = r1.ScanList(&s, "One") @@ -4232,16 +4233,16 @@ func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(30), - "name": gdb.NewValue("john"), + "id": gvar.New(100), + "pid": gvar.New(1), + "age": gvar.New(30), + "name": gvar.New("john"), }, gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(31), - "name": gdb.NewValue("smith"), + "id": gvar.New(200), + "pid": gvar.New(1), + "age": gvar.New(31), + "name": gvar.New("smith"), }, } err = r2.ScanList(&s, "Many", "One", "pid:Id") @@ -4262,14 +4263,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { r3 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(40), + "id": gvar.New(100), + "pid": gvar.New(1), + "age": gvar.New(40), }, gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(41), + "id": gvar.New(200), + "pid": gvar.New(1), + "age": gvar.New(41), }, } err = r3.ScanList(&s, "Many", "One", "pid:Id") @@ -4300,8 +4301,8 @@ func TestResult_Structs1(t *testing.T) { } gtest.C(t, func(t *gtest.T) { r := gdb.Result{ - gdb.Record{"id": gdb.NewValue(nil), "name": gdb.NewValue("john")}, - gdb.Record{"id": gdb.NewValue(nil), "name": gdb.NewValue("smith")}, + gdb.Record{"id": gvar.New(nil), "name": gvar.New("john")}, + gdb.Record{"id": gvar.New(nil), "name": gvar.New("smith")}, } array := make([]*B, 2) err := r.Structs(&array) diff --git a/contrib/drivers/sqlitecgo/sqlitecgo_z_unit_model_test.go b/contrib/drivers/sqlitecgo/sqlitecgo_z_unit_model_test.go index 550aab96404..3ad793df2d3 100644 --- a/contrib/drivers/sqlitecgo/sqlitecgo_z_unit_model_test.go +++ b/contrib/drivers/sqlitecgo/sqlitecgo_z_unit_model_test.go @@ -17,6 +17,7 @@ import ( "github.com/gogf/gf/v2/container/garray" "github.com/gogf/gf/v2/container/gmap" + "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/errors/gcode" @@ -4036,14 +4037,14 @@ func Test_ScanList_NoRecreate_PtrAttribute(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), + "id": gvar.New(1), + "name": gvar.New("john"), + "age": gvar.New(16), }, gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), + "id": gvar.New(2), + "name": gvar.New("smith"), + "age": gvar.New(18), }, } err = r1.ScanList(&s, "One") @@ -4056,12 +4057,12 @@ func Test_ScanList_NoRecreate_PtrAttribute(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "age": gdb.NewValue(20), + "id": gvar.New(1), + "age": gvar.New(20), }, gdb.Record{ - "id": gdb.NewValue(2), - "age": gdb.NewValue(21), + "id": gvar.New(2), + "age": gvar.New(21), }, } err = r2.ScanList(&s, "One", "One", "id:Id") @@ -4092,14 +4093,14 @@ func Test_ScanList_NoRecreate_StructAttribute(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), + "id": gvar.New(1), + "name": gvar.New("john"), + "age": gvar.New(16), }, gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), + "id": gvar.New(2), + "name": gvar.New("smith"), + "age": gvar.New(18), }, } err = r1.ScanList(&s, "One") @@ -4112,12 +4113,12 @@ func Test_ScanList_NoRecreate_StructAttribute(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "age": gdb.NewValue(20), + "id": gvar.New(1), + "age": gvar.New(20), }, gdb.Record{ - "id": gdb.NewValue(2), - "age": gdb.NewValue(21), + "id": gvar.New(2), + "age": gvar.New(21), }, } err = r2.ScanList(&s, "One", "One", "id:Id") @@ -4156,14 +4157,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), + "id": gvar.New(1), + "name": gvar.New("john"), + "age": gvar.New(16), }, gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), + "id": gvar.New(2), + "name": gvar.New("smith"), + "age": gvar.New(18), }, } err = r1.ScanList(&s, "One") @@ -4176,16 +4177,16 @@ func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(30), - "name": gdb.NewValue("john"), + "id": gvar.New(100), + "pid": gvar.New(1), + "age": gvar.New(30), + "name": gvar.New("john"), }, gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(31), - "name": gdb.NewValue("smith"), + "id": gvar.New(200), + "pid": gvar.New(1), + "age": gvar.New(31), + "name": gvar.New("smith"), }, } err = r2.ScanList(&s, "Many", "One", "pid:Id") @@ -4206,14 +4207,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Ptr(t *testing.T) { r3 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(40), + "id": gvar.New(100), + "pid": gvar.New(1), + "age": gvar.New(40), }, gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(41), + "id": gvar.New(200), + "pid": gvar.New(1), + "age": gvar.New(41), }, } err = r3.ScanList(&s, "Many", "One", "pid:Id") @@ -4260,14 +4261,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { ) r1 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(1), - "name": gdb.NewValue("john"), - "age": gdb.NewValue(16), + "id": gvar.New(1), + "name": gvar.New("john"), + "age": gvar.New(16), }, gdb.Record{ - "id": gdb.NewValue(2), - "name": gdb.NewValue("smith"), - "age": gdb.NewValue(18), + "id": gvar.New(2), + "name": gvar.New("smith"), + "age": gvar.New(18), }, } err = r1.ScanList(&s, "One") @@ -4280,16 +4281,16 @@ func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { r2 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(30), - "name": gdb.NewValue("john"), + "id": gvar.New(100), + "pid": gvar.New(1), + "age": gvar.New(30), + "name": gvar.New("john"), }, gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(31), - "name": gdb.NewValue("smith"), + "id": gvar.New(200), + "pid": gvar.New(1), + "age": gvar.New(31), + "name": gvar.New("smith"), }, } err = r2.ScanList(&s, "Many", "One", "pid:Id") @@ -4310,14 +4311,14 @@ func Test_ScanList_NoRecreate_SliceAttribute_Struct(t *testing.T) { r3 := gdb.Result{ gdb.Record{ - "id": gdb.NewValue(100), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(40), + "id": gvar.New(100), + "pid": gvar.New(1), + "age": gvar.New(40), }, gdb.Record{ - "id": gdb.NewValue(200), - "pid": gdb.NewValue(1), - "age": gdb.NewValue(41), + "id": gvar.New(200), + "pid": gvar.New(1), + "age": gvar.New(41), }, } err = r3.ScanList(&s, "Many", "One", "pid:Id") @@ -4348,8 +4349,8 @@ func TestResult_Structs1(t *testing.T) { } gtest.C(t, func(t *gtest.T) { r := gdb.Result{ - gdb.Record{"id": gdb.NewValue(nil), "name": gdb.NewValue("john")}, - gdb.Record{"id": gdb.NewValue(nil), "name": gdb.NewValue("smith")}, + gdb.Record{"id": gvar.New(nil), "name": gvar.New("john")}, + gdb.Record{"id": gvar.New(nil), "name": gvar.New("smith")}, } array := make([]*B, 2) err := r.Structs(&array) From d0e0efb49675f91202172bb1ac21c5b13c63a7d6 Mon Sep 17 00:00:00 2001 From: John Guo Date: Fri, 28 Feb 2025 12:28:08 +0800 Subject: [PATCH 18/48] up --- database/gdb/gdb_core_underlying.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/database/gdb/gdb_core_underlying.go b/database/gdb/gdb_core_underlying.go index a2aaedca389..d7d8d1c510c 100644 --- a/database/gdb/gdb_core_underlying.go +++ b/database/gdb/gdb_core_underlying.go @@ -496,22 +496,6 @@ func (c *Core) RowsToResult(ctx context.Context, rows *sql.Rows) (Result, error) return result, nil } -func (c *Core) getLocalTypeForFieldWithCache( - ctx context.Context, fieldType string, fieldValue any, -) (localType LocalType, err error) { - v := c.localTypeMap.GetOrSetFuncLock(fieldType, func() any { - localType, err = c.db.CheckLocalTypeForField(ctx, fieldType, fieldValue) - if err != nil { - return nil - } - return localType - }) - if err != nil { - return LocalTypeUndefined, err - } - return v.(LocalType), nil -} - // OrderRandomFunction returns the SQL function for random ordering. func (c *Core) OrderRandomFunction() string { return "RAND()" From d24245e0688f418c9ade7c4637b8b874eabb2c53 Mon Sep 17 00:00:00 2001 From: John Guo Date: Fri, 28 Feb 2025 12:29:27 +0800 Subject: [PATCH 19/48] up --- examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples b/examples index fbf44fb4998..2544fee34dd 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit fbf44fb4998e9a7da5d09096a6e722464e25748c +Subproject commit 2544fee34dd10e6914687f7335bd9e772215ce07 From 97c40a5879e40fce5aa1debc6245a02454c18aa3 Mon Sep 17 00:00:00 2001 From: John Guo Date: Fri, 28 Feb 2025 16:33:56 +0800 Subject: [PATCH 20/48] up --- contrib/drivers/mysql/mysql_z_unit_issue_test.go | 2 +- util/gconv/gconv_struct.go | 1 + .../gconv/internal/structcache/structcache_cached_field_info.go | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/contrib/drivers/mysql/mysql_z_unit_issue_test.go b/contrib/drivers/mysql/mysql_z_unit_issue_test.go index 7f7f0a85401..388fa46e2f3 100644 --- a/contrib/drivers/mysql/mysql_z_unit_issue_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_issue_test.go @@ -1741,7 +1741,7 @@ func Test_Issue4086(t *testing.T) { }, }) }) - +return gtest.C(t, func(t *gtest.T) { type ProxyParam struct { ProxyId int64 `json:"proxyId" orm:"proxy_id"` diff --git a/util/gconv/gconv_struct.go b/util/gconv/gconv_struct.go index 57fadd7c9d3..8c7e1aa762a 100644 --- a/util/gconv/gconv_struct.go +++ b/util/gconv/gconv_struct.go @@ -336,6 +336,7 @@ func fuzzyMatchingFieldName( } // bindVarToStructField sets value to struct object attribute by name. +// each value to attribute converting comes into in this function. func bindVarToStructField( fieldValue reflect.Value, srcValue interface{}, diff --git a/util/gconv/internal/structcache/structcache_cached_field_info.go b/util/gconv/internal/structcache/structcache_cached_field_info.go index 1009295e28e..d50028acee8 100644 --- a/util/gconv/internal/structcache/structcache_cached_field_info.go +++ b/util/gconv/internal/structcache/structcache_cached_field_info.go @@ -51,6 +51,8 @@ type CachedFieldInfoBase struct { IsCommonInterface bool // IsCustomConvert marks there custom converting function for this field type. + // A custom converting function is a function that user defined for converting specified type + // to another type. IsCustomConvert bool // StructField is the type info of this field. From 7f030248ac1028f29a6ff6c9e984cd93cd4339c5 Mon Sep 17 00:00:00 2001 From: John Guo Date: Sun, 2 Mar 2025 11:15:22 +0800 Subject: [PATCH 21/48] up --- util/gconv/gconv.go | 20 +-- util/gconv/gconv_convert.go | 47 ++++--- util/gconv/gconv_convert_config.go | 99 +++++++++++++++ util/gconv/gconv_converter.go | 46 ++++--- util/gconv/gconv_converter_builtin.go | 82 ++++++++++++ util/gconv/gconv_maptomap.go | 34 ++--- util/gconv/gconv_scan.go | 13 +- util/gconv/gconv_struct.go | 119 +++++++++++------- .../gconv/internal/structcache/structcache.go | 50 +++++++- .../structcache/structcache_cached.go | 53 ++------ .../structcache_cached_field_info.go | 2 +- .../structcache_cached_struct_info.go | 119 ++++++++---------- 12 files changed, 443 insertions(+), 241 deletions(-) create mode 100644 util/gconv/gconv_convert_config.go create mode 100644 util/gconv/gconv_converter_builtin.go diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index d3bc027ef05..426afd40147 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -14,6 +14,8 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/structcache" ) +type AnyConvertFunc = structcache.AnyConvertFunc + var ( // Empty strings. emptyStringMap = map[string]struct{}{ @@ -29,17 +31,7 @@ var ( // Note that only pointer can implement interface IUnmarshalValue. type IUnmarshalValue = localinterface.IUnmarshalValue -func init() { - // register common converters for internal usage. - structcache.RegisterCommonConverter(structcache.CommonConverter{ - Int64: Int64, - Uint64: Uint64, - String: String, - Float32: Float32, - Float64: Float64, - Time: Time, - GTime: GTime, - Bytes: Bytes, - Bool: Bool, - }) -} +var ( + // defaultConvertConfig is the default configuration for type converting. + defaultConvertConfig = NewConvertConfig() +) diff --git a/util/gconv/gconv_convert.go b/util/gconv/gconv_convert.go index 49bb32b1fd3..2cd67d3e8bf 100644 --- a/util/gconv/gconv_convert.go +++ b/util/gconv/gconv_convert.go @@ -21,12 +21,15 @@ import ( // The optional parameter `extraParams` is used for additional necessary parameter for this conversion. // It supports common basic types conversion as its conversion based on type name string. func Convert(fromValue interface{}, toTypeName string, extraParams ...interface{}) interface{} { - return doConvert(doConvertInput{ - FromValue: fromValue, - ToTypeName: toTypeName, - ReferValue: nil, - Extra: extraParams, - }) + return doConvert( + defaultConvertConfig, + doConvertInput{ + FromValue: fromValue, + ToTypeName: toTypeName, + ReferValue: nil, + Extra: extraParams, + }, + ) } // ConvertWithRefer converts the variable `fromValue` to the type referred by value `referValue`. @@ -40,12 +43,15 @@ func ConvertWithRefer(fromValue interface{}, referValue interface{}, extraParams } else { referValueRf = reflect.ValueOf(referValue) } - return doConvert(doConvertInput{ - FromValue: fromValue, - ToTypeName: referValueRf.Type().String(), - ReferValue: referValue, - Extra: extraParams, - }) + return doConvert( + defaultConvertConfig, + doConvertInput{ + FromValue: fromValue, + ToTypeName: referValueRf.Type().String(), + ReferValue: referValue, + Extra: extraParams, + }, + ) } type doConvertInput struct { @@ -53,13 +59,14 @@ type doConvertInput struct { ToTypeName string // Target value type name in string. ReferValue interface{} // Referred value, a value in type `ToTypeName`. Note that its type might be reflect.Value. Extra []interface{} // Extra values for implementing the converting. + // Marks that the value is already converted and set to `ReferValue`. Caller can ignore the returned result. // It is an attribute for internal usage purpose. alreadySetToReferValue bool } // doConvert does commonly use types converting. -func doConvert(in doConvertInput) (convertedValue interface{}) { +func doConvert(cf *ConvertConfig, in doConvertInput) (convertedValue interface{}) { switch in.ToTypeName { case "int": return Int(in.FromValue) @@ -296,14 +303,14 @@ func doConvert(in doConvertInput) (convertedValue interface{}) { } // custom converter. - if dstReflectValue, ok, _ := callCustomConverterWithRefer(fromReflectValue, referReflectValue); ok { + if dstReflectValue, ok, _ := cf.callCustomConverterWithRefer(fromReflectValue, referReflectValue); ok { return dstReflectValue.Interface() } defer func() { if recover() != nil { in.alreadySetToReferValue = false - if err := bindVarToReflectValue(referReflectValue, in.FromValue, nil); err == nil { + if err := bindVarToReflectValue(cf, referReflectValue, in.FromValue, nil); err == nil { in.alreadySetToReferValue = true convertedValue = referReflectValue.Interface() } @@ -326,7 +333,7 @@ func doConvert(in doConvertInput) (convertedValue interface{}) { default: in.ToTypeName = originType.Kind().String() in.ReferValue = nil - refElementValue := reflect.ValueOf(doConvert(in)) + refElementValue := reflect.ValueOf(doConvert(cf, in)) originTypeValue := reflect.New(refElementValue.Type()).Elem() originTypeValue.Set(refElementValue) in.alreadySetToReferValue = true @@ -335,7 +342,7 @@ func doConvert(in doConvertInput) (convertedValue interface{}) { case reflect.Map: var targetValue = reflect.New(referReflectValue.Type()).Elem() - if err := doMapToMap(in.FromValue, targetValue); err == nil { + if err := doMapToMap(cf, in.FromValue, targetValue); err == nil { in.alreadySetToReferValue = true } return targetValue.Interface() @@ -343,15 +350,15 @@ func doConvert(in doConvertInput) (convertedValue interface{}) { in.ToTypeName = referReflectValue.Kind().String() in.ReferValue = nil in.alreadySetToReferValue = true - convertedValue = reflect.ValueOf(doConvert(in)).Convert(referReflectValue.Type()).Interface() + convertedValue = reflect.ValueOf(doConvert(cf, in)).Convert(referReflectValue.Type()).Interface() return convertedValue } return in.FromValue } } -func doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput) { - convertedValue := doConvert(in) +func doConvertWithReflectValueSet(cf *ConvertConfig, reflectValue reflect.Value, in doConvertInput) { + convertedValue := doConvert(cf, in) if !in.alreadySetToReferValue { reflectValue.Set(reflect.ValueOf(convertedValue)) } diff --git a/util/gconv/gconv_convert_config.go b/util/gconv/gconv_convert_config.go new file mode 100644 index 00000000000..82712c0776b --- /dev/null +++ b/util/gconv/gconv_convert_config.go @@ -0,0 +1,99 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + "time" + + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv/internal/structcache" +) + +// CommonTypeConverter holds some converting functions of common types for internal usage. +type CommonTypeConverter = structcache.CommonTypeConverter + +type ( + converterInType = reflect.Type + converterOutType = reflect.Type + converterFunc = reflect.Value +) + +// ConvertConfig is the configuration for type converting. +type ConvertConfig struct { + internalConvertConfig *structcache.ConvertConfig + // customConverters for internal converter storing. + customConverters map[converterInType]map[converterOutType]converterFunc +} + +var ( + intType = reflect.TypeOf(0) + int8Type = reflect.TypeOf(int8(0)) + int16Type = reflect.TypeOf(int16(0)) + int32Type = reflect.TypeOf(int32(0)) + int64Type = reflect.TypeOf(int64(0)) + + uintType = reflect.TypeOf(uint(0)) + uint8Type = reflect.TypeOf(uint8(0)) + uint16Type = reflect.TypeOf(uint16(0)) + uint32Type = reflect.TypeOf(uint32(0)) + uint64Type = reflect.TypeOf(uint64(0)) + + float32Type = reflect.TypeOf(float32(0)) + float64Type = reflect.TypeOf(float64(0)) + + stringType = reflect.TypeOf("") + bytesType = reflect.TypeOf([]byte{}) + + boolType = reflect.TypeOf(false) + + timeType = reflect.TypeOf((*time.Time)(nil)).Elem() + gtimeType = reflect.TypeOf((*gtime.Time)(nil)).Elem() +) + +// NewConvertConfig creates and returns configuration management object for type converting. +func NewConvertConfig() *ConvertConfig { + cf := &ConvertConfig{ + internalConvertConfig: structcache.NewConvertConfig(), + customConverters: make(map[converterInType]map[converterOutType]converterFunc), + } + cf.registerBuiltInConverter() + return cf +} + +func (cf *ConvertConfig) registerBuiltInConverter() { + cf.registerAnyConvertFuncForTypes( + builtInAnyConvertFuncForInt64, intType, int8Type, int16Type, int32Type, int64Type, + ) + cf.registerAnyConvertFuncForTypes( + builtInAnyConvertFuncForUint64, uintType, uint8Type, uint16Type, uint32Type, uint64Type, + ) + cf.registerAnyConvertFuncForTypes( + builtInAnyConvertFuncForString, stringType, + ) + cf.registerAnyConvertFuncForTypes( + builtInAnyConvertFuncForFloat64, float32Type, float64Type, + ) + cf.registerAnyConvertFuncForTypes( + builtInAnyConvertFuncForBool, boolType, + ) + cf.registerAnyConvertFuncForTypes( + builtInAnyConvertFuncForBytes, bytesType, + ) + cf.registerAnyConvertFuncForTypes( + builtInAnyConvertFuncForTime, timeType, + ) + cf.registerAnyConvertFuncForTypes( + builtInAnyConvertFuncForGTime, gtimeType, + ) +} + +func (cf *ConvertConfig) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, types ...reflect.Type) { + for _, t := range types { + cf.internalConvertConfig.RegisterAnyConvertFunc(t, convertFunc) + } +} diff --git a/util/gconv/gconv_converter.go b/util/gconv/gconv_converter.go index eb0e226d1c0..72337f00f47 100644 --- a/util/gconv/gconv_converter.go +++ b/util/gconv/gconv_converter.go @@ -11,19 +11,14 @@ import ( "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/util/gconv/internal/structcache" ) -type ( - converterInType = reflect.Type - converterOutType = reflect.Type - converterFunc = reflect.Value -) - -// customConverters for internal converter storing. -var customConverters = make(map[converterInType]map[converterOutType]converterFunc) +// RegisterConverter registers custom converter. +func RegisterConverter(fn any) (err error) { + return defaultConvertConfig.RegisterConverter(fn) +} -// RegisterConverter to register custom converter. +// RegisterConverter registers custom converter. // It must be registered before you use this custom converting feature. // It is suggested to do it in boot procedure of the process. // @@ -31,7 +26,7 @@ var customConverters = make(map[converterInType]map[converterOutType]converterFu // 1. The parameter `fn` must be defined as pattern `func(T1) (T2, error)`. // It will convert type `T1` to type `T2`. // 2. The `T1` should not be type of pointer, but the `T2` should be type of pointer. -func RegisterConverter(fn interface{}) (err error) { +func (cf *ConvertConfig) RegisterConverter(fn any) (err error) { var ( fnReflectType = reflect.TypeOf(fn) errType = reflect.TypeOf((*error)(nil)).Elem() @@ -41,7 +36,8 @@ func RegisterConverter(fn interface{}) (err error) { !fnReflectType.Out(1).Implements(errType) { err = gerror.NewCodef( gcode.CodeInvalidParameter, - "parameter must be type of converter function and defined as pattern `func(T1) (T2, error)`, but defined as `%s`", + "parameter must be type of converter function and defined as pattern `func(T1) (T2, error)`, "+ + "but defined as `%s`", fnReflectType.String(), ) return @@ -69,10 +65,10 @@ func RegisterConverter(fn interface{}) (err error) { return } - registeredOutTypeMap, ok := customConverters[inType] + registeredOutTypeMap, ok := cf.customConverters[inType] if !ok { registeredOutTypeMap = make(map[converterOutType]converterFunc) - customConverters[inType] = registeredOutTypeMap + cf.customConverters[inType] = registeredOutTypeMap } if _, ok = registeredOutTypeMap[outType]; ok { err = gerror.NewCodef( @@ -83,14 +79,14 @@ func RegisterConverter(fn interface{}) (err error) { return } registeredOutTypeMap[outType] = reflect.ValueOf(fn) - structcache.RegisterCustomConvertType(outType) + cf.internalConvertConfig.RegisterCustomConvertType(outType) return } -func getRegisteredConverterFuncAndSrcType( +func (cf *ConvertConfig) getRegisteredConverterFuncAndSrcType( srcReflectValue, dstReflectValueForRefer reflect.Value, ) (f converterFunc, srcType reflect.Type, ok bool) { - if len(customConverters) == 0 { + if len(cf.customConverters) == 0 { return reflect.Value{}, nil, false } srcType = srcReflectValue.Type() @@ -99,7 +95,7 @@ func getRegisteredConverterFuncAndSrcType( } var registeredOutTypeMap map[converterOutType]converterFunc // firstly, it searches the map by input parameter type. - registeredOutTypeMap, ok = customConverters[srcType] + registeredOutTypeMap, ok = cf.customConverters[srcType] if !ok { return reflect.Value{}, nil, false } @@ -123,28 +119,28 @@ func getRegisteredConverterFuncAndSrcType( return } -func callCustomConverterWithRefer( +func (cf *ConvertConfig) callCustomConverterWithRefer( srcReflectValue, referReflectValue reflect.Value, ) (dstReflectValue reflect.Value, converted bool, err error) { - registeredConverterFunc, srcType, ok := getRegisteredConverterFuncAndSrcType(srcReflectValue, referReflectValue) + registeredConverterFunc, srcType, ok := cf.getRegisteredConverterFuncAndSrcType(srcReflectValue, referReflectValue) if !ok { return reflect.Value{}, false, nil } dstReflectValue = reflect.New(referReflectValue.Type()).Elem() - converted, err = doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) + converted, err = cf.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) return } // callCustomConverter call the custom converter. It will try some possible type. -func callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) { - registeredConverterFunc, srcType, ok := getRegisteredConverterFuncAndSrcType(srcReflectValue, dstReflectValue) +func (cf *ConvertConfig) callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) { + registeredConverterFunc, srcType, ok := cf.getRegisteredConverterFuncAndSrcType(srcReflectValue, dstReflectValue) if !ok { return false, nil } - return doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) + return cf.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) } -func doCallCustomConverter( +func (cf *ConvertConfig) doCallCustomConverter( srcReflectValue reflect.Value, dstReflectValue reflect.Value, registeredConverterFunc converterFunc, diff --git a/util/gconv/gconv_converter_builtin.go b/util/gconv/gconv_converter_builtin.go new file mode 100644 index 00000000000..1d2e00594d9 --- /dev/null +++ b/util/gconv/gconv_converter_builtin.go @@ -0,0 +1,82 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + "time" + + "github.com/gogf/gf/v2/os/gtime" +) + +func builtInAnyConvertFuncForInt64(from any, to reflect.Value) error { + v, err := doInt64(from) + if err != nil { + return err + } + to.SetInt(v) + return nil +} + +func builtInAnyConvertFuncForUint64(from any, to reflect.Value) error { + v, err := doUint64(from) + if err != nil { + return err + } + to.SetUint(v) + return nil +} + +func builtInAnyConvertFuncForString(from any, to reflect.Value) error { + v, err := doString(from) + if err != nil { + return err + } + to.SetString(v) + return nil +} + +func builtInAnyConvertFuncForFloat64(from any, to reflect.Value) error { + v, err := doFloat64(from) + if err != nil { + return err + } + to.SetFloat(v) + return nil +} + +func builtInAnyConvertFuncForBool(from any, to reflect.Value) error { + v, err := doBool(from) + if err != nil { + return err + } + to.SetBool(v) + return nil +} + +func builtInAnyConvertFuncForBytes(from any, to reflect.Value) error { + v, err := doBytes(from) + if err != nil { + return err + } + to.SetBytes(v) + return nil +} + +func builtInAnyConvertFuncForTime(from any, to reflect.Value) error { + *to.Addr().Interface().(*time.Time) = Time(from) + return nil +} + +func builtInAnyConvertFuncForGTime(from any, to reflect.Value) error { + v := GTime(from) + if v == nil { + v = gtime.New() + } + *to.Addr().Interface().(*gtime.Time) = *v + return nil +} diff --git a/util/gconv/gconv_maptomap.go b/util/gconv/gconv_maptomap.go index ffd352e582f..bc40a82c059 100644 --- a/util/gconv/gconv_maptomap.go +++ b/util/gconv/gconv_maptomap.go @@ -16,7 +16,7 @@ import ( // MapToMap converts any map type variable `params` to another map type variable `pointer` // using reflect. // See doMapToMap. -func MapToMap(params interface{}, pointer interface{}, mapping ...map[string]string) error { +func MapToMap(params any, pointer any, mapping ...map[string]string) error { return Scan(params, pointer, mapping...) } @@ -30,7 +30,7 @@ func MapToMap(params interface{}, pointer interface{}, mapping ...map[string]str // // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes // sense only if the items of original map `params` is type struct. -func doMapToMap(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) { +func doMapToMap(cf *ConvertConfig, params any, pointer any, mapping ...map[string]string) (err error) { var ( paramsRv reflect.Value paramsKind reflect.Kind @@ -50,7 +50,7 @@ func doMapToMap(params interface{}, pointer interface{}, mapping ...map[string]s paramsKind = paramsRv.Kind() } if paramsKind != reflect.Map { - return doMapToMap(Map(params), pointer, mapping...) + return doMapToMap(cf, Map(params), pointer, mapping...) } // Empty params map, no need continue. if paramsRv.Len() == 0 { @@ -107,22 +107,26 @@ func doMapToMap(params interface{}, pointer interface{}, mapping ...map[string]s default: mapValue.Set( reflect.ValueOf( - doConvert(doConvertInput{ - FromValue: paramsRv.MapIndex(key).Interface(), - ToTypeName: pointerValueType.String(), - ReferValue: mapValue, - Extra: nil, - }), + doConvert( + cf, doConvertInput{ + FromValue: paramsRv.MapIndex(key).Interface(), + ToTypeName: pointerValueType.String(), + ReferValue: mapValue, + Extra: nil, + }), ), ) } var mapKey = reflect.ValueOf( - doConvert(doConvertInput{ - FromValue: key.Interface(), - ToTypeName: pointerKeyType.Name(), - ReferValue: reflect.New(pointerKeyType).Elem().Interface(), - Extra: nil, - }), + doConvert( + cf, + doConvertInput{ + FromValue: key.Interface(), + ToTypeName: pointerKeyType.Name(), + ReferValue: reflect.New(pointerKeyType).Elem().Interface(), + Extra: nil, + }, + ), ) dataMap.SetMapIndex(mapKey, mapValue) } diff --git a/util/gconv/gconv_scan.go b/util/gconv/gconv_scan.go index 376a2b1aae2..5ced0c5d8bd 100644 --- a/util/gconv/gconv_scan.go +++ b/util/gconv/gconv_scan.go @@ -26,6 +26,10 @@ import ( // The `paramKeyToAttrMap` parameter is used for mapping between attribute names and parameter keys. // TODO: change `paramKeyToAttrMap` to `ScanOption` to be more scalable; add `DeepCopy` option for `ScanOption`. func Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) { + return ScanWithConfig(defaultConvertConfig, srcValue, dstPointer, paramKeyToAttrMap...) +} + +func ScanWithConfig(cf *ConvertConfig, srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) { // Check if srcValue is nil, in which case no conversion is needed if srcValue == nil { return nil @@ -142,7 +146,7 @@ func Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) } // Special handling for struct or map slice elements if dstElemKind == reflect.Struct || dstElemKind == reflect.Map { - return doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...) + return doScanForComplicatedTypes(cf, srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...) } // Handle basic type slice conversions var srcValueReflectValueKind = srcValueReflectValue.Kind() @@ -173,11 +177,11 @@ func Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) dstPointerReflectValueElem.Set(newSlice) return nil } - return doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...) + return doScanForComplicatedTypes(cf, srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...) default: // Handle complex types (structs, maps, etc.) - return doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...) + return doScanForComplicatedTypes(cf, srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...) } } @@ -193,6 +197,7 @@ func Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) // - dstPointerReflectType: The reflection type of the destination pointer // - paramKeyToAttrMap: Optional mapping between parameter keys and struct attribute names func doScanForComplicatedTypes( + cf *ConvertConfig, srcValue, dstPointer any, dstPointerReflectType reflect.Type, paramKeyToAttrMap ...map[string]string, @@ -220,7 +225,7 @@ func doScanForComplicatedTypes( switch dstPointerReflectTypeElemKind { case reflect.Map: // Convert map to map - return doMapToMap(srcValue, dstPointer, paramKeyToAttrMap...) + return doMapToMap(cf, srcValue, dstPointer, paramKeyToAttrMap...) case reflect.Array, reflect.Slice: var ( diff --git a/util/gconv/gconv_struct.go b/util/gconv/gconv_struct.go index 8c7e1aa762a..e47ee395f4f 100644 --- a/util/gconv/gconv_struct.go +++ b/util/gconv/gconv_struct.go @@ -32,20 +32,34 @@ import ( // It will automatically convert the first letter of the key to uppercase // in mapping procedure to do the matching. // It ignores the map key, if it does not match. -func Struct(params interface{}, pointer interface{}, paramKeyToAttrMap ...map[string]string) (err error) { +func Struct(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) { return Scan(params, pointer, paramKeyToAttrMap...) } // StructTag acts as Struct but also with support for priority tag feature, which retrieves the // specified priorityTagAndFieldName for `params` key-value items to struct attribute names mapping. // The parameter `priorityTag` supports multiple priorityTagAndFieldName that can be joined with char ','. -func StructTag(params interface{}, pointer interface{}, priorityTag string) (err error) { +func StructTag(params any, pointer any, priorityTag string) (err error) { return doStruct(params, pointer, nil, priorityTag) } // doStruct is the core internal converting function for any data to struct. func doStruct( - params interface{}, pointer interface{}, paramKeyToAttrMap map[string]string, priorityTag string, + params any, + pointer any, + paramKeyToAttrMap map[string]string, + priorityTag string, +) (err error) { + return doStructWithConfig(defaultConvertConfig, params, pointer, paramKeyToAttrMap, priorityTag) +} + +// doStruct is the core internal converting function for any data to struct. +func doStructWithConfig( + cf *ConvertConfig, + params any, + pointer any, + paramKeyToAttrMap map[string]string, + priorityTag string, ) (err error) { if params == nil { // If `params` is nil, no conversion. @@ -77,7 +91,7 @@ func doStruct( var ( paramsReflectValue reflect.Value - paramsInterface interface{} // DO NOT use `params` directly as it might be type `reflect.Value` + paramsInterface any // DO NOT use `params` directly as it might be type `reflect.Value` pointerReflectValue reflect.Value pointerReflectKind reflect.Kind pointerElemReflectValue reflect.Value // The reflection value to struct element. @@ -118,7 +132,7 @@ func doStruct( } // custom convert. - if ok, err = callCustomConverter(paramsReflectValue, pointerReflectValue); ok { + if ok, err = cf.callCustomConverter(paramsReflectValue, pointerReflectValue); ok { return err } @@ -150,15 +164,15 @@ func doStruct( // Retrieve its element, may be struct at last. pointerElemReflectValue = pointerElemReflectValue.Elem() } - paramsMap, ok := paramsInterface.(map[string]interface{}) + paramsMap, ok := paramsInterface.(map[string]any) if !ok { - // paramsMap is the map[string]interface{} type variable for params. + // paramsMap is the map[string]any type variable for params. // DO NOT use MapDeep here. paramsMap = doMapConvert(paramsInterface, recursiveTypeAuto, true) if paramsMap == nil { return gerror.NewCodef( gcode.CodeInvalidParameter, - `convert params from "%#v" to "map[string]interface{}" failed`, + `convert params from "%#v" to "map[string]any" failed`, params, ) } @@ -168,7 +182,7 @@ func doStruct( return nil } // Get struct info from cache or parse struct and cache the struct info. - cachedStructInfo := structcache.GetCachedStructInfo( + cachedStructInfo := cf.internalConvertConfig.GetCachedStructInfo( pointerElemReflectValue.Type(), priorityTag, ) // Nothing to be converted. @@ -184,7 +198,7 @@ func doStruct( // Indicates that those values have been used and cannot be reused. usedParamsKeyOrTagNameMap = structcache.GetUsedParamsKeyOrTagNameMapFromPool() cachedFieldInfo *structcache.CachedFieldInfo - paramsValue interface{} + paramsValue any ) defer structcache.PutUsedParamsKeyOrTagNameMapToPool(usedParamsKeyOrTagNameMap) @@ -199,16 +213,17 @@ func doStruct( if cachedFieldInfo != nil { fieldValue := cachedFieldInfo.GetFieldReflectValueFrom(pointerElemReflectValue) if err = bindVarToStructField( + cf, + cachedFieldInfo, fieldValue, paramsValue, - cachedFieldInfo, paramKeyToAttrMap, ); err != nil { return err } if len(cachedFieldInfo.OtherSameNameField) > 0 { if err = setOtherSameNameField( - cachedFieldInfo, paramsValue, pointerReflectValue, paramKeyToAttrMap, + cf, cachedFieldInfo, paramsValue, pointerReflectValue, paramKeyToAttrMap, ); err != nil { return err } @@ -221,11 +236,12 @@ func doStruct( return nil } return bindStructWithLoopFieldInfos( - paramsMap, pointerElemReflectValue, paramKeyToAttrMap, usedParamsKeyOrTagNameMap, cachedStructInfo, + cf, paramsMap, pointerElemReflectValue, paramKeyToAttrMap, usedParamsKeyOrTagNameMap, cachedStructInfo, ) } func setOtherSameNameField( + cf *ConvertConfig, cachedFieldInfo *structcache.CachedFieldInfo, srcValue any, structValue reflect.Value, @@ -234,7 +250,7 @@ func setOtherSameNameField( // loop the same field name of all sub attributes. for _, otherFieldInfo := range cachedFieldInfo.OtherSameNameField { fieldValue := cachedFieldInfo.GetOtherFieldReflectValueFrom(structValue, otherFieldInfo.FieldIndexes) - if err = bindVarToStructField(fieldValue, srcValue, otherFieldInfo, paramKeyToAttrMap); err != nil { + if err = bindVarToStructField(cf, otherFieldInfo, fieldValue, srcValue, paramKeyToAttrMap); err != nil { return err } } @@ -242,6 +258,7 @@ func setOtherSameNameField( } func bindStructWithLoopFieldInfos( + cf *ConvertConfig, paramsMap map[string]any, structValue reflect.Value, paramKeyToAttrMap map[string]string, @@ -257,21 +274,21 @@ func bindStructWithLoopFieldInfos( matched bool ok bool ) - for _, cachedFieldInfo = range cachedStructInfo.FieldConvertInfos { + for _, cachedFieldInfo = range cachedStructInfo.GetFieldConvertInfos() { for _, fieldTag := range cachedFieldInfo.PriorityTagAndFieldName { if paramValue, ok = paramsMap[fieldTag]; !ok { continue } fieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue) if err = bindVarToStructField( - fieldValue, paramValue, cachedFieldInfo, paramKeyToAttrMap, + cf, cachedFieldInfo, fieldValue, paramValue, paramKeyToAttrMap, ); err != nil { return err } // handle same field name in nested struct. if len(cachedFieldInfo.OtherSameNameField) > 0 { if err = setOtherSameNameField( - cachedFieldInfo, paramValue, structValue, paramKeyToAttrMap, + cf, cachedFieldInfo, paramValue, structValue, paramKeyToAttrMap, ); err != nil { return err } @@ -297,14 +314,14 @@ func bindStructWithLoopFieldInfos( fieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue) if paramValue != nil { if err = bindVarToStructField( - fieldValue, paramValue, cachedFieldInfo, paramKeyToAttrMap, + cf, cachedFieldInfo, fieldValue, paramValue, paramKeyToAttrMap, ); err != nil { return err } // handle same field name in nested struct. if len(cachedFieldInfo.OtherSameNameField) > 0 { if err = setOtherSameNameField( - cachedFieldInfo, paramValue, structValue, paramKeyToAttrMap, + cf, cachedFieldInfo, paramValue, structValue, paramKeyToAttrMap, ); err != nil { return err } @@ -338,9 +355,10 @@ func fuzzyMatchingFieldName( // bindVarToStructField sets value to struct object attribute by name. // each value to attribute converting comes into in this function. func bindVarToStructField( - fieldValue reflect.Value, - srcValue interface{}, + cf *ConvertConfig, cachedFieldInfo *structcache.CachedFieldInfo, + fieldValue reflect.Value, + srcValue any, paramKeyToAttrMap map[string]string, ) (err error) { if !fieldValue.IsValid() { @@ -352,7 +370,7 @@ func bindVarToStructField( } defer func() { if exception := recover(); exception != nil { - if err = bindVarToReflectValue(fieldValue, srcValue, paramKeyToAttrMap); err != nil { + if err = bindVarToReflectValue(cf, fieldValue, srcValue, paramKeyToAttrMap); err != nil { err = gerror.Wrapf(err, `error binding srcValue to attribute "%s"`, cachedFieldInfo.FieldName()) } } @@ -372,7 +390,7 @@ func bindVarToStructField( if customConverterInput, ok = srcValue.(reflect.Value); !ok { customConverterInput = reflect.ValueOf(srcValue) } - if ok, err = callCustomConverter(customConverterInput, fieldValue); ok || err != nil { + if ok, err = cf.callCustomConverter(customConverterInput, fieldValue); ok || err != nil { return } } @@ -383,20 +401,21 @@ func bindVarToStructField( } // Common types use fast assignment logic if cachedFieldInfo.ConvertFunc != nil { - cachedFieldInfo.ConvertFunc(srcValue, fieldValue) - return nil - } - doConvertWithReflectValueSet(fieldValue, doConvertInput{ - FromValue: srcValue, - ToTypeName: cachedFieldInfo.StructField.Type.String(), - ReferValue: fieldValue, - }) + return cachedFieldInfo.ConvertFunc(srcValue, fieldValue) + } + doConvertWithReflectValueSet( + cf, fieldValue, doConvertInput{ + FromValue: srcValue, + ToTypeName: cachedFieldInfo.StructField.Type.String(), + ReferValue: fieldValue, + }, + ) return nil } // bindVarToReflectValueWithInterfaceCheck does bind using common interfaces checks. -func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value interface{}) (bool, error) { - var pointer interface{} +func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value any) (bool, error) { + var pointer any if reflectValue.Kind() != reflect.Ptr && reflectValue.CanAddr() { reflectValueAddr := reflectValue.Addr() if reflectValueAddr.IsNil() || !reflectValueAddr.IsValid() { @@ -460,7 +479,7 @@ func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value i // bindVarToReflectValue sets `value` to reflect value object `structFieldValue`. func bindVarToReflectValue( - structFieldValue reflect.Value, value interface{}, paramKeyToAttrMap map[string]string, + cf *ConvertConfig, structFieldValue reflect.Value, value any, paramKeyToAttrMap map[string]string, ) (err error) { // JSON content converting. ok, err := doConvertWithJsonCheck(value, structFieldValue) @@ -486,7 +505,7 @@ func bindVarToReflectValue( // Converting using reflection by kind. switch kind { case reflect.Map: - return doMapToMap(value, structFieldValue, paramKeyToAttrMap) + return doMapToMap(cf, value, structFieldValue, paramKeyToAttrMap) case reflect.Struct: // Recursively converting for struct attribute. @@ -528,11 +547,13 @@ func bindVarToReflectValue( } } if !converted { - doConvertWithReflectValueSet(elem, doConvertInput{ - FromValue: reflectValue.Index(i).Interface(), - ToTypeName: elemTypeName, - ReferValue: elem, - }) + doConvertWithReflectValueSet( + cf, elem, doConvertInput{ + FromValue: reflectValue.Index(i).Interface(), + ToTypeName: elemTypeName, + ReferValue: elem, + }, + ) } if elemType.Kind() == reflect.Ptr { // Before it sets the `elem` to array, do pointer converting if necessary. @@ -578,11 +599,13 @@ func bindVarToReflectValue( } } if !converted { - doConvertWithReflectValueSet(elem, doConvertInput{ - FromValue: value, - ToTypeName: elemTypeName, - ReferValue: elem, - }) + doConvertWithReflectValueSet( + cf, elem, doConvertInput{ + FromValue: value, + ToTypeName: elemTypeName, + ReferValue: elem, + }, + ) } if elemType.Kind() == reflect.Ptr { // Before it sets the `elem` to array, do pointer converting if necessary. @@ -602,19 +625,19 @@ func bindVarToReflectValue( return err } elem := item.Elem() - if err = bindVarToReflectValue(elem, value, paramKeyToAttrMap); err == nil { + if err = bindVarToReflectValue(cf, elem, value, paramKeyToAttrMap); err == nil { structFieldValue.Set(elem.Addr()) } } else { // Not empty pointer, it assigns values to it. - return bindVarToReflectValue(structFieldValue.Elem(), value, paramKeyToAttrMap) + return bindVarToReflectValue(cf, structFieldValue.Elem(), value, paramKeyToAttrMap) } // It mainly and specially handles the interface of nil value. case reflect.Interface: if value == nil { // Specially. - structFieldValue.Set(reflect.ValueOf((*interface{})(nil))) + structFieldValue.Set(reflect.ValueOf((*any)(nil))) } else { // Note there's reflect conversion mechanism here. structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type())) diff --git a/util/gconv/internal/structcache/structcache.go b/util/gconv/internal/structcache/structcache.go index cdb97388dad..e99fd84c63f 100644 --- a/util/gconv/internal/structcache/structcache.go +++ b/util/gconv/internal/structcache/structcache.go @@ -9,24 +9,64 @@ package structcache import ( "reflect" + "sync" + "time" + "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -var ( +type AnyConvertFunc func(from any, to reflect.Value) error + +// ConvertConfig is the configuration for type converting. +type ConvertConfig struct { + // map[reflect.Type]*CachedStructInfo + cachedStructsInfoMap sync.Map + // customConvertTypeMap is used to store whether field types are registered to custom conversions // For example: // func (src *TypeA) (dst *TypeB,err error) // This map will store `TypeB` for quick judgment during assignment. - customConvertTypeMap = map[reflect.Type]struct{}{} -) + // TODO remove? + customConvertTypeMap map[reflect.Type]struct{} + + // anyToTypeConvertMap for custom type converting from any to its reflect.Value. + anyToTypeConvertMap map[reflect.Type]AnyConvertFunc +} + +// CommonTypeConverter holds some converting functions of common types for internal usage. +type CommonTypeConverter struct { + Int64 func(v any) (int64, error) + Uint64 func(v any) (uint64, error) + String func(v any) (string, error) + Float32 func(v any) (float32, error) + Float64 func(v any) (float64, error) + Time func(v any, format ...string) (time.Time, error) + GTime func(v any, format ...string) (*gtime.Time, error) + Bytes func(v any) ([]byte, error) + Bool func(v any) (bool, error) +} + +// NewConvertConfig creates and returns a new ConvertConfig object. +func NewConvertConfig() *ConvertConfig { + return &ConvertConfig{ + cachedStructsInfoMap: sync.Map{}, + customConvertTypeMap: make(map[reflect.Type]struct{}), + anyToTypeConvertMap: make(map[reflect.Type]AnyConvertFunc), + } +} // RegisterCustomConvertType registers custom -func RegisterCustomConvertType(fieldType reflect.Type) { +func (cf *ConvertConfig) RegisterCustomConvertType(fieldType reflect.Type) { if fieldType.Kind() == reflect.Ptr { fieldType = fieldType.Elem() } - customConvertTypeMap[fieldType] = struct{}{} + cf.customConvertTypeMap[fieldType] = struct{}{} +} + +// RegisterAnyConvertFunc registers custom type converting function for specified type. +func (cf *ConvertConfig) RegisterAnyConvertFunc(t reflect.Type, convertFunc AnyConvertFunc) { + cf.anyToTypeConvertMap[t] = convertFunc } var ( diff --git a/util/gconv/internal/structcache/structcache_cached.go b/util/gconv/internal/structcache/structcache_cached.go index 1c7d4cf322b..ef092f2922d 100644 --- a/util/gconv/internal/structcache/structcache_cached.go +++ b/util/gconv/internal/structcache/structcache_cached.go @@ -8,48 +8,19 @@ package structcache import ( "reflect" - "sync" - "time" "github.com/gogf/gf/v2/internal/utils" - "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/gtag" ) -// CommonConverter holds some converting functions of common types for internal usage. -type CommonConverter struct { - Int64 func(any interface{}) int64 - Uint64 func(any interface{}) uint64 - String func(any interface{}) string - Float32 func(any interface{}) float32 - Float64 func(any interface{}) float64 - Time func(any interface{}, format ...string) time.Time - GTime func(any interface{}, format ...string) *gtime.Time - Bytes func(any interface{}) []byte - Bool func(any interface{}) bool -} - -var ( - // map[reflect.Type]*CachedStructInfo - cachedStructsInfoMap = sync.Map{} - - // localCommonConverter holds some converting functions of common types for internal usage. - localCommonConverter CommonConverter -) - -// RegisterCommonConverter registers the CommonConverter for local usage. -func RegisterCommonConverter(commonConverter CommonConverter) { - localCommonConverter = commonConverter -} - // GetCachedStructInfo retrieves or parses and returns a cached info for certain struct type. // The given `structType` should be type of struct. -func GetCachedStructInfo(structType reflect.Type, priorityTag string) *CachedStructInfo { +func (cf *ConvertConfig) GetCachedStructInfo(structType reflect.Type, priorityTag string) *CachedStructInfo { if structType.Kind() != reflect.Struct { return nil } // check if it has been cached. - cachedStructInfo, ok := getCachedConvertStructInfo(structType) + cachedStructInfo, ok := cf.getCachedConvertStructInfo(structType) if ok { // directly returns the cached struct info if already exists. return cachedStructInfo @@ -58,9 +29,7 @@ func GetCachedStructInfo(structType reflect.Type, priorityTag string) *CachedStr // else create one. // it parses and generates a cache info for given struct type. - cachedStructInfo = &CachedStructInfo{ - tagOrFiledNameToFieldInfoMap: make(map[string]*CachedFieldInfo), - } + cachedStructInfo = NewCachedStructInfo(cf.customConvertTypeMap, cf.anyToTypeConvertMap) var ( priorityTagArray []string parentIndex = make([]int, 0) @@ -70,19 +39,19 @@ func GetCachedStructInfo(structType reflect.Type, priorityTag string) *CachedStr } else { priorityTagArray = gtag.StructTagPriority } - parseStructToCachedStructInfo(structType, parentIndex, cachedStructInfo, priorityTagArray) - storeCachedStructInfo(structType, cachedStructInfo) + cf.parseStructToCachedStructInfo(structType, parentIndex, cachedStructInfo, priorityTagArray) + cf.storeCachedStructInfo(structType, cachedStructInfo) return cachedStructInfo } -func storeCachedStructInfo(structType reflect.Type, cachedStructInfo *CachedStructInfo) { +func (cf *ConvertConfig) storeCachedStructInfo(structType reflect.Type, cachedStructInfo *CachedStructInfo) { // Temporarily enabled as an experimental feature - cachedStructsInfoMap.Store(structType, cachedStructInfo) + cf.cachedStructsInfoMap.Store(structType, cachedStructInfo) } -func getCachedConvertStructInfo(structType reflect.Type) (*CachedStructInfo, bool) { +func (cf *ConvertConfig) getCachedConvertStructInfo(structType reflect.Type) (*CachedStructInfo, bool) { // Temporarily enabled as an experimental feature - v, ok := cachedStructsInfoMap.Load(structType) + v, ok := cf.cachedStructsInfoMap.Load(structType) if ok { return v.(*CachedStructInfo), ok } @@ -91,7 +60,7 @@ func getCachedConvertStructInfo(structType reflect.Type) (*CachedStructInfo, boo // parseStructToCachedStructInfo parses given struct reflection type and stores its fields info into given CachedStructInfo. // It stores nothing into CachedStructInfo if given struct reflection type has no fields. -func parseStructToCachedStructInfo( +func (cf *ConvertConfig) parseStructToCachedStructInfo( structType reflect.Type, fieldIndexes []int, cachedStructInfo *CachedStructInfo, @@ -136,7 +105,7 @@ func parseStructToCachedStructInfo( // Do not add anonymous structures without tags cachedStructInfo.AddField(structField, append(copyFieldIndexes, i), priorityTagArray) } - parseStructToCachedStructInfo(fieldType, append(copyFieldIndexes, i), cachedStructInfo, priorityTagArray) + cf.parseStructToCachedStructInfo(fieldType, append(copyFieldIndexes, i), cachedStructInfo, priorityTagArray) continue } // Do not directly use append(fieldIndexes, i) diff --git a/util/gconv/internal/structcache/structcache_cached_field_info.go b/util/gconv/internal/structcache/structcache_cached_field_info.go index d50028acee8..ff89e15cf85 100644 --- a/util/gconv/internal/structcache/structcache_cached_field_info.go +++ b/util/gconv/internal/structcache/structcache_cached_field_info.go @@ -76,7 +76,7 @@ type CachedFieldInfoBase struct { OtherSameNameField []*CachedFieldInfo // ConvertFunc is the converting function for this field. - ConvertFunc func(from any, to reflect.Value) + ConvertFunc AnyConvertFunc // The last fuzzy matching key for this field. // The fuzzy matching occurs only if there are no direct tag and field name matching in the params map. diff --git a/util/gconv/internal/structcache/structcache_cached_struct_info.go b/util/gconv/internal/structcache/structcache_cached_struct_info.go index 24510737684..e1e7e408489 100644 --- a/util/gconv/internal/structcache/structcache_cached_struct_info.go +++ b/util/gconv/internal/structcache/structcache_cached_struct_info.go @@ -9,14 +9,24 @@ package structcache import ( "reflect" "strings" - "time" "github.com/gogf/gf/v2/internal/utils" - "github.com/gogf/gf/v2/os/gtime" ) // CachedStructInfo holds the cached info for certain struct. type CachedStructInfo struct { + // All sub attributes field info slice. + fieldConvertInfos []*CachedFieldInfo + + // customConvertTypeMap is used to store whether field types are registered to custom conversions + // For example: + // func (src *TypeA) (dst *TypeB,err error) + // This map will store `TypeB` for quick judgment during assignment. + customConvertTypeMap map[reflect.Type]struct{} + + // anyToTypeConvertMap for custom type converting from any to its reflect.Value. + anyToTypeConvertMap map[reflect.Type]AnyConvertFunc + // This map field is mainly used in the bindStructWithLoopParamsMap method // key = field's name // Will save all field names and PriorityTagAndFieldName @@ -25,9 +35,23 @@ type CachedStructInfo struct { // // It will be stored twice, which keys are `name` and `field`. tagOrFiledNameToFieldInfoMap map[string]*CachedFieldInfo +} - // All sub attributes field info slice. - FieldConvertInfos []*CachedFieldInfo +// NewCachedStructInfo creates and returns a new CachedStructInfo object. +func NewCachedStructInfo( + customConvertTypeMap map[reflect.Type]struct{}, + anyToTypeConvertMap map[reflect.Type]AnyConvertFunc, +) *CachedStructInfo { + return &CachedStructInfo{ + tagOrFiledNameToFieldInfoMap: make(map[string]*CachedFieldInfo), + fieldConvertInfos: make([]*CachedFieldInfo, 0), + customConvertTypeMap: customConvertTypeMap, + anyToTypeConvertMap: anyToTypeConvertMap, + } +} + +func (csi *CachedStructInfo) GetFieldConvertInfos() []*CachedFieldInfo { + return csi.fieldConvertInfos } func (csi *CachedStructInfo) HasNoFields() bool { @@ -46,7 +70,7 @@ func (csi *CachedStructInfo) AddField(field reflect.StructField, fieldIndexes [] field, fieldIndexes, priorityTags, cachedFieldInfo, tagOrFieldName, ) if newFieldInfo.IsField { - csi.FieldConvertInfos = append(csi.FieldConvertInfos, newFieldInfo) + csi.fieldConvertInfos = append(csi.fieldConvertInfos, newFieldInfo) } // if the field info by `tagOrFieldName` already cached, // it so adds this new field info to other same name field. @@ -82,7 +106,9 @@ func (csi *CachedStructInfo) makeOrCopyCachedInfo( // copyCachedInfoWithFieldIndexes copies and returns a new CachedFieldInfo based on given CachedFieldInfo, but different // FieldIndexes. Mainly used for copying fields with the same name and type. -func (csi *CachedStructInfo) copyCachedInfoWithFieldIndexes(cfi *CachedFieldInfo, fieldIndexes []int) *CachedFieldInfo { +func (csi *CachedStructInfo) copyCachedInfoWithFieldIndexes( + cfi *CachedFieldInfo, fieldIndexes []int, +) *CachedFieldInfo { base := CachedFieldInfoBase{} base = *cfi.CachedFieldInfoBase base.FieldIndexes = fieldIndexes @@ -98,7 +124,7 @@ func (csi *CachedStructInfo) makeCachedFieldInfo( IsCommonInterface: checkTypeIsCommonInterface(field), StructField: field, FieldIndexes: fieldIndexes, - ConvertFunc: csi.genFieldConvertFunc(field.Type.String()), + ConvertFunc: csi.genFieldConvertFunc(field.Type), IsCustomConvert: csi.checkTypeHasCustomConvert(field.Type), PriorityTagAndFieldName: csi.genPriorityTagAndFieldName(field, priorityTags), RemoveSymbolsFieldName: utils.RemoveSymbols(field.Name), @@ -109,59 +135,20 @@ func (csi *CachedStructInfo) makeCachedFieldInfo( } } -func (csi *CachedStructInfo) genFieldConvertFunc(fieldType string) (convertFunc func(from any, to reflect.Value)) { - if fieldType[0] == '*' { - convertFunc = csi.genFieldConvertFunc(fieldType[1:]) +func (csi *CachedStructInfo) genFieldConvertFunc(fieldType reflect.Type) (convertFunc AnyConvertFunc) { + if v := csi.anyToTypeConvertMap[fieldType]; v != nil { + return v + } + + var fieldTypeKind = fieldType.Kind() + if fieldTypeKind == reflect.Ptr { + convertFunc = csi.genFieldConvertFunc(fieldType.Elem()) if convertFunc == nil { return nil } return csi.genPtrConvertFunc(convertFunc) } - switch fieldType { - case "int", "int8", "int16", "int32", "int64": - convertFunc = func(from any, to reflect.Value) { - to.SetInt(localCommonConverter.Int64(from)) - } - case "uint", "uint8", "uint16", "uint32", "uint64": - convertFunc = func(from any, to reflect.Value) { - to.SetUint(localCommonConverter.Uint64(from)) - } - case "string": - convertFunc = func(from any, to reflect.Value) { - to.SetString(localCommonConverter.String(from)) - } - case "float32": - convertFunc = func(from any, to reflect.Value) { - to.SetFloat(float64(localCommonConverter.Float32(from))) - } - case "float64": - convertFunc = func(from any, to reflect.Value) { - to.SetFloat(localCommonConverter.Float64(from)) - } - case "Time", "time.Time": - convertFunc = func(from any, to reflect.Value) { - *to.Addr().Interface().(*time.Time) = localCommonConverter.Time(from) - } - case "GTime", "gtime.Time": - convertFunc = func(from any, to reflect.Value) { - v := localCommonConverter.GTime(from) - if v == nil { - v = gtime.New() - } - *to.Addr().Interface().(*gtime.Time) = *v - } - case "bool": - convertFunc = func(from any, to reflect.Value) { - to.SetBool(localCommonConverter.Bool(from)) - } - case "[]byte": - convertFunc = func(from any, to reflect.Value) { - to.SetBytes(localCommonConverter.Bytes(from)) - } - default: - return nil - } - return convertFunc + return nil } func (csi *CachedStructInfo) genPriorityTagAndFieldName( @@ -188,21 +175,19 @@ func (csi *CachedStructInfo) genPriorityTagAndFieldName( return } +func (csi *CachedStructInfo) genPtrConvertFunc(convertFunc AnyConvertFunc) AnyConvertFunc { + return func(from any, to reflect.Value) error { + if to.IsNil() { + to.Set(reflect.New(to.Type().Elem())) + } + return convertFunc(from, to.Elem()) + } +} + func (csi *CachedStructInfo) checkTypeHasCustomConvert(fieldType reflect.Type) bool { if fieldType.Kind() == reflect.Ptr { fieldType = fieldType.Elem() } - _, ok := customConvertTypeMap[fieldType] + _, ok := csi.customConvertTypeMap[fieldType] return ok } - -func (csi *CachedStructInfo) genPtrConvertFunc( - convertFunc func(from any, to reflect.Value), -) func(from any, to reflect.Value) { - return func(from any, to reflect.Value) { - if to.IsNil() { - to.Set(reflect.New(to.Type().Elem())) - } - convertFunc(from, to.Elem()) - } -} From da93839fedbb1c026ffb83d238ed3b4d7a58182d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 2 Mar 2025 03:15:56 +0000 Subject: [PATCH 22/48] Apply gci import order changes --- contrib/drivers/mysql/mysql_z_unit_issue_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/drivers/mysql/mysql_z_unit_issue_test.go b/contrib/drivers/mysql/mysql_z_unit_issue_test.go index 388fa46e2f3..019d6042ed6 100644 --- a/contrib/drivers/mysql/mysql_z_unit_issue_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_issue_test.go @@ -1741,7 +1741,7 @@ func Test_Issue4086(t *testing.T) { }, }) }) -return + return gtest.C(t, func(t *gtest.T) { type ProxyParam struct { ProxyId int64 `json:"proxyId" orm:"proxy_id"` From d5e786ce930f4589dc27914bc3c49ce0ccdcbdee Mon Sep 17 00:00:00 2001 From: John Guo Date: Sun, 2 Mar 2025 13:09:40 +0800 Subject: [PATCH 23/48] up --- util/gconv/gconv.go | 15 +- util/gconv/gconv_basic.go | 281 +------- util/gconv/gconv_convert.go | 326 +-------- util/gconv/gconv_convert_config.go | 99 --- util/gconv/gconv_converter.go | 430 +++++++++++- util/gconv/gconv_converter_bool.go | 74 ++ util/gconv/gconv_converter_builtin.go | 39 +- util/gconv/gconv_converter_bytes.go | 67 ++ util/gconv/gconv_converter_float.go | 145 ++++ util/gconv/gconv_converter_int.go | 152 +++++ util/gconv/gconv_converter_map.go | 504 ++++++++++++++ util/gconv/gconv_converter_maps.go | 7 + util/gconv/gconv_converter_maptomap.go | 126 ++++ util/gconv/gconv_converter_maptomaps.go | 120 ++++ util/gconv/gconv_converter_rune.go | 29 + util/gconv/gconv_converter_scan.go | 336 +++++++++ util/gconv/gconv_converter_string.go | 135 ++++ util/gconv/gconv_converter_struct.go | 628 +++++++++++++++++ util/gconv/gconv_converter_structs.go | 115 ++++ util/gconv/gconv_converter_time.go | 111 +++ util/gconv/gconv_converter_uint.go | 156 +++++ util/gconv/gconv_float.go | 134 +--- util/gconv/gconv_int.go | 155 +---- util/gconv/gconv_map.go | 515 +------------- util/gconv/gconv_maptomap.go | 121 ---- util/gconv/gconv_maptomaps.go | 115 +--- util/gconv/gconv_scan.go | 332 +-------- util/gconv/gconv_struct.go | 635 +----------------- util/gconv/gconv_structs.go | 116 +--- util/gconv/gconv_time.go | 73 +- util/gconv/gconv_uint.go | 159 +---- util/gconv/gconv_z_bench_struct_test.go | 2 +- .../gconv/internal/structcache/structcache.go | 31 +- .../structcache/structcache_cached.go | 2 +- .../structcache_cached_struct_info.go | 14 +- 35 files changed, 3214 insertions(+), 3085 deletions(-) delete mode 100644 util/gconv/gconv_convert_config.go create mode 100644 util/gconv/gconv_converter_bool.go create mode 100644 util/gconv/gconv_converter_bytes.go create mode 100644 util/gconv/gconv_converter_float.go create mode 100644 util/gconv/gconv_converter_int.go create mode 100644 util/gconv/gconv_converter_map.go create mode 100644 util/gconv/gconv_converter_maps.go create mode 100644 util/gconv/gconv_converter_maptomap.go create mode 100644 util/gconv/gconv_converter_maptomaps.go create mode 100644 util/gconv/gconv_converter_rune.go create mode 100644 util/gconv/gconv_converter_scan.go create mode 100644 util/gconv/gconv_converter_string.go create mode 100644 util/gconv/gconv_converter_struct.go create mode 100644 util/gconv/gconv_converter_structs.go create mode 100644 util/gconv/gconv_converter_time.go create mode 100644 util/gconv/gconv_converter_uint.go diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index 426afd40147..00748eb06ec 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -32,6 +32,17 @@ var ( type IUnmarshalValue = localinterface.IUnmarshalValue var ( - // defaultConvertConfig is the default configuration for type converting. - defaultConvertConfig = NewConvertConfig() + // defaultConverter is the default management object converting. + defaultConverter = NewConverter() ) + +// RegisterConverter registers custom converter. +// Deprecated: use RegisterTypeConverterFunc instead for clear +func RegisterConverter(fn any) (err error) { + return defaultConverter.RegisterTypeConverterFunc(fn) +} + +// RegisterTypeConverterFunc registers custom converter. +func RegisterTypeConverterFunc(fn any) (err error) { + return defaultConverter.RegisterTypeConverterFunc(fn) +} diff --git a/util/gconv/gconv_basic.go b/util/gconv/gconv_basic.go index 03449231e3d..d4ab35eaf2f 100644 --- a/util/gconv/gconv_basic.go +++ b/util/gconv/gconv_basic.go @@ -6,309 +6,40 @@ package gconv -import ( - "fmt" - "math" - "reflect" - "strconv" - "strings" - "time" - - "github.com/gogf/gf/v2/encoding/gbinary" - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/reflection" - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" -) - // Byte converts `any` to byte. func Byte(any any) byte { - v, _ := doByte(any) + v, _ := defaultConverter.Uint8(any) return v } -func doByte(any any) (byte, error) { - if v, ok := any.(byte); ok { - return v, nil - } - return doUint8(any) -} - // Bytes converts `any` to []byte. func Bytes(any any) []byte { - v, _ := doBytes(any) + v, _ := defaultConverter.Bytes(any) return v } -func doBytes(any any) ([]byte, error) { - if empty.IsNil(any) { - return nil, nil - } - switch value := any.(type) { - case string: - return []byte(value), nil - - case []byte: - return value, nil - - default: - if f, ok := value.(localinterface.IBytes); ok { - return f.Bytes(), nil - } - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Map: - bytes, err := json.Marshal(any) - if err != nil { - return nil, err - } - return bytes, nil - - case reflect.Array, reflect.Slice: - var ( - ok = true - bytes = make([]byte, originValueAndKind.OriginValue.Len()) - ) - for i := range bytes { - int32Value, err := doInt32(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil { - return nil, err - } - if int32Value < 0 || int32Value > math.MaxUint8 { - ok = false - break - } - bytes[i] = byte(int32Value) - } - if ok { - return bytes, nil - } - default: - } - return gbinary.Encode(any), nil - } -} - // Rune converts `any` to rune. func Rune(any any) rune { - v, _ := doRune(any) + v, _ := defaultConverter.Rune(any) return v } -func doRune(any any) (rune, error) { - if v, ok := any.(rune); ok { - return v, nil - } - v, err := doInt32(any) - if err != nil { - return 0, err - } - return v, nil -} - // Runes converts `any` to []rune. func Runes(any any) []rune { - v, _ := doRunes(any) + v, _ := defaultConverter.Runes(any) return v } -func doRunes(any any) ([]rune, error) { - if v, ok := any.([]rune); ok { - return v, nil - } - s, err := doString(any) - if err != nil { - return nil, err - } - return []rune(s), nil -} - // String converts `any` to string. // It's most commonly used converting function. func String(any any) string { - v, _ := doString(any) + v, _ := defaultConverter.String(any) return v } -func doString(any any) (string, error) { - if empty.IsNil(any) { - return "", nil - } - switch value := any.(type) { - case int: - return strconv.Itoa(value), nil - case int8: - return strconv.Itoa(int(value)), nil - case int16: - return strconv.Itoa(int(value)), nil - case int32: - return strconv.Itoa(int(value)), nil - case int64: - return strconv.FormatInt(value, 10), nil - case uint: - return strconv.FormatUint(uint64(value), 10), nil - case uint8: - return strconv.FormatUint(uint64(value), 10), nil - case uint16: - return strconv.FormatUint(uint64(value), 10), nil - case uint32: - return strconv.FormatUint(uint64(value), 10), nil - case uint64: - return strconv.FormatUint(value, 10), nil - case float32: - return strconv.FormatFloat(float64(value), 'f', -1, 32), nil - case float64: - return strconv.FormatFloat(value, 'f', -1, 64), nil - case bool: - return strconv.FormatBool(value), nil - case string: - return value, nil - case []byte: - return string(value), nil - case complex64, complex128: - return fmt.Sprintf("%v", value), nil - case time.Time: - if value.IsZero() { - return "", nil - } - return value.String(), nil - case *time.Time: - if value == nil { - return "", nil - } - return value.String(), nil - case gtime.Time: - if value.IsZero() { - return "", nil - } - return value.String(), nil - case *gtime.Time: - if value == nil { - return "", nil - } - return value.String(), nil - default: - if f, ok := value.(localinterface.IString); ok { - // If the variable implements the String() interface, - // then use that interface to perform the conversion - return f.String(), nil - } - if f, ok := value.(localinterface.IError); ok { - // If the variable implements the Error() interface, - // then use that interface to perform the conversion - return f.Error(), nil - } - // Reflect checks. - var ( - rv = reflect.ValueOf(value) - kind = rv.Kind() - ) - switch kind { - case - reflect.Chan, - reflect.Map, - reflect.Slice, - reflect.Func, - reflect.Interface, - reflect.UnsafePointer: - if rv.IsNil() { - return "", nil - } - case reflect.String: - return rv.String(), nil - case reflect.Ptr: - if rv.IsNil() { - return "", nil - } - return doString(rv.Elem().Interface()) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return strconv.FormatInt(rv.Int(), 10), nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return strconv.FormatUint(rv.Uint(), 10), nil - case reflect.Uintptr: - return strconv.FormatUint(rv.Uint(), 10), nil - case reflect.Float32, reflect.Float64: - return strconv.FormatFloat(rv.Float(), 'f', -1, 64), nil - case reflect.Bool: - return strconv.FormatBool(rv.Bool()), nil - default: - } - // Finally, we use json.Marshal to convert. - jsonContent, err := json.Marshal(value) - if err != nil { - return fmt.Sprint(value), gerror.WrapCodef( - gcode.CodeInvalidParameter, err, "error marshaling value to JSON for: %v", value, - ) - } - return string(jsonContent), nil - } -} - // Bool converts `any` to bool. // It returns false if `any` is: false, "", 0, "false", "off", "no", empty slice/map. func Bool(any any) bool { - v, _ := doBool(any) + v, _ := defaultConverter.Bool(any) return v } - -func doBool(any any) (bool, error) { - if empty.IsNil(any) { - return false, nil - } - switch value := any.(type) { - case bool: - return value, nil - case []byte: - if _, ok := emptyStringMap[strings.ToLower(string(value))]; ok { - return false, nil - } - return true, nil - case string: - if _, ok := emptyStringMap[strings.ToLower(value)]; ok { - return false, nil - } - return true, nil - default: - if f, ok := value.(localinterface.IBool); ok { - return f.Bool(), nil - } - rv := reflect.ValueOf(any) - switch rv.Kind() { - case reflect.Ptr: - if rv.IsNil() { - return false, nil - } - if rv.Type().Elem().Kind() == reflect.Bool { - return rv.Elem().Bool(), nil - } - return doBool(rv.Elem().Interface()) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return rv.Int() != 0, nil - case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return rv.Uint() != 0, nil - case reflect.Float32, reflect.Float64: - return rv.Float() != 0, nil - case reflect.Bool: - return rv.Bool(), nil - // TODO:(Map,Array,Slice,Struct) It might panic here for these types. - case reflect.Map, reflect.Array: - fallthrough - case reflect.Slice: - return rv.Len() != 0, nil - case reflect.Struct: - return true, nil - default: - s, err := doString(any) - if err != nil { - return false, err - } - if _, ok := emptyStringMap[strings.ToLower(s)]; ok { - return false, nil - } - return true, nil - } - } -} diff --git a/util/gconv/gconv_convert.go b/util/gconv/gconv_convert.go index 2cd67d3e8bf..6603469a23d 100644 --- a/util/gconv/gconv_convert.go +++ b/util/gconv/gconv_convert.go @@ -7,22 +7,15 @@ package gconv import ( - "context" "reflect" - "time" - - "github.com/gogf/gf/v2/internal/intlog" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/os/gtime" ) // Convert converts the variable `fromValue` to the type `toTypeName`, the type `toTypeName` is specified by string. // // The optional parameter `extraParams` is used for additional necessary parameter for this conversion. // It supports common basic types conversion as its conversion based on type name string. -func Convert(fromValue interface{}, toTypeName string, extraParams ...interface{}) interface{} { - return doConvert( - defaultConvertConfig, +func Convert(fromValue any, toTypeName string, extraParams ...any) any { + return defaultConverter.doConvert( doConvertInput{ FromValue: fromValue, ToTypeName: toTypeName, @@ -36,15 +29,14 @@ func Convert(fromValue interface{}, toTypeName string, extraParams ...interface{ // // The optional parameter `extraParams` is used for additional necessary parameter for this conversion. // It supports common basic types conversion as its conversion based on type name string. -func ConvertWithRefer(fromValue interface{}, referValue interface{}, extraParams ...interface{}) interface{} { +func ConvertWithRefer(fromValue any, referValue any, extraParams ...any) any { var referValueRf reflect.Value if v, ok := referValue.(reflect.Value); ok { referValueRf = v } else { referValueRf = reflect.ValueOf(referValue) } - return doConvert( - defaultConvertConfig, + return defaultConverter.doConvert( doConvertInput{ FromValue: fromValue, ToTypeName: referValueRf.Type().String(), @@ -53,313 +45,3 @@ func ConvertWithRefer(fromValue interface{}, referValue interface{}, extraParams }, ) } - -type doConvertInput struct { - FromValue interface{} // Value that is converted from. - ToTypeName string // Target value type name in string. - ReferValue interface{} // Referred value, a value in type `ToTypeName`. Note that its type might be reflect.Value. - Extra []interface{} // Extra values for implementing the converting. - - // Marks that the value is already converted and set to `ReferValue`. Caller can ignore the returned result. - // It is an attribute for internal usage purpose. - alreadySetToReferValue bool -} - -// doConvert does commonly use types converting. -func doConvert(cf *ConvertConfig, in doConvertInput) (convertedValue interface{}) { - switch in.ToTypeName { - case "int": - return Int(in.FromValue) - case "*int": - if _, ok := in.FromValue.(*int); ok { - return in.FromValue - } - v := Int(in.FromValue) - return &v - - case "int8": - return Int8(in.FromValue) - case "*int8": - if _, ok := in.FromValue.(*int8); ok { - return in.FromValue - } - v := Int8(in.FromValue) - return &v - - case "int16": - return Int16(in.FromValue) - case "*int16": - if _, ok := in.FromValue.(*int16); ok { - return in.FromValue - } - v := Int16(in.FromValue) - return &v - - case "int32": - return Int32(in.FromValue) - case "*int32": - if _, ok := in.FromValue.(*int32); ok { - return in.FromValue - } - v := Int32(in.FromValue) - return &v - - case "int64": - return Int64(in.FromValue) - case "*int64": - if _, ok := in.FromValue.(*int64); ok { - return in.FromValue - } - v := Int64(in.FromValue) - return &v - - case "uint": - return Uint(in.FromValue) - case "*uint": - if _, ok := in.FromValue.(*uint); ok { - return in.FromValue - } - v := Uint(in.FromValue) - return &v - - case "uint8": - return Uint8(in.FromValue) - case "*uint8": - if _, ok := in.FromValue.(*uint8); ok { - return in.FromValue - } - v := Uint8(in.FromValue) - return &v - - case "uint16": - return Uint16(in.FromValue) - case "*uint16": - if _, ok := in.FromValue.(*uint16); ok { - return in.FromValue - } - v := Uint16(in.FromValue) - return &v - - case "uint32": - return Uint32(in.FromValue) - case "*uint32": - if _, ok := in.FromValue.(*uint32); ok { - return in.FromValue - } - v := Uint32(in.FromValue) - return &v - - case "uint64": - return Uint64(in.FromValue) - case "*uint64": - if _, ok := in.FromValue.(*uint64); ok { - return in.FromValue - } - v := Uint64(in.FromValue) - return &v - - case "float32": - return Float32(in.FromValue) - case "*float32": - if _, ok := in.FromValue.(*float32); ok { - return in.FromValue - } - v := Float32(in.FromValue) - return &v - - case "float64": - return Float64(in.FromValue) - case "*float64": - if _, ok := in.FromValue.(*float64); ok { - return in.FromValue - } - v := Float64(in.FromValue) - return &v - - case "bool": - return Bool(in.FromValue) - case "*bool": - if _, ok := in.FromValue.(*bool); ok { - return in.FromValue - } - v := Bool(in.FromValue) - return &v - - case "string": - return String(in.FromValue) - case "*string": - if _, ok := in.FromValue.(*string); ok { - return in.FromValue - } - v := String(in.FromValue) - return &v - - case "[]byte": - return Bytes(in.FromValue) - case "[]int": - return Ints(in.FromValue) - case "[]int32": - return Int32s(in.FromValue) - case "[]int64": - return Int64s(in.FromValue) - case "[]uint": - return Uints(in.FromValue) - case "[]uint8": - return Bytes(in.FromValue) - case "[]uint32": - return Uint32s(in.FromValue) - case "[]uint64": - return Uint64s(in.FromValue) - case "[]float32": - return Float32s(in.FromValue) - case "[]float64": - return Float64s(in.FromValue) - case "[]string": - return Strings(in.FromValue) - - case "Time", "time.Time": - if len(in.Extra) > 0 { - return Time(in.FromValue, String(in.Extra[0])) - } - return Time(in.FromValue) - case "*time.Time": - var v time.Time - if len(in.Extra) > 0 { - v = Time(in.FromValue, String(in.Extra[0])) - } else { - if _, ok := in.FromValue.(*time.Time); ok { - return in.FromValue - } - v = Time(in.FromValue) - } - return &v - - case "GTime", "gtime.Time": - if len(in.Extra) > 0 { - if v := GTime(in.FromValue, String(in.Extra[0])); v != nil { - return *v - } else { - return *gtime.New() - } - } - if v := GTime(in.FromValue); v != nil { - return *v - } else { - return *gtime.New() - } - case "*gtime.Time": - if len(in.Extra) > 0 { - if v := GTime(in.FromValue, String(in.Extra[0])); v != nil { - return v - } else { - return gtime.New() - } - } - if v := GTime(in.FromValue); v != nil { - return v - } else { - return gtime.New() - } - - case "Duration", "time.Duration": - return Duration(in.FromValue) - case "*time.Duration": - if _, ok := in.FromValue.(*time.Duration); ok { - return in.FromValue - } - v := Duration(in.FromValue) - return &v - - case "map[string]string": - return MapStrStr(in.FromValue) - - case "map[string]interface {}": - return Map(in.FromValue) - - case "[]map[string]interface {}": - return Maps(in.FromValue) - - case "RawMessage", "json.RawMessage": - // issue 3449 - bytes, err := json.Marshal(in.FromValue) - if err != nil { - intlog.Errorf(context.TODO(), `%+v`, err) - } - return bytes - - default: - if in.ReferValue != nil { - var referReflectValue reflect.Value - if v, ok := in.ReferValue.(reflect.Value); ok { - referReflectValue = v - } else { - referReflectValue = reflect.ValueOf(in.ReferValue) - } - var fromReflectValue reflect.Value - if v, ok := in.FromValue.(reflect.Value); ok { - fromReflectValue = v - } else { - fromReflectValue = reflect.ValueOf(in.FromValue) - } - - // custom converter. - if dstReflectValue, ok, _ := cf.callCustomConverterWithRefer(fromReflectValue, referReflectValue); ok { - return dstReflectValue.Interface() - } - - defer func() { - if recover() != nil { - in.alreadySetToReferValue = false - if err := bindVarToReflectValue(cf, referReflectValue, in.FromValue, nil); err == nil { - in.alreadySetToReferValue = true - convertedValue = referReflectValue.Interface() - } - } - }() - switch referReflectValue.Kind() { - case reflect.Ptr: - // Type converting for custom type pointers. - // Eg: - // type PayMode int - // type Req struct{ - // Mode *PayMode - // } - // - // Struct(`{"Mode": 1000}`, &req) - originType := referReflectValue.Type().Elem() - switch originType.Kind() { - case reflect.Struct: - // Not support some kinds. - default: - in.ToTypeName = originType.Kind().String() - in.ReferValue = nil - refElementValue := reflect.ValueOf(doConvert(cf, in)) - originTypeValue := reflect.New(refElementValue.Type()).Elem() - originTypeValue.Set(refElementValue) - in.alreadySetToReferValue = true - return originTypeValue.Addr().Convert(referReflectValue.Type()).Interface() - } - - case reflect.Map: - var targetValue = reflect.New(referReflectValue.Type()).Elem() - if err := doMapToMap(cf, in.FromValue, targetValue); err == nil { - in.alreadySetToReferValue = true - } - return targetValue.Interface() - } - in.ToTypeName = referReflectValue.Kind().String() - in.ReferValue = nil - in.alreadySetToReferValue = true - convertedValue = reflect.ValueOf(doConvert(cf, in)).Convert(referReflectValue.Type()).Interface() - return convertedValue - } - return in.FromValue - } -} - -func doConvertWithReflectValueSet(cf *ConvertConfig, reflectValue reflect.Value, in doConvertInput) { - convertedValue := doConvert(cf, in) - if !in.alreadySetToReferValue { - reflectValue.Set(reflect.ValueOf(convertedValue)) - } -} diff --git a/util/gconv/gconv_convert_config.go b/util/gconv/gconv_convert_config.go deleted file mode 100644 index 82712c0776b..00000000000 --- a/util/gconv/gconv_convert_config.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package gconv - -import ( - "reflect" - "time" - - "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/util/gconv/internal/structcache" -) - -// CommonTypeConverter holds some converting functions of common types for internal usage. -type CommonTypeConverter = structcache.CommonTypeConverter - -type ( - converterInType = reflect.Type - converterOutType = reflect.Type - converterFunc = reflect.Value -) - -// ConvertConfig is the configuration for type converting. -type ConvertConfig struct { - internalConvertConfig *structcache.ConvertConfig - // customConverters for internal converter storing. - customConverters map[converterInType]map[converterOutType]converterFunc -} - -var ( - intType = reflect.TypeOf(0) - int8Type = reflect.TypeOf(int8(0)) - int16Type = reflect.TypeOf(int16(0)) - int32Type = reflect.TypeOf(int32(0)) - int64Type = reflect.TypeOf(int64(0)) - - uintType = reflect.TypeOf(uint(0)) - uint8Type = reflect.TypeOf(uint8(0)) - uint16Type = reflect.TypeOf(uint16(0)) - uint32Type = reflect.TypeOf(uint32(0)) - uint64Type = reflect.TypeOf(uint64(0)) - - float32Type = reflect.TypeOf(float32(0)) - float64Type = reflect.TypeOf(float64(0)) - - stringType = reflect.TypeOf("") - bytesType = reflect.TypeOf([]byte{}) - - boolType = reflect.TypeOf(false) - - timeType = reflect.TypeOf((*time.Time)(nil)).Elem() - gtimeType = reflect.TypeOf((*gtime.Time)(nil)).Elem() -) - -// NewConvertConfig creates and returns configuration management object for type converting. -func NewConvertConfig() *ConvertConfig { - cf := &ConvertConfig{ - internalConvertConfig: structcache.NewConvertConfig(), - customConverters: make(map[converterInType]map[converterOutType]converterFunc), - } - cf.registerBuiltInConverter() - return cf -} - -func (cf *ConvertConfig) registerBuiltInConverter() { - cf.registerAnyConvertFuncForTypes( - builtInAnyConvertFuncForInt64, intType, int8Type, int16Type, int32Type, int64Type, - ) - cf.registerAnyConvertFuncForTypes( - builtInAnyConvertFuncForUint64, uintType, uint8Type, uint16Type, uint32Type, uint64Type, - ) - cf.registerAnyConvertFuncForTypes( - builtInAnyConvertFuncForString, stringType, - ) - cf.registerAnyConvertFuncForTypes( - builtInAnyConvertFuncForFloat64, float32Type, float64Type, - ) - cf.registerAnyConvertFuncForTypes( - builtInAnyConvertFuncForBool, boolType, - ) - cf.registerAnyConvertFuncForTypes( - builtInAnyConvertFuncForBytes, bytesType, - ) - cf.registerAnyConvertFuncForTypes( - builtInAnyConvertFuncForTime, timeType, - ) - cf.registerAnyConvertFuncForTypes( - builtInAnyConvertFuncForGTime, gtimeType, - ) -} - -func (cf *ConvertConfig) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, types ...reflect.Type) { - for _, t := range types { - cf.internalConvertConfig.RegisterAnyConvertFunc(t, convertFunc) - } -} diff --git a/util/gconv/gconv_converter.go b/util/gconv/gconv_converter.go index 72337f00f47..2a4803cd32a 100644 --- a/util/gconv/gconv_converter.go +++ b/util/gconv/gconv_converter.go @@ -7,18 +7,99 @@ package gconv import ( + "context" "reflect" + "time" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/intlog" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv/internal/structcache" ) -// RegisterConverter registers custom converter. -func RegisterConverter(fn any) (err error) { - return defaultConvertConfig.RegisterConverter(fn) +type ( + converterInType = reflect.Type + converterOutType = reflect.Type + converterFunc = reflect.Value +) + +// Converter is the manager for type converting. +type Converter struct { + internalConvertConfig *structcache.ConvertConfig + typeConverterFuncMap map[converterInType]map[converterOutType]converterFunc +} + +var ( + intType = reflect.TypeOf(0) + int8Type = reflect.TypeOf(int8(0)) + int16Type = reflect.TypeOf(int16(0)) + int32Type = reflect.TypeOf(int32(0)) + int64Type = reflect.TypeOf(int64(0)) + + uintType = reflect.TypeOf(uint(0)) + uint8Type = reflect.TypeOf(uint8(0)) + uint16Type = reflect.TypeOf(uint16(0)) + uint32Type = reflect.TypeOf(uint32(0)) + uint64Type = reflect.TypeOf(uint64(0)) + + float32Type = reflect.TypeOf(float32(0)) + float64Type = reflect.TypeOf(float64(0)) + + stringType = reflect.TypeOf("") + bytesType = reflect.TypeOf([]byte{}) + + boolType = reflect.TypeOf(false) + + timeType = reflect.TypeOf((*time.Time)(nil)).Elem() + gtimeType = reflect.TypeOf((*gtime.Time)(nil)).Elem() +) + +// NewConverter creates and returns management object for type converting. +func NewConverter() *Converter { + cf := &Converter{ + internalConvertConfig: structcache.NewConvertConfig(), + typeConverterFuncMap: make(map[converterInType]map[converterOutType]converterFunc), + } + cf.registerBuiltInConverter() + return cf } -// RegisterConverter registers custom converter. +func (c *Converter) registerBuiltInConverter() { + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForInt64, intType, int8Type, int16Type, int32Type, int64Type, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForUint64, uintType, uint8Type, uint16Type, uint32Type, uint64Type, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForString, stringType, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForFloat64, float32Type, float64Type, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForBool, boolType, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForBytes, bytesType, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForTime, timeType, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForGTime, gtimeType, + ) +} + +func (c *Converter) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, types ...reflect.Type) { + for _, t := range types { + c.internalConvertConfig.RegisterAnyConvertFunc(t, convertFunc) + } +} + +// RegisterTypeConverterFunc registers custom converter. // It must be registered before you use this custom converting feature. // It is suggested to do it in boot procedure of the process. // @@ -26,7 +107,7 @@ func RegisterConverter(fn any) (err error) { // 1. The parameter `fn` must be defined as pattern `func(T1) (T2, error)`. // It will convert type `T1` to type `T2`. // 2. The `T1` should not be type of pointer, but the `T2` should be type of pointer. -func (cf *ConvertConfig) RegisterConverter(fn any) (err error) { +func (c *Converter) RegisterTypeConverterFunc(fn any) (err error) { var ( fnReflectType = reflect.TypeOf(fn) errType = reflect.TypeOf((*error)(nil)).Elem() @@ -65,10 +146,10 @@ func (cf *ConvertConfig) RegisterConverter(fn any) (err error) { return } - registeredOutTypeMap, ok := cf.customConverters[inType] + registeredOutTypeMap, ok := c.typeConverterFuncMap[inType] if !ok { registeredOutTypeMap = make(map[converterOutType]converterFunc) - cf.customConverters[inType] = registeredOutTypeMap + c.typeConverterFuncMap[inType] = registeredOutTypeMap } if _, ok = registeredOutTypeMap[outType]; ok { err = gerror.NewCodef( @@ -79,14 +160,14 @@ func (cf *ConvertConfig) RegisterConverter(fn any) (err error) { return } registeredOutTypeMap[outType] = reflect.ValueOf(fn) - cf.internalConvertConfig.RegisterCustomConvertType(outType) + c.internalConvertConfig.RegisterTypeConvertFunc(outType) return } -func (cf *ConvertConfig) getRegisteredConverterFuncAndSrcType( +func (c *Converter) getRegisteredConverterFuncAndSrcType( srcReflectValue, dstReflectValueForRefer reflect.Value, ) (f converterFunc, srcType reflect.Type, ok bool) { - if len(cf.customConverters) == 0 { + if len(c.typeConverterFuncMap) == 0 { return reflect.Value{}, nil, false } srcType = srcReflectValue.Type() @@ -95,7 +176,7 @@ func (cf *ConvertConfig) getRegisteredConverterFuncAndSrcType( } var registeredOutTypeMap map[converterOutType]converterFunc // firstly, it searches the map by input parameter type. - registeredOutTypeMap, ok = cf.customConverters[srcType] + registeredOutTypeMap, ok = c.typeConverterFuncMap[srcType] if !ok { return reflect.Value{}, nil, false } @@ -119,28 +200,28 @@ func (cf *ConvertConfig) getRegisteredConverterFuncAndSrcType( return } -func (cf *ConvertConfig) callCustomConverterWithRefer( +func (c *Converter) callCustomConverterWithRefer( srcReflectValue, referReflectValue reflect.Value, ) (dstReflectValue reflect.Value, converted bool, err error) { - registeredConverterFunc, srcType, ok := cf.getRegisteredConverterFuncAndSrcType(srcReflectValue, referReflectValue) + registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, referReflectValue) if !ok { return reflect.Value{}, false, nil } dstReflectValue = reflect.New(referReflectValue.Type()).Elem() - converted, err = cf.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) + converted, err = c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) return } // callCustomConverter call the custom converter. It will try some possible type. -func (cf *ConvertConfig) callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) { - registeredConverterFunc, srcType, ok := cf.getRegisteredConverterFuncAndSrcType(srcReflectValue, dstReflectValue) +func (c *Converter) callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) { + registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, dstReflectValue) if !ok { return false, nil } - return cf.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) + return c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) } -func (cf *ConvertConfig) doCallCustomConverter( +func (c *Converter) doCallCustomConverter( srcReflectValue reflect.Value, dstReflectValue reflect.Value, registeredConverterFunc converterFunc, @@ -181,3 +262,316 @@ func (cf *ConvertConfig) doCallCustomConverter( return converted, nil } + +type doConvertInput struct { + FromValue interface{} // Value that is converted from. + ToTypeName string // Target value type name in string. + ReferValue interface{} // Referred value, a value in type `ToTypeName`. Note that its type might be reflect.Value. + Extra []interface{} // Extra values for implementing the converting. + + // Marks that the value is already converted and set to `ReferValue`. Caller can ignore the returned result. + // It is an attribute for internal usage purpose. + alreadySetToReferValue bool +} + +// doConvert does commonly use types converting. +func (c *Converter) doConvert(in doConvertInput) (convertedValue interface{}) { + switch in.ToTypeName { + case "int": + return Int(in.FromValue) + case "*int": + if _, ok := in.FromValue.(*int); ok { + return in.FromValue + } + v := Int(in.FromValue) + return &v + + case "int8": + return Int8(in.FromValue) + case "*int8": + if _, ok := in.FromValue.(*int8); ok { + return in.FromValue + } + v := Int8(in.FromValue) + return &v + + case "int16": + return Int16(in.FromValue) + case "*int16": + if _, ok := in.FromValue.(*int16); ok { + return in.FromValue + } + v := Int16(in.FromValue) + return &v + + case "int32": + return Int32(in.FromValue) + case "*int32": + if _, ok := in.FromValue.(*int32); ok { + return in.FromValue + } + v := Int32(in.FromValue) + return &v + + case "int64": + return Int64(in.FromValue) + case "*int64": + if _, ok := in.FromValue.(*int64); ok { + return in.FromValue + } + v := Int64(in.FromValue) + return &v + + case "uint": + return Uint(in.FromValue) + case "*uint": + if _, ok := in.FromValue.(*uint); ok { + return in.FromValue + } + v := Uint(in.FromValue) + return &v + + case "uint8": + return Uint8(in.FromValue) + case "*uint8": + if _, ok := in.FromValue.(*uint8); ok { + return in.FromValue + } + v := Uint8(in.FromValue) + return &v + + case "uint16": + return Uint16(in.FromValue) + case "*uint16": + if _, ok := in.FromValue.(*uint16); ok { + return in.FromValue + } + v := Uint16(in.FromValue) + return &v + + case "uint32": + return Uint32(in.FromValue) + case "*uint32": + if _, ok := in.FromValue.(*uint32); ok { + return in.FromValue + } + v := Uint32(in.FromValue) + return &v + + case "uint64": + return Uint64(in.FromValue) + case "*uint64": + if _, ok := in.FromValue.(*uint64); ok { + return in.FromValue + } + v := Uint64(in.FromValue) + return &v + + case "float32": + return Float32(in.FromValue) + case "*float32": + if _, ok := in.FromValue.(*float32); ok { + return in.FromValue + } + v := Float32(in.FromValue) + return &v + + case "float64": + return Float64(in.FromValue) + case "*float64": + if _, ok := in.FromValue.(*float64); ok { + return in.FromValue + } + v := Float64(in.FromValue) + return &v + + case "bool": + return Bool(in.FromValue) + case "*bool": + if _, ok := in.FromValue.(*bool); ok { + return in.FromValue + } + v := Bool(in.FromValue) + return &v + + case "string": + return String(in.FromValue) + case "*string": + if _, ok := in.FromValue.(*string); ok { + return in.FromValue + } + v := String(in.FromValue) + return &v + + case "[]byte": + return Bytes(in.FromValue) + case "[]int": + return Ints(in.FromValue) + case "[]int32": + return Int32s(in.FromValue) + case "[]int64": + return Int64s(in.FromValue) + case "[]uint": + return Uints(in.FromValue) + case "[]uint8": + return Bytes(in.FromValue) + case "[]uint32": + return Uint32s(in.FromValue) + case "[]uint64": + return Uint64s(in.FromValue) + case "[]float32": + return Float32s(in.FromValue) + case "[]float64": + return Float64s(in.FromValue) + case "[]string": + return Strings(in.FromValue) + + case "Time", "time.Time": + if len(in.Extra) > 0 { + return Time(in.FromValue, String(in.Extra[0])) + } + return Time(in.FromValue) + case "*time.Time": + var v time.Time + if len(in.Extra) > 0 { + v = Time(in.FromValue, String(in.Extra[0])) + } else { + if _, ok := in.FromValue.(*time.Time); ok { + return in.FromValue + } + v = Time(in.FromValue) + } + return &v + + case "GTime", "gtime.Time": + if len(in.Extra) > 0 { + if v := GTime(in.FromValue, String(in.Extra[0])); v != nil { + return *v + } else { + return *gtime.New() + } + } + if v := GTime(in.FromValue); v != nil { + return *v + } else { + return *gtime.New() + } + case "*gtime.Time": + if len(in.Extra) > 0 { + if v := GTime(in.FromValue, String(in.Extra[0])); v != nil { + return v + } else { + return gtime.New() + } + } + if v := GTime(in.FromValue); v != nil { + return v + } else { + return gtime.New() + } + + case "Duration", "time.Duration": + return Duration(in.FromValue) + case "*time.Duration": + if _, ok := in.FromValue.(*time.Duration); ok { + return in.FromValue + } + v := Duration(in.FromValue) + return &v + + case "map[string]string": + return MapStrStr(in.FromValue) + + case "map[string]interface {}": + return Map(in.FromValue) + + case "[]map[string]interface {}": + return Maps(in.FromValue) + + case "RawMessage", "json.RawMessage": + // issue 3449 + bytes, err := json.Marshal(in.FromValue) + if err != nil { + intlog.Errorf(context.TODO(), `%+v`, err) + } + return bytes + + default: + if in.ReferValue != nil { + var referReflectValue reflect.Value + if v, ok := in.ReferValue.(reflect.Value); ok { + referReflectValue = v + } else { + referReflectValue = reflect.ValueOf(in.ReferValue) + } + var fromReflectValue reflect.Value + if v, ok := in.FromValue.(reflect.Value); ok { + fromReflectValue = v + } else { + fromReflectValue = reflect.ValueOf(in.FromValue) + } + + // custom converter. + if dstReflectValue, ok, _ := c.callCustomConverterWithRefer(fromReflectValue, referReflectValue); ok { + return dstReflectValue.Interface() + } + + defer func() { + if recover() != nil { + in.alreadySetToReferValue = false + if err := c.bindVarToReflectValue(referReflectValue, in.FromValue, nil); err == nil { + in.alreadySetToReferValue = true + convertedValue = referReflectValue.Interface() + } + } + }() + switch referReflectValue.Kind() { + case reflect.Ptr: + // Type converting for custom type pointers. + // Eg: + // type PayMode int + // type Req struct{ + // Mode *PayMode + // } + // + // Struct(`{"Mode": 1000}`, &req) + originType := referReflectValue.Type().Elem() + switch originType.Kind() { + case reflect.Struct: + // Not support some kinds. + default: + in.ToTypeName = originType.Kind().String() + in.ReferValue = nil + refElementValue := reflect.ValueOf(c.doConvert(in)) + originTypeValue := reflect.New(refElementValue.Type()).Elem() + originTypeValue.Set(refElementValue) + in.alreadySetToReferValue = true + return originTypeValue.Addr().Convert(referReflectValue.Type()).Interface() + } + + case reflect.Map: + var targetValue = reflect.New(referReflectValue.Type()).Elem() + if err := c.MapToMap(in.FromValue, targetValue); err == nil { + in.alreadySetToReferValue = true + } + return targetValue.Interface() + + default: + + } + in.ToTypeName = referReflectValue.Kind().String() + in.ReferValue = nil + in.alreadySetToReferValue = true + convertedValue = reflect.ValueOf(c.doConvert(in)).Convert(referReflectValue.Type()).Interface() + return convertedValue + } + return in.FromValue + } +} + +func (c *Converter) doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput) { + convertedValue := c.doConvert(in) + if !in.alreadySetToReferValue { + reflectValue.Set(reflect.ValueOf(convertedValue)) + } +} diff --git a/util/gconv/gconv_converter_bool.go b/util/gconv/gconv_converter_bool.go new file mode 100644 index 00000000000..94e26bea237 --- /dev/null +++ b/util/gconv/gconv_converter_bool.go @@ -0,0 +1,74 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + "strings" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +func (c *Converter) Bool(any any) (bool, error) { + if empty.IsNil(any) { + return false, nil + } + switch value := any.(type) { + case bool: + return value, nil + case []byte: + if _, ok := emptyStringMap[strings.ToLower(string(value))]; ok { + return false, nil + } + return true, nil + case string: + if _, ok := emptyStringMap[strings.ToLower(value)]; ok { + return false, nil + } + return true, nil + default: + if f, ok := value.(localinterface.IBool); ok { + return f.Bool(), nil + } + rv := reflect.ValueOf(any) + switch rv.Kind() { + case reflect.Ptr: + if rv.IsNil() { + return false, nil + } + if rv.Type().Elem().Kind() == reflect.Bool { + return rv.Elem().Bool(), nil + } + return c.Bool(rv.Elem().Interface()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return rv.Int() != 0, nil + case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return rv.Uint() != 0, nil + case reflect.Float32, reflect.Float64: + return rv.Float() != 0, nil + case reflect.Bool: + return rv.Bool(), nil + // TODO:(Map,Array,Slice,Struct) It might panic here for these types. + case reflect.Map, reflect.Array: + fallthrough + case reflect.Slice: + return rv.Len() != 0, nil + case reflect.Struct: + return true, nil + default: + s, err := c.String(any) + if err != nil { + return false, err + } + if _, ok := emptyStringMap[strings.ToLower(s)]; ok { + return false, nil + } + return true, nil + } + } +} diff --git a/util/gconv/gconv_converter_builtin.go b/util/gconv/gconv_converter_builtin.go index 1d2e00594d9..5009e6d462f 100644 --- a/util/gconv/gconv_converter_builtin.go +++ b/util/gconv/gconv_converter_builtin.go @@ -13,8 +13,8 @@ import ( "github.com/gogf/gf/v2/os/gtime" ) -func builtInAnyConvertFuncForInt64(from any, to reflect.Value) error { - v, err := doInt64(from) +func (c *Converter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) error { + v, err := c.Int64(from) if err != nil { return err } @@ -22,8 +22,8 @@ func builtInAnyConvertFuncForInt64(from any, to reflect.Value) error { return nil } -func builtInAnyConvertFuncForUint64(from any, to reflect.Value) error { - v, err := doUint64(from) +func (c *Converter) builtInAnyConvertFuncForUint64(from any, to reflect.Value) error { + v, err := c.Uint64(from) if err != nil { return err } @@ -31,8 +31,8 @@ func builtInAnyConvertFuncForUint64(from any, to reflect.Value) error { return nil } -func builtInAnyConvertFuncForString(from any, to reflect.Value) error { - v, err := doString(from) +func (c *Converter) builtInAnyConvertFuncForString(from any, to reflect.Value) error { + v, err := c.String(from) if err != nil { return err } @@ -40,8 +40,8 @@ func builtInAnyConvertFuncForString(from any, to reflect.Value) error { return nil } -func builtInAnyConvertFuncForFloat64(from any, to reflect.Value) error { - v, err := doFloat64(from) +func (c *Converter) builtInAnyConvertFuncForFloat64(from any, to reflect.Value) error { + v, err := c.Float64(from) if err != nil { return err } @@ -49,8 +49,8 @@ func builtInAnyConvertFuncForFloat64(from any, to reflect.Value) error { return nil } -func builtInAnyConvertFuncForBool(from any, to reflect.Value) error { - v, err := doBool(from) +func (c *Converter) builtInAnyConvertFuncForBool(from any, to reflect.Value) error { + v, err := c.Bool(from) if err != nil { return err } @@ -58,8 +58,8 @@ func builtInAnyConvertFuncForBool(from any, to reflect.Value) error { return nil } -func builtInAnyConvertFuncForBytes(from any, to reflect.Value) error { - v, err := doBytes(from) +func (c *Converter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) error { + v, err := c.Bytes(from) if err != nil { return err } @@ -67,13 +67,20 @@ func builtInAnyConvertFuncForBytes(from any, to reflect.Value) error { return nil } -func builtInAnyConvertFuncForTime(from any, to reflect.Value) error { - *to.Addr().Interface().(*time.Time) = Time(from) +func (c *Converter) builtInAnyConvertFuncForTime(from any, to reflect.Value) error { + t, err := c.Time(from) + if err != nil { + return err + } + *to.Addr().Interface().(*time.Time) = t return nil } -func builtInAnyConvertFuncForGTime(from any, to reflect.Value) error { - v := GTime(from) +func (c *Converter) builtInAnyConvertFuncForGTime(from any, to reflect.Value) error { + v, err := c.GTime(from) + if err != nil { + return err + } if v == nil { v = gtime.New() } diff --git a/util/gconv/gconv_converter_bytes.go b/util/gconv/gconv_converter_bytes.go new file mode 100644 index 00000000000..3237bd4bbfd --- /dev/null +++ b/util/gconv/gconv_converter_bytes.go @@ -0,0 +1,67 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "math" + "reflect" + + "github.com/gogf/gf/v2/encoding/gbinary" + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/reflection" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +func (c *Converter) Bytes(any any) ([]byte, error) { + if empty.IsNil(any) { + return nil, nil + } + switch value := any.(type) { + case string: + return []byte(value), nil + + case []byte: + return value, nil + + default: + if f, ok := value.(localinterface.IBytes); ok { + return f.Bytes(), nil + } + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Map: + bytes, err := json.Marshal(any) + if err != nil { + return nil, err + } + return bytes, nil + + case reflect.Array, reflect.Slice: + var ( + ok = true + bytes = make([]byte, originValueAndKind.OriginValue.Len()) + ) + for i := range bytes { + int32Value, err := c.Int32(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil { + return nil, err + } + if int32Value < 0 || int32Value > math.MaxUint8 { + ok = false + break + } + bytes[i] = byte(int32Value) + } + if ok { + return bytes, nil + } + default: + } + return gbinary.Encode(any), nil + } +} diff --git a/util/gconv/gconv_converter_float.go b/util/gconv/gconv_converter_float.go new file mode 100644 index 00000000000..3c186ab5669 --- /dev/null +++ b/util/gconv/gconv_converter_float.go @@ -0,0 +1,145 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + "strconv" + + "github.com/gogf/gf/v2/encoding/gbinary" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +func (c *Converter) Float32(any any) (float32, error) { + if empty.IsNil(any) { + return 0, nil + } + switch value := any.(type) { + case float32: + return value, nil + case float64: + return float32(value), nil + case []byte: + // TODO: It might panic here for these types. + return gbinary.DecodeToFloat32(value), nil + default: + rv := reflect.ValueOf(any) + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return float32(rv.Int()), nil + case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return float32(rv.Uint()), nil + case reflect.Float32, reflect.Float64: + return float32(rv.Float()), nil + case reflect.Bool: + if rv.Bool() { + return 1, nil + } + return 0, nil + case reflect.String: + f, err := strconv.ParseFloat(rv.String(), 32) + if err != nil { + return 0, gerror.WrapCodef( + gcode.CodeInvalidParameter, err, "converting string to float32 failed for: %v", any, + ) + } + return float32(f), nil + case reflect.Ptr: + if rv.IsNil() { + return 0, nil + } + if f, ok := value.(localinterface.IFloat32); ok { + return f.Float32(), nil + } + return c.Float32(rv.Elem().Interface()) + default: + if f, ok := value.(localinterface.IFloat32); ok { + return f.Float32(), nil + } + s, err := c.String(any) + if err != nil { + return 0, err + } + v, err := strconv.ParseFloat(s, 32) + if err != nil { + return 0, gerror.WrapCodef( + gcode.CodeInvalidParameter, err, "converting string to float32 failed for: %v", any, + ) + } + return float32(v), nil + } + } +} + +func (c *Converter) Float64(any any) (float64, error) { + if empty.IsNil(any) { + return 0, nil + } + switch value := any.(type) { + case float32: + return float64(value), nil + case float64: + return value, nil + case []byte: + // TODO: It might panic here for these types. + return gbinary.DecodeToFloat64(value), nil + default: + rv := reflect.ValueOf(any) + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return float64(rv.Int()), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return float64(rv.Uint()), nil + case reflect.Uintptr: + return float64(rv.Uint()), nil + case reflect.Float32, reflect.Float64: + // Please Note: + // When the type is float32 or a custom type defined based on float32, + // switching to float64 may result in a few extra decimal places. + return rv.Float(), nil + case reflect.Bool: + if rv.Bool() { + return 1, nil + } + return 0, nil + case reflect.String: + f, err := strconv.ParseFloat(rv.String(), 64) + if err != nil { + return 0, gerror.WrapCodef( + gcode.CodeInvalidParameter, err, "converting string to float64 failed for: %v", any, + ) + } + return f, nil + case reflect.Ptr: + if rv.IsNil() { + return 0, nil + } + if f, ok := value.(localinterface.IFloat64); ok { + return f.Float64(), nil + } + return c.Float64(rv.Elem().Interface()) + default: + if f, ok := value.(localinterface.IFloat64); ok { + return f.Float64(), nil + } + s, err := c.String(any) + if err != nil { + return 0, err + } + v, err := strconv.ParseFloat(s, 64) + if err != nil { + return 0, gerror.WrapCodef( + gcode.CodeInvalidParameter, err, "converting string to float64 failed for: %v", any, + ) + } + return v, nil + } + } +} diff --git a/util/gconv/gconv_converter_int.go b/util/gconv/gconv_converter_int.go new file mode 100644 index 00000000000..cc23f314f7f --- /dev/null +++ b/util/gconv/gconv_converter_int.go @@ -0,0 +1,152 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "math" + "reflect" + "strconv" + + "github.com/gogf/gf/v2/encoding/gbinary" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +func (c *Converter) Int(any any) (int, error) { + if v, ok := any.(int); ok { + return v, nil + } + v, err := c.Int64(any) + if err != nil { + return 0, err + } + return int(v), nil +} + +func (c *Converter) Int8(any any) (int8, error) { + if v, ok := any.(int8); ok { + return v, nil + } + v, err := c.Int64(any) + if err != nil { + return 0, err + } + return int8(v), nil +} + +func (c *Converter) Int16(any any) (int16, error) { + if v, ok := any.(int16); ok { + return v, nil + } + v, err := defaultConverter.Int64(any) + if err != nil { + return 0, err + } + return int16(v), nil +} + +func (c *Converter) Int32(any any) (int32, error) { + if v, ok := any.(int32); ok { + return v, nil + } + v, err := c.Int64(any) + if err != nil { + return 0, err + } + return int32(v), nil +} + +func (c *Converter) Int64(any any) (int64, error) { + if empty.IsNil(any) { + return 0, nil + } + if v, ok := any.(int64); ok { + return v, nil + } + rv := reflect.ValueOf(any) + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return rv.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return int64(rv.Uint()), nil + case reflect.Uintptr: + return int64(rv.Uint()), nil + case reflect.Float32, reflect.Float64: + return int64(rv.Float()), nil + case reflect.Bool: + if rv.Bool() { + return 1, nil + } + return 0, nil + case reflect.Ptr: + if rv.IsNil() { + return 0, nil + } + if f, ok := any.(localinterface.IInt64); ok { + return f.Int64(), nil + } + return c.Int64(rv.Elem().Interface()) + case reflect.Slice: + // TODO: It might panic here for these types. + if rv.Type().Elem().Kind() == reflect.Uint8 { + return gbinary.DecodeToInt64(rv.Bytes()), nil + } + case reflect.String: + var ( + s = rv.String() + isMinus = false + ) + if len(s) > 0 { + if s[0] == '-' { + isMinus = true + s = s[1:] + } else if s[0] == '+' { + s = s[1:] + } + } + // Hexadecimal. + if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') { + if v, e := strconv.ParseInt(s[2:], 16, 64); e == nil { + if isMinus { + return -v, nil + } + return v, nil + } + } + // Decimal. + if v, e := strconv.ParseInt(s, 10, 64); e == nil { + if isMinus { + return -v, nil + } + return v, nil + } + // Float64. + valueInt64, err := c.Float64(s) + if err != nil { + return 0, err + } + if math.IsNaN(valueInt64) { + return 0, nil + } else { + if isMinus { + return -int64(valueInt64), nil + } + return int64(valueInt64), nil + } + default: + if f, ok := any.(localinterface.IInt64); ok { + return f.Int64(), nil + } + } + return 0, gerror.NewCodef( + gcode.CodeInvalidParameter, + `unsupport value type for converting to int64: %v`, + reflect.TypeOf(any), + ) +} diff --git a/util/gconv/gconv_converter_map.go b/util/gconv/gconv_converter_map.go new file mode 100644 index 00000000000..13f7a3d221b --- /dev/null +++ b/util/gconv/gconv_converter_map.go @@ -0,0 +1,504 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + "strings" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" + "github.com/gogf/gf/v2/util/gtag" +) + +// MapConvert implements the map converting. +// It automatically checks and converts json string to map if `value` is string/[]byte. +// +// TODO completely implement the recursive converting for all types, especially the map. +func (c *Converter) doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool, option ...MapOption) map[string]interface{} { + if value == nil { + return nil + } + // It redirects to its underlying value if it has implemented interface iVal. + if v, ok := value.(localinterface.IVal); ok { + value = v.Val() + } + var ( + usedOption = getUsedMapOption(option...) + newTags = gtag.StructTagPriority + ) + if usedOption.Deep { + recursive = recursiveTypeTrue + } + switch len(usedOption.Tags) { + case 0: + // No need handling. + case 1: + newTags = append(strings.Split(usedOption.Tags[0], ","), gtag.StructTagPriority...) + default: + newTags = append(usedOption.Tags, gtag.StructTagPriority...) + } + // Assert the common combination of types, and finally it uses reflection. + dataMap := make(map[string]interface{}) + switch r := value.(type) { + case string: + // If it is a JSON string, automatically unmarshal it! + if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { + if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil { + return nil + } + } else { + return nil + } + case []byte: + // If it is a JSON string, automatically unmarshal it! + if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { + if err := json.UnmarshalUseNumber(r, &dataMap); err != nil { + return nil + } + } else { + return nil + } + case map[interface{}]interface{}: + recursiveOption := usedOption + recursiveOption.Tags = newTags + for k, v := range r { + dataMap[String(k)] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: v, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + }, + ) + } + case map[interface{}]string: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]int: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]uint: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]float32: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]float64: + for k, v := range r { + dataMap[String(k)] = v + } + case map[string]bool: + for k, v := range r { + dataMap[k] = v + } + case map[string]int: + for k, v := range r { + dataMap[k] = v + } + case map[string]uint: + for k, v := range r { + dataMap[k] = v + } + case map[string]float32: + for k, v := range r { + dataMap[k] = v + } + case map[string]float64: + for k, v := range r { + dataMap[k] = v + } + case map[string]string: + for k, v := range r { + dataMap[k] = v + } + case map[string]interface{}: + if recursive == recursiveTypeTrue { + recursiveOption := usedOption + recursiveOption.Tags = newTags + // A copy of current map. + for k, v := range r { + dataMap[k] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: v, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + }, + ) + } + } else { + // It returns the map directly without any changing. + return r + } + case map[int]interface{}: + recursiveOption := usedOption + recursiveOption.Tags = newTags + for k, v := range r { + dataMap[String(k)] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: v, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + }, + ) + } + case map[int]string: + for k, v := range r { + dataMap[String(k)] = v + } + case map[uint]string: + for k, v := range r { + dataMap[String(k)] = v + } + + default: + // Not a common type, it then uses reflection for conversion. + var reflectValue reflect.Value + if v, ok := value.(reflect.Value); ok { + reflectValue = v + } else { + reflectValue = reflect.ValueOf(value) + } + reflectKind := reflectValue.Kind() + // If it is a pointer, we should find its real data type. + for reflectKind == reflect.Ptr { + reflectValue = reflectValue.Elem() + reflectKind = reflectValue.Kind() + } + switch reflectKind { + // If `value` is type of array, it converts the value of even number index as its key and + // the value of odd number index as its corresponding value, for example: + // []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"} + // []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil} + case reflect.Slice, reflect.Array: + length := reflectValue.Len() + for i := 0; i < length; i += 2 { + if i+1 < length { + dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface() + } else { + dataMap[String(reflectValue.Index(i).Interface())] = nil + } + } + case reflect.Map, reflect.Struct, reflect.Interface: + recursiveOption := usedOption + recursiveOption.Tags = newTags + convertedValue := c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: true, + Value: value, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + MustMapReturn: mustMapReturn, + }, + ) + if m, ok := convertedValue.(map[string]interface{}); ok { + return m + } + return nil + default: + return nil + } + } + return dataMap +} + +func getUsedMapOption(option ...MapOption) MapOption { + var usedOption MapOption + if len(option) > 0 { + usedOption = option[0] + } + return usedOption +} + +type doMapConvertForMapOrStructValueInput struct { + IsRoot bool // It returns directly if it is not root and with no recursive converting. + Value interface{} // Current operation value. + RecursiveType recursiveType // The type from top function entry. + RecursiveOption bool // Whether convert recursively for `current` operation. + Option MapOption // Map converting option. + MustMapReturn bool // Must return map instead of Value when empty. +} + +func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} { + if !in.IsRoot && !in.RecursiveOption { + return in.Value + } + + var reflectValue reflect.Value + if v, ok := in.Value.(reflect.Value); ok { + reflectValue = v + in.Value = v.Interface() + } else { + reflectValue = reflect.ValueOf(in.Value) + } + reflectKind := reflectValue.Kind() + // If it is a pointer, we should find its real data type. + for reflectKind == reflect.Ptr { + reflectValue = reflectValue.Elem() + reflectKind = reflectValue.Kind() + } + switch reflectKind { + case reflect.Map: + var ( + mapIter = reflectValue.MapRange() + dataMap = make(map[string]interface{}) + ) + for mapIter.Next() { + var ( + mapKeyValue = mapIter.Value() + mapValue interface{} + ) + switch { + case mapKeyValue.IsZero(): + if utils.CanCallIsNil(mapKeyValue) && mapKeyValue.IsNil() { + // quick check for nil value. + mapValue = nil + } else { + // in case of: + // exception recovered: reflect: call of reflect.Value.Interface on zero Value + mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface() + } + default: + mapValue = mapKeyValue.Interface() + } + dataMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: mapValue, + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } + return dataMap + + case reflect.Struct: + var dataMap = make(map[string]interface{}) + // Map converting interface check. + if v, ok := in.Value.(localinterface.IMapStrAny); ok { + // Value copy, in case of concurrent safety. + for mapK, mapV := range v.MapStrAny() { + if in.RecursiveOption { + dataMap[mapK] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: mapV, + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } else { + dataMap[mapK] = mapV + } + } + if len(dataMap) > 0 { + return dataMap + } + } + // Using reflect for converting. + var ( + rtField reflect.StructField + rvField reflect.Value + reflectType = reflectValue.Type() // attribute value type. + mapKey = "" // mapKey may be the tag name or the struct attribute name. + ) + for i := 0; i < reflectValue.NumField(); i++ { + rtField = reflectType.Field(i) + rvField = reflectValue.Field(i) + // Only convert the public attributes. + fieldName := rtField.Name + if !utils.IsLetterUpper(fieldName[0]) { + continue + } + mapKey = "" + fieldTag := rtField.Tag + for _, tag := range in.Option.Tags { + if mapKey = fieldTag.Get(tag); mapKey != "" { + break + } + } + if mapKey == "" { + mapKey = fieldName + } else { + // Support json tag feature: -, omitempty + mapKey = strings.TrimSpace(mapKey) + if mapKey == "-" { + continue + } + array := strings.Split(mapKey, ",") + if len(array) > 1 { + switch strings.TrimSpace(array[1]) { + case "omitempty": + if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) { + continue + } else { + mapKey = strings.TrimSpace(array[0]) + } + default: + mapKey = strings.TrimSpace(array[0]) + } + } + if mapKey == "" { + mapKey = fieldName + } + } + if in.RecursiveOption || rtField.Anonymous { + // Do map converting recursively. + var ( + rvAttrField = rvField + rvAttrKind = rvField.Kind() + ) + if rvAttrKind == reflect.Ptr { + rvAttrField = rvField.Elem() + rvAttrKind = rvAttrField.Kind() + } + switch rvAttrKind { + case reflect.Struct: + // Embedded struct and has no fields, just ignores it. + // Eg: gmeta.Meta + if rvAttrField.Type().NumField() == 0 { + continue + } + var ( + hasNoTag = mapKey == fieldName + // DO NOT use rvAttrField.Interface() here, + // as it might be changed from pointer to struct. + rvInterface = rvField.Interface() + ) + switch { + case hasNoTag && rtField.Anonymous: + // It means this attribute field has no tag. + // Overwrite the attribute with sub-struct attribute fields. + anonymousValue := c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvInterface, + RecursiveType: in.RecursiveType, + RecursiveOption: true, + Option: in.Option, + }) + if m, ok := anonymousValue.(map[string]interface{}); ok { + for k, v := range m { + dataMap[k] = v + } + } else { + dataMap[mapKey] = rvInterface + } + + // It means this attribute field has desired tag. + case !hasNoTag && rtField.Anonymous: + dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvInterface, + RecursiveType: in.RecursiveType, + RecursiveOption: true, + Option: in.Option, + }) + + default: + dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvInterface, + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }) + } + + // The struct attribute is type of slice. + case reflect.Array, reflect.Slice: + length := rvAttrField.Len() + if length == 0 { + dataMap[mapKey] = rvAttrField.Interface() + break + } + array := make([]interface{}, length) + for arrayIndex := 0; arrayIndex < length; arrayIndex++ { + array[arrayIndex] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvAttrField.Index(arrayIndex).Interface(), + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } + dataMap[mapKey] = array + case reflect.Map: + var ( + mapIter = rvAttrField.MapRange() + nestedMap = make(map[string]interface{}) + ) + for mapIter.Next() { + nestedMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: mapIter.Value().Interface(), + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } + dataMap[mapKey] = nestedMap + default: + if rvField.IsValid() { + dataMap[mapKey] = reflectValue.Field(i).Interface() + } else { + dataMap[mapKey] = nil + } + } + } else { + // No recursive map value converting + if rvField.IsValid() { + dataMap[mapKey] = reflectValue.Field(i).Interface() + } else { + dataMap[mapKey] = nil + } + } + } + if !in.MustMapReturn && len(dataMap) == 0 { + return in.Value + } + return dataMap + + // The given value is type of slice. + case reflect.Array, reflect.Slice: + length := reflectValue.Len() + if length == 0 { + break + } + array := make([]interface{}, reflectValue.Len()) + for i := 0; i < length; i++ { + array[i] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: reflectValue.Index(i).Interface(), + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }) + } + return array + + default: + } + return in.Value +} diff --git a/util/gconv/gconv_converter_maps.go b/util/gconv/gconv_converter_maps.go new file mode 100644 index 00000000000..a5c4126a56b --- /dev/null +++ b/util/gconv/gconv_converter_maps.go @@ -0,0 +1,7 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv diff --git a/util/gconv/gconv_converter_maptomap.go b/util/gconv/gconv_converter_maptomap.go new file mode 100644 index 00000000000..46a6bf8795f --- /dev/null +++ b/util/gconv/gconv_converter_maptomap.go @@ -0,0 +1,126 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" +) + +// MapToMap converts any map type variable `params` to another map type variable `pointer`. +// +// The parameter `params` can be any type of map, like: +// map[string]string, map[string]struct, map[string]*struct, reflect.Value, etc. +// +// The parameter `pointer` should be type of *map, like: +// map[int]string, map[string]struct, map[string]*struct, reflect.Value, etc. +// +// The optional parameter `mapping` is used for struct attribute to map key mapping, which makes +// sense only if the items of original map `params` is type struct. +func (c *Converter) MapToMap(params any, pointer any, mapping ...map[string]string) (err error) { + var ( + paramsRv reflect.Value + paramsKind reflect.Kind + keyToAttributeNameMapping map[string]string + ) + if len(mapping) > 0 { + keyToAttributeNameMapping = mapping[0] + } + if v, ok := params.(reflect.Value); ok { + paramsRv = v + } else { + paramsRv = reflect.ValueOf(params) + } + paramsKind = paramsRv.Kind() + if paramsKind == reflect.Ptr { + paramsRv = paramsRv.Elem() + paramsKind = paramsRv.Kind() + } + if paramsKind != reflect.Map { + return c.MapToMap(Map(params), pointer, mapping...) + } + // Empty params map, no need continue. + if paramsRv.Len() == 0 { + return nil + } + var pointerRv reflect.Value + if v, ok := pointer.(reflect.Value); ok { + pointerRv = v + } else { + pointerRv = reflect.ValueOf(pointer) + } + pointerKind := pointerRv.Kind() + for pointerKind == reflect.Ptr { + pointerRv = pointerRv.Elem() + pointerKind = pointerRv.Kind() + } + if pointerKind != reflect.Map { + return gerror.NewCodef( + gcode.CodeInvalidParameter, + `destination pointer should be type of *map, but got: %s`, + pointerKind, + ) + } + defer func() { + // Catch the panic, especially the reflection operation panics. + if exception := recover(); exception != nil { + if v, ok := exception.(error); ok && gerror.HasStack(v) { + err = v + } else { + err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception) + } + } + }() + var ( + paramsKeys = paramsRv.MapKeys() + pointerKeyType = pointerRv.Type().Key() + pointerValueType = pointerRv.Type().Elem() + pointerValueKind = pointerValueType.Kind() + dataMap = reflect.MakeMapWithSize(pointerRv.Type(), len(paramsKeys)) + ) + // Retrieve the true element type of target map. + if pointerValueKind == reflect.Ptr { + pointerValueKind = pointerValueType.Elem().Kind() + } + for _, key := range paramsKeys { + mapValue := reflect.New(pointerValueType).Elem() + switch pointerValueKind { + case reflect.Map, reflect.Struct: + if err = c.Struct( + paramsRv.MapIndex(key).Interface(), mapValue, keyToAttributeNameMapping, "", + ); err != nil { + return err + } + default: + mapValue.Set( + reflect.ValueOf( + c.doConvert(doConvertInput{ + FromValue: paramsRv.MapIndex(key).Interface(), + ToTypeName: pointerValueType.String(), + ReferValue: mapValue, + Extra: nil, + }), + ), + ) + } + var mapKey = reflect.ValueOf( + c.doConvert( + doConvertInput{ + FromValue: key.Interface(), + ToTypeName: pointerKeyType.Name(), + ReferValue: reflect.New(pointerKeyType).Elem().Interface(), + Extra: nil, + }, + ), + ) + dataMap.SetMapIndex(mapKey, mapValue) + } + pointerRv.Set(dataMap) + return nil +} diff --git a/util/gconv/gconv_converter_maptomaps.go b/util/gconv/gconv_converter_maptomaps.go new file mode 100644 index 00000000000..2c33ebfdc0d --- /dev/null +++ b/util/gconv/gconv_converter_maptomaps.go @@ -0,0 +1,120 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" +) + +// MapToMaps converts any map type variable `params` to another map slice variable `pointer`. +// +// The parameter `params` can be type of []map, []*map, []struct, []*struct. +// +// The parameter `pointer` should be type of []map, []*map. +// +// The optional parameter `mapping` is used for struct attribute to map key mapping, which makes +// sense only if the item of `params` is type struct. +func (c *Converter) MapToMaps(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) { + // Params and its element type check. + var ( + paramsRv reflect.Value + paramsKind reflect.Kind + ) + if v, ok := params.(reflect.Value); ok { + paramsRv = v + } else { + paramsRv = reflect.ValueOf(params) + } + paramsKind = paramsRv.Kind() + if paramsKind == reflect.Ptr { + paramsRv = paramsRv.Elem() + paramsKind = paramsRv.Kind() + } + if paramsKind != reflect.Array && paramsKind != reflect.Slice { + return gerror.NewCode( + gcode.CodeInvalidParameter, + "params should be type of slice, example: []map/[]*map/[]struct/[]*struct", + ) + } + var ( + paramsElem = paramsRv.Type().Elem() + paramsElemKind = paramsElem.Kind() + ) + if paramsElemKind == reflect.Ptr { + paramsElem = paramsElem.Elem() + paramsElemKind = paramsElem.Kind() + } + if paramsElemKind != reflect.Map && + paramsElemKind != reflect.Struct && + paramsElemKind != reflect.Interface { + return gerror.NewCodef( + gcode.CodeInvalidParameter, + "params element should be type of map/*map/struct/*struct, but got: %s", + paramsElemKind, + ) + } + // Empty slice, no need continue. + if paramsRv.Len() == 0 { + return nil + } + // Pointer and its element type check. + var ( + pointerRv = reflect.ValueOf(pointer) + pointerKind = pointerRv.Kind() + ) + for pointerKind == reflect.Ptr { + pointerRv = pointerRv.Elem() + pointerKind = pointerRv.Kind() + } + if pointerKind != reflect.Array && pointerKind != reflect.Slice { + return gerror.NewCode(gcode.CodeInvalidParameter, "pointer should be type of *[]map/*[]*map") + } + var ( + pointerElemType = pointerRv.Type().Elem() + pointerElemKind = pointerElemType.Kind() + ) + if pointerElemKind == reflect.Ptr { + pointerElemKind = pointerElemType.Elem().Kind() + } + if pointerElemKind != reflect.Map { + return gerror.NewCode(gcode.CodeInvalidParameter, "pointer element should be type of map/*map") + } + defer func() { + // Catch the panic, especially the reflection operation panics. + if exception := recover(); exception != nil { + if v, ok := exception.(error); ok && gerror.HasStack(v) { + err = v + } else { + err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception) + } + } + }() + var ( + pointerSlice = reflect.MakeSlice(pointerRv.Type(), paramsRv.Len(), paramsRv.Len()) + ) + for i := 0; i < paramsRv.Len(); i++ { + var item reflect.Value + if pointerElemType.Kind() == reflect.Ptr { + item = reflect.New(pointerElemType.Elem()) + if err = MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap...); err != nil { + return err + } + pointerSlice.Index(i).Set(item) + } else { + item = reflect.New(pointerElemType) + if err = MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap...); err != nil { + return err + } + pointerSlice.Index(i).Set(item.Elem()) + } + } + pointerRv.Set(pointerSlice) + return +} diff --git a/util/gconv/gconv_converter_rune.go b/util/gconv/gconv_converter_rune.go new file mode 100644 index 00000000000..b5bff899edb --- /dev/null +++ b/util/gconv/gconv_converter_rune.go @@ -0,0 +1,29 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +func (c *Converter) Rune(any any) (rune, error) { + if v, ok := any.(rune); ok { + return v, nil + } + v, err := c.Int32(any) + if err != nil { + return 0, err + } + return v, nil +} + +func (c *Converter) Runes(any any) ([]rune, error) { + if v, ok := any.([]rune); ok { + return v, nil + } + s, err := c.String(any) + if err != nil { + return nil, err + } + return []rune(s), nil +} diff --git a/util/gconv/gconv_converter_scan.go b/util/gconv/gconv_converter_scan.go new file mode 100644 index 00000000000..269b3de94c5 --- /dev/null +++ b/util/gconv/gconv_converter_scan.go @@ -0,0 +1,336 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +func (c *Converter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) { + // Check if srcValue is nil, in which case no conversion is needed + if srcValue == nil { + return nil + } + // Check if dstPointer is nil, which is an invalid parameter + if dstPointer == nil { + return gerror.NewCode( + gcode.CodeInvalidParameter, + `destination pointer should not be nil`, + ) + } + + // Get the reflection type and value of dstPointer + var ( + dstPointerReflectType reflect.Type + dstPointerReflectValue reflect.Value + ) + if v, ok := dstPointer.(reflect.Value); ok { + dstPointerReflectValue = v + dstPointerReflectType = v.Type() + } else { + dstPointerReflectValue = reflect.ValueOf(dstPointer) + // Do not use dstPointerReflectValue.Type() as dstPointerReflectValue might be zero + dstPointerReflectType = reflect.TypeOf(dstPointer) + } + + // Validate the kind of dstPointer + var dstPointerReflectKind = dstPointerReflectType.Kind() + if dstPointerReflectKind != reflect.Ptr { + // If dstPointer is not a pointer, try to get its address + if dstPointerReflectValue.CanAddr() { + dstPointerReflectValue = dstPointerReflectValue.Addr() + dstPointerReflectType = dstPointerReflectValue.Type() + dstPointerReflectKind = dstPointerReflectType.Kind() + } else { + // If dstPointer is not a pointer and cannot be addressed, return an error + return gerror.NewCodef( + gcode.CodeInvalidParameter, + `destination pointer should be type of pointer, but got type: %v`, + dstPointerReflectType, + ) + } + } + + // Get the reflection value of srcValue + var srcValueReflectValue reflect.Value + if v, ok := srcValue.(reflect.Value); ok { + srcValueReflectValue = v + } else { + srcValueReflectValue = reflect.ValueOf(srcValue) + } + + // Get the element type and kind of dstPointer + var ( + dstPointerReflectValueElem = dstPointerReflectValue.Elem() + dstPointerReflectValueElemKind = dstPointerReflectValueElem.Kind() + ) + // Handle multiple level pointers + if dstPointerReflectValueElemKind == reflect.Ptr { + if dstPointerReflectValueElem.IsNil() { + // Create a new value for the pointer dereference + nextLevelPtr := reflect.New(dstPointerReflectValueElem.Type().Elem()) + // Recursively scan into the dereferenced pointer + if err = Scan(srcValueReflectValue, nextLevelPtr, paramKeyToAttrMap...); err == nil { + dstPointerReflectValueElem.Set(nextLevelPtr) + } + return + } + return Scan(srcValueReflectValue, dstPointerReflectValueElem, paramKeyToAttrMap...) + } + + // Check if srcValue and dstPointer are the same type, in which case direct assignment can be performed + if ok := doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem); ok { + return nil + } + + // Handle different destination types + switch dstPointerReflectValueElemKind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + // Convert to int type + dstPointerReflectValueElem.SetInt(Int64(srcValue)) + return nil + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + // Convert to uint type + dstPointerReflectValueElem.SetUint(Uint64(srcValue)) + return nil + + case reflect.Float32, reflect.Float64: + // Convert to float type + dstPointerReflectValueElem.SetFloat(Float64(srcValue)) + return nil + + case reflect.String: + // Convert to string type + dstPointerReflectValueElem.SetString(String(srcValue)) + return nil + + case reflect.Bool: + // Convert to bool type + dstPointerReflectValueElem.SetBool(Bool(srcValue)) + return nil + + case reflect.Slice: + // Handle slice type conversion + var ( + dstElemType = dstPointerReflectValueElem.Type().Elem() + dstElemKind = dstElemType.Kind() + ) + // The slice element might be a pointer type + if dstElemKind == reflect.Ptr { + dstElemType = dstElemType.Elem() + dstElemKind = dstElemType.Kind() + } + // Special handling for struct or map slice elements + if dstElemKind == reflect.Struct || dstElemKind == reflect.Map { + return c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...) + } + // Handle basic type slice conversions + var srcValueReflectValueKind = srcValueReflectValue.Kind() + if srcValueReflectValueKind == reflect.Slice || srcValueReflectValueKind == reflect.Array { + var ( + srcLen = srcValueReflectValue.Len() + newSlice = reflect.MakeSlice(dstPointerReflectValueElem.Type(), srcLen, srcLen) + ) + for i := 0; i < srcLen; i++ { + srcElem := srcValueReflectValue.Index(i).Interface() + switch dstElemType.Kind() { + case reflect.String: + newSlice.Index(i).SetString(String(srcElem)) + case reflect.Int: + newSlice.Index(i).SetInt(Int64(srcElem)) + case reflect.Int64: + newSlice.Index(i).SetInt(Int64(srcElem)) + case reflect.Float64: + newSlice.Index(i).SetFloat(Float64(srcElem)) + case reflect.Bool: + newSlice.Index(i).SetBool(Bool(srcElem)) + default: + return Scan( + srcElem, newSlice.Index(i).Addr().Interface(), paramKeyToAttrMap..., + ) + } + } + dstPointerReflectValueElem.Set(newSlice) + return nil + } + return c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...) + + default: + // Handle complex types (structs, maps, etc.) + return c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...) + } +} + +// doScanForComplicatedTypes handles the scanning of complex data types. +// It supports converting between maps, structs, and slices of these types. +// The function first attempts JSON conversion, then falls back to specific type handling. +// +// It supports `pointer` in type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct` for converting. +// +// Parameters: +// - srcValue: The source value to convert from +// - dstPointer: The destination pointer to convert to +// - dstPointerReflectType: The reflection type of the destination pointer +// - paramKeyToAttrMap: Optional mapping between parameter keys and struct attribute names +func (c *Converter) doScanForComplicatedTypes( + srcValue, dstPointer any, + dstPointerReflectType reflect.Type, + paramKeyToAttrMap ...map[string]string, +) error { + // Try JSON conversion first + ok, err := doConvertWithJsonCheck(srcValue, dstPointer) + if err != nil { + return err + } + if ok { + return nil + } + + // Handle specific type conversions + var ( + dstPointerReflectTypeElem = dstPointerReflectType.Elem() + dstPointerReflectTypeElemKind = dstPointerReflectTypeElem.Kind() + keyToAttributeNameMapping map[string]string + ) + if len(paramKeyToAttrMap) > 0 { + keyToAttributeNameMapping = paramKeyToAttrMap[0] + } + + // Handle different destination types + switch dstPointerReflectTypeElemKind { + case reflect.Map: + // Convert map to map + return c.MapToMap(srcValue, dstPointer, paramKeyToAttrMap...) + + case reflect.Array, reflect.Slice: + var ( + sliceElem = dstPointerReflectTypeElem.Elem() + sliceElemKind = sliceElem.Kind() + ) + // Handle pointer elements + for sliceElemKind == reflect.Ptr { + sliceElem = sliceElem.Elem() + sliceElemKind = sliceElem.Kind() + } + if sliceElemKind == reflect.Map { + // Convert to slice of maps + return c.MapToMaps(srcValue, dstPointer, paramKeyToAttrMap...) + } + // Convert to slice of structs + return c.Structs(srcValue, dstPointer, keyToAttributeNameMapping, "") + + default: + // Convert to single struct + return c.Struct(srcValue, dstPointer, keyToAttributeNameMapping, "") + } +} + +// doConvertWithTypeCheck supports `pointer` in type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct` +// for converting. +func doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem reflect.Value) (ok bool) { + if !dstPointerReflectValueElem.IsValid() || !srcValueReflectValue.IsValid() { + return false + } + switch { + // Examples: + // UploadFile => UploadFile + // []UploadFile => []UploadFile + // *UploadFile => *UploadFile + // *[]UploadFile => *[]UploadFile + // map[int][int] => map[int][int] + // []map[int][int] => []map[int][int] + // *[]map[int][int] => *[]map[int][int] + case dstPointerReflectValueElem.Type() == srcValueReflectValue.Type(): + dstPointerReflectValueElem.Set(srcValueReflectValue) + return true + + // Examples: + // UploadFile => *UploadFile + // []UploadFile => *[]UploadFile + // map[int][int] => *map[int][int] + // []map[int][int] => *[]map[int][int] + case dstPointerReflectValueElem.Kind() == reflect.Ptr && + dstPointerReflectValueElem.Elem().IsValid() && + dstPointerReflectValueElem.Elem().Type() == srcValueReflectValue.Type(): + dstPointerReflectValueElem.Elem().Set(srcValueReflectValue) + return true + + // Examples: + // *UploadFile => UploadFile + // *[]UploadFile => []UploadFile + // *map[int][int] => map[int][int] + // *[]map[int][int] => []map[int][int] + case srcValueReflectValue.Kind() == reflect.Ptr && + srcValueReflectValue.Elem().IsValid() && + dstPointerReflectValueElem.Type() == srcValueReflectValue.Elem().Type(): + dstPointerReflectValueElem.Set(srcValueReflectValue.Elem()) + return true + + default: + return false + } +} + +// doConvertWithJsonCheck attempts to convert the source value to the destination +// using JSON marshaling and unmarshaling. This is particularly useful for complex +// types that can be represented as JSON. +// +// Parameters: +// - srcValue: The source value to convert from +// - dstPointer: The destination pointer to convert to +// +// Returns: +// - bool: true if JSON conversion was successful +// - error: any error that occurred during conversion +func doConvertWithJsonCheck(srcValue any, dstPointer any) (ok bool, err error) { + switch valueResult := srcValue.(type) { + case []byte: + if json.Valid(valueResult) { + if dstPointerReflectType, ok := dstPointer.(reflect.Value); ok { + if dstPointerReflectType.Kind() == reflect.Ptr { + if dstPointerReflectType.IsNil() { + return false, nil + } + return true, json.UnmarshalUseNumber(valueResult, dstPointerReflectType.Interface()) + } else if dstPointerReflectType.CanAddr() { + return true, json.UnmarshalUseNumber(valueResult, dstPointerReflectType.Addr().Interface()) + } + } else { + return true, json.UnmarshalUseNumber(valueResult, dstPointer) + } + } + + case string: + if valueBytes := []byte(valueResult); json.Valid(valueBytes) { + if dstPointerReflectType, ok := dstPointer.(reflect.Value); ok { + if dstPointerReflectType.Kind() == reflect.Ptr { + if dstPointerReflectType.IsNil() { + return false, nil + } + return true, json.UnmarshalUseNumber(valueBytes, dstPointerReflectType.Interface()) + } else if dstPointerReflectType.CanAddr() { + return true, json.UnmarshalUseNumber(valueBytes, dstPointerReflectType.Addr().Interface()) + } + } else { + return true, json.UnmarshalUseNumber(valueBytes, dstPointer) + } + } + + default: + // The `params` might be struct that implements interface function Interface, eg: gvar.Var. + if v, ok := srcValue.(localinterface.IInterface); ok { + return doConvertWithJsonCheck(v.Interface(), dstPointer) + } + } + return false, nil +} diff --git a/util/gconv/gconv_converter_string.go b/util/gconv/gconv_converter_string.go new file mode 100644 index 00000000000..07e60247bc0 --- /dev/null +++ b/util/gconv/gconv_converter_string.go @@ -0,0 +1,135 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "fmt" + "reflect" + "strconv" + "time" + + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +func (c *Converter) String(any any) (string, error) { + if empty.IsNil(any) { + return "", nil + } + switch value := any.(type) { + case int: + return strconv.Itoa(value), nil + case int8: + return strconv.Itoa(int(value)), nil + case int16: + return strconv.Itoa(int(value)), nil + case int32: + return strconv.Itoa(int(value)), nil + case int64: + return strconv.FormatInt(value, 10), nil + case uint: + return strconv.FormatUint(uint64(value), 10), nil + case uint8: + return strconv.FormatUint(uint64(value), 10), nil + case uint16: + return strconv.FormatUint(uint64(value), 10), nil + case uint32: + return strconv.FormatUint(uint64(value), 10), nil + case uint64: + return strconv.FormatUint(value, 10), nil + case float32: + return strconv.FormatFloat(float64(value), 'f', -1, 32), nil + case float64: + return strconv.FormatFloat(value, 'f', -1, 64), nil + case bool: + return strconv.FormatBool(value), nil + case string: + return value, nil + case []byte: + return string(value), nil + case complex64, complex128: + return fmt.Sprintf("%v", value), nil + case time.Time: + if value.IsZero() { + return "", nil + } + return value.String(), nil + case *time.Time: + if value == nil { + return "", nil + } + return value.String(), nil + case gtime.Time: + if value.IsZero() { + return "", nil + } + return value.String(), nil + case *gtime.Time: + if value == nil { + return "", nil + } + return value.String(), nil + default: + if f, ok := value.(localinterface.IString); ok { + // If the variable implements the String() interface, + // then use that interface to perform the conversion + return f.String(), nil + } + if f, ok := value.(localinterface.IError); ok { + // If the variable implements the Error() interface, + // then use that interface to perform the conversion + return f.Error(), nil + } + // Reflect checks. + var ( + rv = reflect.ValueOf(value) + kind = rv.Kind() + ) + switch kind { + case + reflect.Chan, + reflect.Map, + reflect.Slice, + reflect.Func, + reflect.Interface, + reflect.UnsafePointer: + if rv.IsNil() { + return "", nil + } + case reflect.String: + return rv.String(), nil + case reflect.Ptr: + if rv.IsNil() { + return "", nil + } + return c.String(rv.Elem().Interface()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.FormatInt(rv.Int(), 10), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.FormatUint(rv.Uint(), 10), nil + case reflect.Uintptr: + return strconv.FormatUint(rv.Uint(), 10), nil + case reflect.Float32, reflect.Float64: + return strconv.FormatFloat(rv.Float(), 'f', -1, 64), nil + case reflect.Bool: + return strconv.FormatBool(rv.Bool()), nil + default: + } + // Finally, we use json.Marshal to convert. + jsonContent, err := json.Marshal(value) + if err != nil { + return fmt.Sprint(value), gerror.WrapCodef( + gcode.CodeInvalidParameter, err, "error marshaling value to JSON for: %v", value, + ) + } + return string(jsonContent), nil + } +} diff --git a/util/gconv/gconv_converter_struct.go b/util/gconv/gconv_converter_struct.go new file mode 100644 index 00000000000..74f21c0bf16 --- /dev/null +++ b/util/gconv/gconv_converter_struct.go @@ -0,0 +1,628 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + "strings" + + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" + "github.com/gogf/gf/v2/util/gconv/internal/structcache" +) + +// Struct is the core internal converting function for any data to struct. +func (c *Converter) Struct( + params any, + pointer any, + paramKeyToAttrMap map[string]string, + priorityTag string, +) (err error) { + if params == nil { + // If `params` is nil, no conversion. + return nil + } + if pointer == nil { + return gerror.NewCode(gcode.CodeInvalidParameter, "object pointer cannot be nil") + } + + // JSON content converting. + ok, err := doConvertWithJsonCheck(params, pointer) + if err != nil { + return err + } + if ok { + return nil + } + + defer func() { + // Catch the panic, especially the reflection operation panics. + if exception := recover(); exception != nil { + if v, ok := exception.(error); ok && gerror.HasStack(v) { + err = v + } else { + err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception) + } + } + }() + + var ( + paramsReflectValue reflect.Value + paramsInterface any // DO NOT use `params` directly as it might be type `reflect.Value` + pointerReflectValue reflect.Value + pointerReflectKind reflect.Kind + pointerElemReflectValue reflect.Value // The reflection value to struct element. + ) + if v, ok := params.(reflect.Value); ok { + paramsReflectValue = v + } else { + paramsReflectValue = reflect.ValueOf(params) + } + paramsInterface = paramsReflectValue.Interface() + if v, ok := pointer.(reflect.Value); ok { + pointerReflectValue = v + pointerElemReflectValue = v + } else { + pointerReflectValue = reflect.ValueOf(pointer) + pointerReflectKind = pointerReflectValue.Kind() + if pointerReflectKind != reflect.Ptr { + return gerror.NewCodef( + gcode.CodeInvalidParameter, + "destination pointer should be type of '*struct', but got '%v'", + pointerReflectKind, + ) + } + // Using IsNil on reflect.Ptr variable is OK. + if !pointerReflectValue.IsValid() || pointerReflectValue.IsNil() { + return gerror.NewCode( + gcode.CodeInvalidParameter, + "destination pointer cannot be nil", + ) + } + pointerElemReflectValue = pointerReflectValue.Elem() + } + + // If `params` and `pointer` are the same type, the do directly assignment. + // For performance enhancement purpose. + if ok = doConvertWithTypeCheck(paramsReflectValue, pointerElemReflectValue); ok { + return nil + } + + // custom convert. + if ok, err = c.callCustomConverter(paramsReflectValue, pointerReflectValue); ok { + return err + } + + // Normal unmarshalling interfaces checks. + if ok, err = bindVarToReflectValueWithInterfaceCheck(pointerReflectValue, paramsInterface); ok { + return err + } + + // It automatically creates struct object if necessary. + // For example, if `pointer` is **User, then `elem` is *User, which is a pointer to User. + if pointerElemReflectValue.Kind() == reflect.Ptr { + if !pointerElemReflectValue.IsValid() || pointerElemReflectValue.IsNil() { + e := reflect.New(pointerElemReflectValue.Type().Elem()) + pointerElemReflectValue.Set(e) + defer func() { + if err != nil { + // If it is converted failed, it reset the `pointer` to nil. + pointerReflectValue.Elem().Set(reflect.Zero(pointerReflectValue.Type().Elem())) + } + }() + } + // if v, ok := pointerElemReflectValue.Interface().(localinterface.IUnmarshalValue); ok { + // return v.UnmarshalValue(params) + // } + // Note that it's `pointerElemReflectValue` here not `pointerReflectValue`. + if ok, err = bindVarToReflectValueWithInterfaceCheck(pointerElemReflectValue, paramsInterface); ok { + return err + } + // Retrieve its element, may be struct at last. + pointerElemReflectValue = pointerElemReflectValue.Elem() + } + paramsMap, ok := paramsInterface.(map[string]any) + if !ok { + // paramsMap is the map[string]any type variable for params. + // DO NOT use MapDeep here. + paramsMap = c.doMapConvert(paramsInterface, recursiveTypeAuto, true) + if paramsMap == nil { + return gerror.NewCodef( + gcode.CodeInvalidParameter, + `convert params from "%#v" to "map[string]any" failed`, + params, + ) + } + } + // Nothing to be done as the parameters are empty. + if len(paramsMap) == 0 { + return nil + } + // Get struct info from cache or parse struct and cache the struct info. + cachedStructInfo := c.internalConvertConfig.GetCachedStructInfo( + pointerElemReflectValue.Type(), priorityTag, + ) + // Nothing to be converted. + if cachedStructInfo == nil { + return nil + } + // For the structure types of 0 tagOrFiledNameToFieldInfoMap, + // they also need to be cached to prevent invalid logic + if cachedStructInfo.HasNoFields() { + return nil + } + var ( + // Indicates that those values have been used and cannot be reused. + usedParamsKeyOrTagNameMap = structcache.GetUsedParamsKeyOrTagNameMapFromPool() + cachedFieldInfo *structcache.CachedFieldInfo + paramsValue any + ) + defer structcache.PutUsedParamsKeyOrTagNameMapToPool(usedParamsKeyOrTagNameMap) + + // Firstly, search according to custom mapping rules. + // If a possible direct assignment is found, reduce the number of subsequent map searches. + for paramKey, fieldName := range paramKeyToAttrMap { + paramsValue, ok = paramsMap[paramKey] + if !ok { + continue + } + cachedFieldInfo = cachedStructInfo.GetFieldInfo(fieldName) + if cachedFieldInfo != nil { + fieldValue := cachedFieldInfo.GetFieldReflectValueFrom(pointerElemReflectValue) + if err = c.bindVarToStructField( + cachedFieldInfo, + fieldValue, + paramsValue, + paramKeyToAttrMap, + ); err != nil { + return err + } + if len(cachedFieldInfo.OtherSameNameField) > 0 { + if err = c.setOtherSameNameField( + cachedFieldInfo, paramsValue, pointerReflectValue, paramKeyToAttrMap, + ); err != nil { + return err + } + } + usedParamsKeyOrTagNameMap[paramKey] = struct{}{} + } + } + // Already done converting for given `paramsMap`. + if len(usedParamsKeyOrTagNameMap) == len(paramsMap) { + return nil + } + return c.bindStructWithLoopFieldInfos( + paramsMap, pointerElemReflectValue, paramKeyToAttrMap, usedParamsKeyOrTagNameMap, cachedStructInfo, + ) +} + +func (c *Converter) setOtherSameNameField( + cachedFieldInfo *structcache.CachedFieldInfo, + srcValue any, + structValue reflect.Value, + paramKeyToAttrMap map[string]string, +) (err error) { + // loop the same field name of all sub attributes. + for _, otherFieldInfo := range cachedFieldInfo.OtherSameNameField { + fieldValue := cachedFieldInfo.GetOtherFieldReflectValueFrom(structValue, otherFieldInfo.FieldIndexes) + if err = c.bindVarToStructField(otherFieldInfo, fieldValue, srcValue, paramKeyToAttrMap); err != nil { + return err + } + } + return nil +} + +func (c *Converter) bindStructWithLoopFieldInfos( + paramsMap map[string]any, + structValue reflect.Value, + paramKeyToAttrMap map[string]string, + usedParamsKeyOrTagNameMap map[string]struct{}, + cachedStructInfo *structcache.CachedStructInfo, +) (err error) { + var ( + cachedFieldInfo *structcache.CachedFieldInfo + fuzzLastKey string + fieldValue reflect.Value + paramKey string + paramValue any + matched bool + ok bool + ) + for _, cachedFieldInfo = range cachedStructInfo.GetFieldConvertInfos() { + for _, fieldTag := range cachedFieldInfo.PriorityTagAndFieldName { + if paramValue, ok = paramsMap[fieldTag]; !ok { + continue + } + fieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue) + if err = c.bindVarToStructField( + cachedFieldInfo, fieldValue, paramValue, paramKeyToAttrMap, + ); err != nil { + return err + } + // handle same field name in nested struct. + if len(cachedFieldInfo.OtherSameNameField) > 0 { + if err = c.setOtherSameNameField( + cachedFieldInfo, paramValue, structValue, paramKeyToAttrMap, + ); err != nil { + return err + } + } + usedParamsKeyOrTagNameMap[fieldTag] = struct{}{} + matched = true + break + } + if matched { + matched = false + continue + } + + fuzzLastKey = cachedFieldInfo.LastFuzzyKey.Load().(string) + if paramValue, ok = paramsMap[fuzzLastKey]; !ok { + paramKey, paramValue = fuzzyMatchingFieldName( + cachedFieldInfo.RemoveSymbolsFieldName, paramsMap, usedParamsKeyOrTagNameMap, + ) + ok = paramKey != "" + cachedFieldInfo.LastFuzzyKey.Store(paramKey) + } + if ok { + fieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue) + if paramValue != nil { + if err = c.bindVarToStructField( + cachedFieldInfo, fieldValue, paramValue, paramKeyToAttrMap, + ); err != nil { + return err + } + // handle same field name in nested struct. + if len(cachedFieldInfo.OtherSameNameField) > 0 { + if err = c.setOtherSameNameField( + cachedFieldInfo, paramValue, structValue, paramKeyToAttrMap, + ); err != nil { + return err + } + } + } + usedParamsKeyOrTagNameMap[paramKey] = struct{}{} + } + } + return nil +} + +// fuzzy matching rule: +// to match field name and param key in case-insensitive and without symbols. +func fuzzyMatchingFieldName( + fieldName string, + paramsMap map[string]any, + usedParamsKeyMap map[string]struct{}, +) (string, any) { + for paramKey, paramValue := range paramsMap { + if _, ok := usedParamsKeyMap[paramKey]; ok { + continue + } + removeParamKeyUnderline := utils.RemoveSymbols(paramKey) + if strings.EqualFold(fieldName, removeParamKeyUnderline) { + return paramKey, paramValue + } + } + return "", nil +} + +// bindVarToStructField sets value to struct object attribute by name. +// each value to attribute converting comes into in this function. +func (c *Converter) bindVarToStructField( + cachedFieldInfo *structcache.CachedFieldInfo, + fieldValue reflect.Value, + srcValue any, + paramKeyToAttrMap map[string]string, +) (err error) { + if !fieldValue.IsValid() { + return nil + } + // CanSet checks whether attribute is public accessible. + if !fieldValue.CanSet() { + return nil + } + defer func() { + if exception := recover(); exception != nil { + if err = c.bindVarToReflectValue(fieldValue, srcValue, paramKeyToAttrMap); err != nil { + err = gerror.Wrapf(err, `error binding srcValue to attribute "%s"`, cachedFieldInfo.FieldName()) + } + } + }() + // Directly converting. + if empty.IsNil(srcValue) { + fieldValue.Set(reflect.Zero(fieldValue.Type())) + return nil + } + // Try to call custom converter. + // Issue: https://github.com/gogf/gf/issues/3099 + var ( + customConverterInput reflect.Value + ok bool + ) + if cachedFieldInfo.IsCustomConvert { + if customConverterInput, ok = srcValue.(reflect.Value); !ok { + customConverterInput = reflect.ValueOf(srcValue) + } + if ok, err = c.callCustomConverter(customConverterInput, fieldValue); ok || err != nil { + return + } + } + if cachedFieldInfo.IsCommonInterface { + if ok, err = bindVarToReflectValueWithInterfaceCheck(fieldValue, srcValue); ok || err != nil { + return + } + } + // Common types use fast assignment logic + if cachedFieldInfo.ConvertFunc != nil { + return cachedFieldInfo.ConvertFunc(srcValue, fieldValue) + } + c.doConvertWithReflectValueSet( + fieldValue, doConvertInput{ + FromValue: srcValue, + ToTypeName: cachedFieldInfo.StructField.Type.String(), + ReferValue: fieldValue, + }, + ) + return nil +} + +// bindVarToReflectValueWithInterfaceCheck does bind using common interfaces checks. +func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value any) (bool, error) { + var pointer any + if reflectValue.Kind() != reflect.Ptr && reflectValue.CanAddr() { + reflectValueAddr := reflectValue.Addr() + if reflectValueAddr.IsNil() || !reflectValueAddr.IsValid() { + return false, nil + } + // Not a pointer, but can token address, that makes it can be unmarshalled. + pointer = reflectValue.Addr().Interface() + } else { + if reflectValue.IsNil() || !reflectValue.IsValid() { + return false, nil + } + pointer = reflectValue.Interface() + } + // UnmarshalValue. + if v, ok := pointer.(localinterface.IUnmarshalValue); ok { + return ok, v.UnmarshalValue(value) + } + // UnmarshalText. + if v, ok := pointer.(localinterface.IUnmarshalText); ok { + var valueBytes []byte + if b, ok := value.([]byte); ok { + valueBytes = b + } else if s, ok := value.(string); ok { + valueBytes = []byte(s) + } else if f, ok := value.(localinterface.IString); ok { + valueBytes = []byte(f.String()) + } + if len(valueBytes) > 0 { + return ok, v.UnmarshalText(valueBytes) + } + } + // UnmarshalJSON. + if v, ok := pointer.(localinterface.IUnmarshalJSON); ok { + var valueBytes []byte + if b, ok := value.([]byte); ok { + valueBytes = b + } else if s, ok := value.(string); ok { + valueBytes = []byte(s) + } else if f, ok := value.(localinterface.IString); ok { + valueBytes = []byte(f.String()) + } + + if len(valueBytes) > 0 { + // If it is not a valid JSON string, it then adds char `"` on its both sides to make it is. + if !json.Valid(valueBytes) { + newValueBytes := make([]byte, len(valueBytes)+2) + newValueBytes[0] = '"' + newValueBytes[len(newValueBytes)-1] = '"' + copy(newValueBytes[1:], valueBytes) + valueBytes = newValueBytes + } + return ok, v.UnmarshalJSON(valueBytes) + } + } + if v, ok := pointer.(localinterface.ISet); ok { + v.Set(value) + return ok, nil + } + return false, nil +} + +// bindVarToReflectValue sets `value` to reflect value object `structFieldValue`. +func (c *Converter) bindVarToReflectValue( + structFieldValue reflect.Value, value any, paramKeyToAttrMap map[string]string, +) (err error) { + // JSON content converting. + ok, err := doConvertWithJsonCheck(value, structFieldValue) + if err != nil { + return err + } + if ok { + return nil + } + + kind := structFieldValue.Kind() + // Converting using `Set` interface implements, for some types. + switch kind { + case reflect.Slice, reflect.Array, reflect.Ptr, reflect.Interface: + if !structFieldValue.IsNil() { + if v, ok := structFieldValue.Interface().(localinterface.ISet); ok { + v.Set(value) + return nil + } + } + default: + } + + // Converting using reflection by kind. + switch kind { + case reflect.Map: + return c.MapToMap(value, structFieldValue, paramKeyToAttrMap) + + case reflect.Struct: + // Recursively converting for struct attribute. + if err = c.Struct(value, structFieldValue, nil, ""); err != nil { + // Note there's reflect conversion mechanism here. + structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type())) + } + + // Note that the slice element might be type of struct, + // so it uses Struct function doing the converting internally. + case reflect.Slice, reflect.Array: + var ( + reflectArray reflect.Value + reflectValue = reflect.ValueOf(value) + ) + if reflectValue.Kind() == reflect.Slice || reflectValue.Kind() == reflect.Array { + reflectArray = reflect.MakeSlice(structFieldValue.Type(), reflectValue.Len(), reflectValue.Len()) + if reflectValue.Len() > 0 { + var ( + elemType = reflectArray.Index(0).Type() + elemTypeName string + converted bool + ) + for i := 0; i < reflectValue.Len(); i++ { + converted = false + elemTypeName = elemType.Name() + if elemTypeName == "" { + elemTypeName = elemType.String() + } + var elem reflect.Value + if elemType.Kind() == reflect.Ptr { + elem = reflect.New(elemType.Elem()).Elem() + } else { + elem = reflect.New(elemType).Elem() + } + if elem.Kind() == reflect.Struct { + if err = c.Struct(reflectValue.Index(i).Interface(), elem, nil, ""); err == nil { + converted = true + } + } + if !converted { + c.doConvertWithReflectValueSet( + elem, doConvertInput{ + FromValue: reflectValue.Index(i).Interface(), + ToTypeName: elemTypeName, + ReferValue: elem, + }, + ) + } + if elemType.Kind() == reflect.Ptr { + // Before it sets the `elem` to array, do pointer converting if necessary. + elem = elem.Addr() + } + reflectArray.Index(i).Set(elem) + } + } + } else { + var ( + elem reflect.Value + elemType = structFieldValue.Type().Elem() + elemTypeName = elemType.Name() + converted bool + ) + switch reflectValue.Kind() { + case reflect.String: + // Value is empty string. + if reflectValue.IsZero() { + var elemKind = elemType.Kind() + // Try to find the original type kind of the slice element. + if elemKind == reflect.Ptr { + elemKind = elemType.Elem().Kind() + } + switch elemKind { + case reflect.String: + // Empty string cannot be assigned to string slice. + return nil + default: + } + } + default: + } + if elemTypeName == "" { + elemTypeName = elemType.String() + } + if elemType.Kind() == reflect.Ptr { + elem = reflect.New(elemType.Elem()).Elem() + } else { + elem = reflect.New(elemType).Elem() + } + if elem.Kind() == reflect.Struct { + if err = c.Struct(value, elem, nil, ""); err == nil { + converted = true + } + } + if !converted { + c.doConvertWithReflectValueSet( + elem, doConvertInput{ + FromValue: value, + ToTypeName: elemTypeName, + ReferValue: elem, + }, + ) + } + if elemType.Kind() == reflect.Ptr { + // Before it sets the `elem` to array, do pointer converting if necessary. + elem = elem.Addr() + } + reflectArray = reflect.MakeSlice(structFieldValue.Type(), 1, 1) + reflectArray.Index(0).Set(elem) + } + structFieldValue.Set(reflectArray) + + case reflect.Ptr: + if structFieldValue.IsNil() || structFieldValue.IsZero() { + // Nil or empty pointer, it creates a new one. + item := reflect.New(structFieldValue.Type().Elem()) + if ok, err = bindVarToReflectValueWithInterfaceCheck(item, value); ok { + structFieldValue.Set(item) + return err + } + elem := item.Elem() + if err = c.bindVarToReflectValue(elem, value, paramKeyToAttrMap); err == nil { + structFieldValue.Set(elem.Addr()) + } + } else { + // Not empty pointer, it assigns values to it. + return c.bindVarToReflectValue(structFieldValue.Elem(), value, paramKeyToAttrMap) + } + + // It mainly and specially handles the interface of nil value. + case reflect.Interface: + if value == nil { + // Specially. + structFieldValue.Set(reflect.ValueOf((*any)(nil))) + } else { + // Note there's reflect conversion mechanism here. + structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type())) + } + + default: + defer func() { + if exception := recover(); exception != nil { + err = gerror.NewCodef( + gcode.CodeInternalPanic, + `cannot convert value "%+v" to type "%s":%+v`, + value, + structFieldValue.Type().String(), + exception, + ) + } + }() + // It here uses reflect converting `value` to type of the attribute and assigns + // the result value to the attribute. It might fail and panic if the usual Go + // conversion rules do not allow conversion. + structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type())) + } + return nil +} diff --git a/util/gconv/gconv_converter_structs.go b/util/gconv/gconv_converter_structs.go new file mode 100644 index 00000000000..347cd5cbd11 --- /dev/null +++ b/util/gconv/gconv_converter_structs.go @@ -0,0 +1,115 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" +) + +// Structs converts any slice to given struct slice. +// +// It automatically checks and converts json string to []map if `params` is string/[]byte. +// +// The parameter `pointer` should be type of pointer to slice of struct. +// Note that if `pointer` is a pointer to another pointer of type of slice of struct, +// it will create the struct/pointer internally. +func (c *Converter) Structs( + params any, pointer any, paramKeyToAttrMap map[string]string, priorityTag string, +) (err error) { + defer func() { + // Catch the panic, especially the reflection operation panics. + if exception := recover(); exception != nil { + if v, ok := exception.(error); ok && gerror.HasStack(v) { + err = v + } else { + err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception) + } + } + }() + + // Pointer type check. + pointerRv, ok := pointer.(reflect.Value) + if !ok { + pointerRv = reflect.ValueOf(pointer) + if kind := pointerRv.Kind(); kind != reflect.Ptr { + return gerror.NewCodef( + gcode.CodeInvalidParameter, + "pointer should be type of pointer, but got: %v", kind, + ) + } + } + // Converting `params` to map slice. + var ( + paramsList []any + paramsRv = reflect.ValueOf(params) + paramsKind = paramsRv.Kind() + ) + for paramsKind == reflect.Ptr { + paramsRv = paramsRv.Elem() + paramsKind = paramsRv.Kind() + } + switch paramsKind { + case reflect.Slice, reflect.Array: + paramsList = make([]any, paramsRv.Len()) + for i := 0; i < paramsRv.Len(); i++ { + paramsList[i] = paramsRv.Index(i).Interface() + } + default: + var paramsMaps = Maps(params) + paramsList = make([]any, len(paramsMaps)) + for i := 0; i < len(paramsMaps); i++ { + paramsList[i] = paramsMaps[i] + } + } + // If `params` is an empty slice, no conversion. + if len(paramsList) == 0 { + return nil + } + var ( + reflectElemArray = reflect.MakeSlice(pointerRv.Type().Elem(), len(paramsList), len(paramsList)) + itemType = reflectElemArray.Index(0).Type() + itemTypeKind = itemType.Kind() + pointerRvElem = pointerRv.Elem() + pointerRvLength = pointerRvElem.Len() + ) + if itemTypeKind == reflect.Ptr { + // Pointer element. + for i := 0; i < len(paramsList); i++ { + var tempReflectValue reflect.Value + if i < pointerRvLength { + // Might be nil. + tempReflectValue = pointerRvElem.Index(i).Elem() + } + if !tempReflectValue.IsValid() { + tempReflectValue = reflect.New(itemType.Elem()).Elem() + } + if err = c.Struct(paramsList[i], tempReflectValue, paramKeyToAttrMap, priorityTag); err != nil { + return err + } + reflectElemArray.Index(i).Set(tempReflectValue.Addr()) + } + } else { + // Struct element. + for i := 0; i < len(paramsList); i++ { + var tempReflectValue reflect.Value + if i < pointerRvLength { + tempReflectValue = pointerRvElem.Index(i) + } else { + tempReflectValue = reflect.New(itemType).Elem() + } + if err = c.Struct(paramsList[i], tempReflectValue, paramKeyToAttrMap, priorityTag); err != nil { + return err + } + reflectElemArray.Index(i).Set(tempReflectValue) + } + } + pointerRv.Elem().Set(reflectElemArray) + return nil +} diff --git a/util/gconv/gconv_converter_time.go b/util/gconv/gconv_converter_time.go new file mode 100644 index 00000000000..f1b1857582e --- /dev/null +++ b/util/gconv/gconv_converter_time.go @@ -0,0 +1,111 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "time" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +// Time converts `any` to time.Time. +func (c *Converter) Time(any interface{}, format ...string) (time.Time, error) { + // It's already this type. + if len(format) == 0 { + if v, ok := any.(time.Time); ok { + return v, nil + } + } + t, err := c.GTime(any, format...) + if err != nil { + return time.Time{}, err + } + if t != nil { + return t.Time, nil + } + return time.Time{}, nil +} + +// Duration converts `any` to time.Duration. +// If `any` is string, then it uses time.ParseDuration to convert it. +// If `any` is numeric, then it converts `any` as nanoseconds. +func (c *Converter) Duration(any interface{}) (time.Duration, error) { + // It's already this type. + if v, ok := any.(time.Duration); ok { + return v, nil + } + s, err := c.String(any) + if err != nil { + return 0, err + } + if !utils.IsNumeric(s) { + return gtime.ParseDuration(s) + } + i, err := c.Int64(any) + if err != nil { + return 0, err + } + return time.Duration(i), nil +} + +// GTime converts `any` to *gtime.Time. +// The parameter `format` can be used to specify the format of `any`. +// It returns the converted value that matched the first format of the formats slice. +// If no `format` given, it converts `any` using gtime.NewFromTimeStamp if `any` is numeric, +// or using gtime.StrToTime if `any` is string. +func (c *Converter) GTime(any interface{}, format ...string) (*gtime.Time, error) { + if empty.IsNil(any) { + return nil, nil + } + if v, ok := any.(localinterface.IGTime); ok { + return v.GTime(format...), nil + } + // It's already this type. + if len(format) == 0 { + if v, ok := any.(*gtime.Time); ok { + return v, nil + } + if t, ok := any.(time.Time); ok { + return gtime.New(t), nil + } + if t, ok := any.(*time.Time); ok { + return gtime.New(t), nil + } + } + s, err := c.String(any) + if err != nil { + return nil, err + } + if len(s) == 0 { + return gtime.New(), nil + } + // Priority conversion using given format. + if len(format) > 0 { + for _, item := range format { + t, err := gtime.StrToTimeFormat(s, item) + if err != nil { + return nil, err + } + if t != nil { + return t, nil + } + } + return nil, nil + } + if utils.IsNumeric(s) { + i, err := c.Int64(s) + if err != nil { + return nil, err + } + return gtime.NewFromTimeStamp(i), nil + } else { + return gtime.StrToTime(s) + } +} diff --git a/util/gconv/gconv_converter_uint.go b/util/gconv/gconv_converter_uint.go new file mode 100644 index 00000000000..a17ef2a7ad7 --- /dev/null +++ b/util/gconv/gconv_converter_uint.go @@ -0,0 +1,156 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "math" + "reflect" + "strconv" + + "github.com/gogf/gf/v2/encoding/gbinary" + "github.com/gogf/gf/v2/errors/gcode" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +func (c *Converter) Uint(any any) (uint, error) { + if empty.IsNil(any) { + return 0, nil + } + if v, ok := any.(uint); ok { + return v, nil + } + v, err := c.Uint64(any) + return uint(v), err +} + +func (c *Converter) Uint8(any any) (uint8, error) { + if empty.IsNil(any) { + return 0, nil + } + if v, ok := any.(uint8); ok { + return v, nil + } + v, err := c.Uint64(any) + return uint8(v), err +} + +func (c *Converter) Uint16(any any) (uint16, error) { + if empty.IsNil(any) { + return 0, nil + } + if v, ok := any.(uint16); ok { + return v, nil + } + v, err := c.Uint64(any) + return uint16(v), err +} + +func (c *Converter) Uint32(any any) (uint32, error) { + if empty.IsNil(any) { + return 0, nil + } + if v, ok := any.(uint32); ok { + return v, nil + } + v, err := c.Uint64(any) + return uint32(v), err +} + +func (c *Converter) Uint64(any any) (uint64, error) { + if empty.IsNil(any) { + return 0, nil + } + if v, ok := any.(uint64); ok { + return v, nil + } + rv := reflect.ValueOf(any) + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + val := rv.Int() + if val < 0 { + return uint64(val), gerror.NewCodef( + gcode.CodeInvalidParameter, + `cannot convert negative value "%d" to uint64`, + val, + ) + } + return uint64(val), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return rv.Uint(), nil + case reflect.Uintptr: + return rv.Uint(), nil + case reflect.Float32, reflect.Float64: + val := rv.Float() + if val < 0 { + return uint64(val), gerror.NewCodef( + gcode.CodeInvalidParameter, + `cannot convert negative value "%f" to uint64`, + val, + ) + } + return uint64(val), nil + case reflect.Bool: + if rv.Bool() { + return 1, nil + } + return 0, nil + case reflect.Ptr: + if rv.IsNil() { + return 0, nil + } + if f, ok := any.(localinterface.IUint64); ok { + return f.Uint64(), nil + } + return c.Uint64(rv.Elem().Interface()) + case reflect.Slice: + if rv.Type().Elem().Kind() == reflect.Uint8 { + return gbinary.DecodeToUint64(rv.Bytes()), nil + } + return 0, gerror.NewCodef( + gcode.CodeInvalidParameter, + `unsupport slice type "%s" for converting to uint64`, + rv.Type().String(), + ) + case reflect.String: + var s = rv.String() + // Hexadecimal + if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') { + v, err := strconv.ParseUint(s[2:], 16, 64) + if err == nil { + return v, nil + } + return 0, gerror.WrapCodef( + gcode.CodeInvalidParameter, + err, + `cannot convert hexadecimal string "%s" to uint64`, + s, + ) + } + // Decimal + if v, err := strconv.ParseUint(s, 10, 64); err == nil { + return v, nil + } + // Float64 + if v, err := c.Float64(any); err == nil { + if math.IsNaN(v) { + return 0, nil + } + return uint64(v), nil + } + default: + if f, ok := any.(localinterface.IUint64); ok { + return f.Uint64(), nil + } + } + return 0, gerror.NewCodef( + gcode.CodeInvalidParameter, + `unsupport value type "%s" for converting to uint64`, + reflect.TypeOf(any).String(), + ) +} diff --git a/util/gconv/gconv_float.go b/util/gconv/gconv_float.go index fac2d1c9871..62d6d4861d5 100644 --- a/util/gconv/gconv_float.go +++ b/util/gconv/gconv_float.go @@ -6,144 +6,14 @@ package gconv -import ( - "reflect" - "strconv" - - "github.com/gogf/gf/v2/encoding/gbinary" - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" -) - // Float32 converts `any` to float32. func Float32(any any) float32 { - v, _ := doFloat32(any) + v, _ := defaultConverter.Float32(any) return v } -func doFloat32(any any) (float32, error) { - if empty.IsNil(any) { - return 0, nil - } - switch value := any.(type) { - case float32: - return value, nil - case float64: - return float32(value), nil - case []byte: - // TODO: It might panic here for these types. - return gbinary.DecodeToFloat32(value), nil - default: - rv := reflect.ValueOf(any) - switch rv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return float32(rv.Int()), nil - case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return float32(rv.Uint()), nil - case reflect.Float32, reflect.Float64: - return float32(rv.Float()), nil - case reflect.Bool: - if rv.Bool() { - return 1, nil - } - return 0, nil - case reflect.String: - f, err := strconv.ParseFloat(rv.String(), 32) - if err != nil { - return 0, gerror.WrapCodef( - gcode.CodeInvalidParameter, err, "converting string to float32 failed for: %v", any, - ) - } - return float32(f), nil - case reflect.Ptr: - if rv.IsNil() { - return 0, nil - } - if f, ok := value.(localinterface.IFloat32); ok { - return f.Float32(), nil - } - return doFloat32(rv.Elem().Interface()) - default: - if f, ok := value.(localinterface.IFloat32); ok { - return f.Float32(), nil - } - v, err := strconv.ParseFloat(String(any), 32) - if err != nil { - return 0, gerror.WrapCodef( - gcode.CodeInvalidParameter, err, "converting string to float32 failed for: %v", any, - ) - } - return float32(v), nil - } - } -} - // Float64 converts `any` to float64. func Float64(any any) float64 { - v, _ := doFloat64(any) + v, _ := defaultConverter.Float64(any) return v } - -func doFloat64(any any) (float64, error) { - if empty.IsNil(any) { - return 0, nil - } - switch value := any.(type) { - case float32: - return float64(value), nil - case float64: - return value, nil - case []byte: - // TODO: It might panic here for these types. - return gbinary.DecodeToFloat64(value), nil - default: - rv := reflect.ValueOf(any) - switch rv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return float64(rv.Int()), nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return float64(rv.Uint()), nil - case reflect.Uintptr: - return float64(rv.Uint()), nil - case reflect.Float32, reflect.Float64: - // Please Note: - // When the type is float32 or a custom type defined based on float32, - // switching to float64 may result in a few extra decimal places. - return rv.Float(), nil - case reflect.Bool: - if rv.Bool() { - return 1, nil - } - return 0, nil - case reflect.String: - f, err := strconv.ParseFloat(rv.String(), 64) - if err != nil { - return 0, gerror.WrapCodef( - gcode.CodeInvalidParameter, err, "converting string to float64 failed for: %v", any, - ) - } - return f, nil - case reflect.Ptr: - if rv.IsNil() { - return 0, nil - } - if f, ok := value.(localinterface.IFloat64); ok { - return f.Float64(), nil - } - return doFloat64(rv.Elem().Interface()) - default: - if f, ok := value.(localinterface.IFloat64); ok { - return f.Float64(), nil - } - v, err := strconv.ParseFloat(String(any), 64) - if err != nil { - return 0, gerror.WrapCodef( - gcode.CodeInvalidParameter, err, "converting string to float64 failed for: %v", any, - ) - } - return v, nil - } - } -} diff --git a/util/gconv/gconv_int.go b/util/gconv/gconv_int.go index a3f833ae690..78c534d6fa2 100644 --- a/util/gconv/gconv_int.go +++ b/util/gconv/gconv_int.go @@ -6,177 +6,32 @@ package gconv -import ( - "math" - "reflect" - "strconv" - - "github.com/gogf/gf/v2/encoding/gbinary" - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" -) - // Int converts `any` to int. func Int(any any) int { - v, _ := doInt(any) + v, _ := defaultConverter.Int(any) return v } -func doInt(any any) (int, error) { - if v, ok := any.(int); ok { - return v, nil - } - v, err := doInt64(any) - if err != nil { - return 0, err - } - return int(v), nil -} - // Int8 converts `any` to int8. func Int8(any any) int8 { - v, _ := doInt8(any) + v, _ := defaultConverter.Int8(any) return v } -func doInt8(any any) (int8, error) { - if v, ok := any.(int8); ok { - return v, nil - } - v, err := doInt64(any) - if err != nil { - return 0, err - } - return int8(v), nil -} - // Int16 converts `any` to int16. func Int16(any any) int16 { - v, _ := doInt16(any) + v, _ := defaultConverter.Int16(any) return v } -func doInt16(any any) (int16, error) { - if v, ok := any.(int16); ok { - return v, nil - } - v, err := doInt64(any) - if err != nil { - return 0, err - } - return int16(v), nil -} - // Int32 converts `any` to int32. func Int32(any any) int32 { - v, _ := doInt32(any) + v, _ := defaultConverter.Int32(any) return v } -func doInt32(any any) (int32, error) { - if v, ok := any.(int32); ok { - return v, nil - } - v, err := doInt64(any) - if err != nil { - return 0, err - } - return int32(v), nil -} - // Int64 converts `any` to int64. func Int64(any any) int64 { - v, _ := doInt64(any) + v, _ := defaultConverter.Int64(any) return v } - -func doInt64(any any) (int64, error) { - if empty.IsNil(any) { - return 0, nil - } - if v, ok := any.(int64); ok { - return v, nil - } - rv := reflect.ValueOf(any) - switch rv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return rv.Int(), nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return int64(rv.Uint()), nil - case reflect.Uintptr: - return int64(rv.Uint()), nil - case reflect.Float32, reflect.Float64: - return int64(rv.Float()), nil - case reflect.Bool: - if rv.Bool() { - return 1, nil - } - return 0, nil - case reflect.Ptr: - if rv.IsNil() { - return 0, nil - } - if f, ok := any.(localinterface.IInt64); ok { - return f.Int64(), nil - } - return doInt64(rv.Elem().Interface()) - case reflect.Slice: - // TODO: It might panic here for these types. - if rv.Type().Elem().Kind() == reflect.Uint8 { - return gbinary.DecodeToInt64(rv.Bytes()), nil - } - case reflect.String: - var ( - s = rv.String() - isMinus = false - ) - if len(s) > 0 { - if s[0] == '-' { - isMinus = true - s = s[1:] - } else if s[0] == '+' { - s = s[1:] - } - } - // Hexadecimal. - if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') { - if v, e := strconv.ParseInt(s[2:], 16, 64); e == nil { - if isMinus { - return -v, nil - } - return v, nil - } - } - // Decimal. - if v, e := strconv.ParseInt(s, 10, 64); e == nil { - if isMinus { - return -v, nil - } - return v, nil - } - // Float64. - valueInt64, err := doFloat64(s) - if err != nil { - return 0, err - } - if math.IsNaN(valueInt64) { - return 0, nil - } else { - if isMinus { - return -int64(valueInt64), nil - } - return int64(valueInt64), nil - } - default: - if f, ok := any.(localinterface.IInt64); ok { - return f.Int64(), nil - } - } - return 0, gerror.NewCodef( - gcode.CodeInvalidParameter, - `unsupport value type for converting to int64: %v`, - reflect.TypeOf(any), - ) -} diff --git a/util/gconv/gconv_map.go b/util/gconv/gconv_map.go index 46809da6f13..8523c3a423a 100644 --- a/util/gconv/gconv_map.go +++ b/util/gconv/gconv_map.go @@ -6,17 +6,6 @@ package gconv -import ( - "reflect" - "strings" - - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/utils" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" - "github.com/gogf/gf/v2/util/gtag" -) - type recursiveType string const ( @@ -28,7 +17,7 @@ const ( type MapOption struct { // Deep marks doing Map function recursively, which means if the attribute of given converting value // is also a struct/*struct, it automatically calls Map function on this attribute converting it to - // a map[string]interface{} type variable. + // a map[string]any type variable. Deep bool // OmitEmpty ignores the attributes that has json `omitempty` tag. @@ -38,516 +27,30 @@ type MapOption struct { Tags []string } -// Map converts any variable `value` to map[string]interface{}. If the parameter `value` is not a +// Map converts any variable `value` to map[string]any. If the parameter `value` is not a // map/struct/*struct type, then the conversion will fail and returns nil. // // If `value` is a struct/*struct object, the second parameter `priorityTagAndFieldName` specifies the most priority // priorityTagAndFieldName that will be detected, otherwise it detects the priorityTagAndFieldName in order of: // gconv, json, field name. -func Map(value interface{}, option ...MapOption) map[string]interface{} { - return doMapConvert(value, recursiveTypeAuto, false, option...) +func Map(value any, option ...MapOption) map[string]any { + return defaultConverter.doMapConvert(value, recursiveTypeAuto, false, option...) } // MapDeep does Map function recursively, which means if the attribute of `value` // is also a struct/*struct, calls Map function on this attribute converting it to -// a map[string]interface{} type variable. +// a map[string]any type variable. // Deprecated: used Map instead. -func MapDeep(value interface{}, tags ...string) map[string]interface{} { - return doMapConvert(value, recursiveTypeTrue, false, MapOption{ +func MapDeep(value any, tags ...string) map[string]any { + return defaultConverter.doMapConvert(value, recursiveTypeTrue, false, MapOption{ Deep: true, Tags: tags, }) } -// doMapConvert implements the map converting. -// It automatically checks and converts json string to map if `value` is string/[]byte. -// -// TODO completely implement the recursive converting for all types, especially the map. -func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool, option ...MapOption) map[string]interface{} { - if value == nil { - return nil - } - // It redirects to its underlying value if it has implemented interface iVal. - if v, ok := value.(localinterface.IVal); ok { - value = v.Val() - } - var ( - usedOption = getUsedMapOption(option...) - newTags = gtag.StructTagPriority - ) - if usedOption.Deep { - recursive = recursiveTypeTrue - } - switch len(usedOption.Tags) { - case 0: - // No need handling. - case 1: - newTags = append(strings.Split(usedOption.Tags[0], ","), gtag.StructTagPriority...) - default: - newTags = append(usedOption.Tags, gtag.StructTagPriority...) - } - // Assert the common combination of types, and finally it uses reflection. - dataMap := make(map[string]interface{}) - switch r := value.(type) { - case string: - // If it is a JSON string, automatically unmarshal it! - if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { - if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil { - return nil - } - } else { - return nil - } - case []byte: - // If it is a JSON string, automatically unmarshal it! - if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { - if err := json.UnmarshalUseNumber(r, &dataMap); err != nil { - return nil - } - } else { - return nil - } - case map[interface{}]interface{}: - recursiveOption := usedOption - recursiveOption.Tags = newTags - for k, v := range r { - dataMap[String(k)] = doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: v, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - }, - ) - } - case map[interface{}]string: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]int: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]uint: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]float32: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]float64: - for k, v := range r { - dataMap[String(k)] = v - } - case map[string]bool: - for k, v := range r { - dataMap[k] = v - } - case map[string]int: - for k, v := range r { - dataMap[k] = v - } - case map[string]uint: - for k, v := range r { - dataMap[k] = v - } - case map[string]float32: - for k, v := range r { - dataMap[k] = v - } - case map[string]float64: - for k, v := range r { - dataMap[k] = v - } - case map[string]string: - for k, v := range r { - dataMap[k] = v - } - case map[string]interface{}: - if recursive == recursiveTypeTrue { - recursiveOption := usedOption - recursiveOption.Tags = newTags - // A copy of current map. - for k, v := range r { - dataMap[k] = doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: v, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - }, - ) - } - } else { - // It returns the map directly without any changing. - return r - } - case map[int]interface{}: - recursiveOption := usedOption - recursiveOption.Tags = newTags - for k, v := range r { - dataMap[String(k)] = doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: v, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - }, - ) - } - case map[int]string: - for k, v := range r { - dataMap[String(k)] = v - } - case map[uint]string: - for k, v := range r { - dataMap[String(k)] = v - } - - default: - // Not a common type, it then uses reflection for conversion. - var reflectValue reflect.Value - if v, ok := value.(reflect.Value); ok { - reflectValue = v - } else { - reflectValue = reflect.ValueOf(value) - } - reflectKind := reflectValue.Kind() - // If it is a pointer, we should find its real data type. - for reflectKind == reflect.Ptr { - reflectValue = reflectValue.Elem() - reflectKind = reflectValue.Kind() - } - switch reflectKind { - // If `value` is type of array, it converts the value of even number index as its key and - // the value of odd number index as its corresponding value, for example: - // []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"} - // []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil} - case reflect.Slice, reflect.Array: - length := reflectValue.Len() - for i := 0; i < length; i += 2 { - if i+1 < length { - dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface() - } else { - dataMap[String(reflectValue.Index(i).Interface())] = nil - } - } - case reflect.Map, reflect.Struct, reflect.Interface: - recursiveOption := usedOption - recursiveOption.Tags = newTags - convertedValue := doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: true, - Value: value, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - MustMapReturn: mustMapReturn, - }, - ) - if m, ok := convertedValue.(map[string]interface{}); ok { - return m - } - return nil - default: - return nil - } - } - return dataMap -} - -func getUsedMapOption(option ...MapOption) MapOption { - var usedOption MapOption - if len(option) > 0 { - usedOption = option[0] - } - return usedOption -} - -type doMapConvertForMapOrStructValueInput struct { - IsRoot bool // It returns directly if it is not root and with no recursive converting. - Value interface{} // Current operation value. - RecursiveType recursiveType // The type from top function entry. - RecursiveOption bool // Whether convert recursively for `current` operation. - Option MapOption // Map converting option. - MustMapReturn bool // Must return map instead of Value when empty. -} - -func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} { - if !in.IsRoot && !in.RecursiveOption { - return in.Value - } - - var reflectValue reflect.Value - if v, ok := in.Value.(reflect.Value); ok { - reflectValue = v - in.Value = v.Interface() - } else { - reflectValue = reflect.ValueOf(in.Value) - } - reflectKind := reflectValue.Kind() - // If it is a pointer, we should find its real data type. - for reflectKind == reflect.Ptr { - reflectValue = reflectValue.Elem() - reflectKind = reflectValue.Kind() - } - switch reflectKind { - case reflect.Map: - var ( - mapIter = reflectValue.MapRange() - dataMap = make(map[string]interface{}) - ) - for mapIter.Next() { - var ( - mapKeyValue = mapIter.Value() - mapValue interface{} - ) - switch { - case mapKeyValue.IsZero(): - if utils.CanCallIsNil(mapKeyValue) && mapKeyValue.IsNil() { - // quick check for nil value. - mapValue = nil - } else { - // in case of: - // exception recovered: reflect: call of reflect.Value.Interface on zero Value - mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface() - } - default: - mapValue = mapKeyValue.Interface() - } - dataMap[String(mapIter.Key().Interface())] = doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: mapValue, - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } - return dataMap - - case reflect.Struct: - var dataMap = make(map[string]interface{}) - // Map converting interface check. - if v, ok := in.Value.(localinterface.IMapStrAny); ok { - // Value copy, in case of concurrent safety. - for mapK, mapV := range v.MapStrAny() { - if in.RecursiveOption { - dataMap[mapK] = doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: mapV, - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } else { - dataMap[mapK] = mapV - } - } - if len(dataMap) > 0 { - return dataMap - } - } - // Using reflect for converting. - var ( - rtField reflect.StructField - rvField reflect.Value - reflectType = reflectValue.Type() // attribute value type. - mapKey = "" // mapKey may be the tag name or the struct attribute name. - ) - for i := 0; i < reflectValue.NumField(); i++ { - rtField = reflectType.Field(i) - rvField = reflectValue.Field(i) - // Only convert the public attributes. - fieldName := rtField.Name - if !utils.IsLetterUpper(fieldName[0]) { - continue - } - mapKey = "" - fieldTag := rtField.Tag - for _, tag := range in.Option.Tags { - if mapKey = fieldTag.Get(tag); mapKey != "" { - break - } - } - if mapKey == "" { - mapKey = fieldName - } else { - // Support json tag feature: -, omitempty - mapKey = strings.TrimSpace(mapKey) - if mapKey == "-" { - continue - } - array := strings.Split(mapKey, ",") - if len(array) > 1 { - switch strings.TrimSpace(array[1]) { - case "omitempty": - if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) { - continue - } else { - mapKey = strings.TrimSpace(array[0]) - } - default: - mapKey = strings.TrimSpace(array[0]) - } - } - if mapKey == "" { - mapKey = fieldName - } - } - if in.RecursiveOption || rtField.Anonymous { - // Do map converting recursively. - var ( - rvAttrField = rvField - rvAttrKind = rvField.Kind() - ) - if rvAttrKind == reflect.Ptr { - rvAttrField = rvField.Elem() - rvAttrKind = rvAttrField.Kind() - } - switch rvAttrKind { - case reflect.Struct: - // Embedded struct and has no fields, just ignores it. - // Eg: gmeta.Meta - if rvAttrField.Type().NumField() == 0 { - continue - } - var ( - hasNoTag = mapKey == fieldName - // DO NOT use rvAttrField.Interface() here, - // as it might be changed from pointer to struct. - rvInterface = rvField.Interface() - ) - switch { - case hasNoTag && rtField.Anonymous: - // It means this attribute field has no tag. - // Overwrite the attribute with sub-struct attribute fields. - anonymousValue := doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvInterface, - RecursiveType: in.RecursiveType, - RecursiveOption: true, - Option: in.Option, - }) - if m, ok := anonymousValue.(map[string]interface{}); ok { - for k, v := range m { - dataMap[k] = v - } - } else { - dataMap[mapKey] = rvInterface - } - - // It means this attribute field has desired tag. - case !hasNoTag && rtField.Anonymous: - dataMap[mapKey] = doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvInterface, - RecursiveType: in.RecursiveType, - RecursiveOption: true, - Option: in.Option, - }) - - default: - dataMap[mapKey] = doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvInterface, - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }) - } - - // The struct attribute is type of slice. - case reflect.Array, reflect.Slice: - length := rvAttrField.Len() - if length == 0 { - dataMap[mapKey] = rvAttrField.Interface() - break - } - array := make([]interface{}, length) - for arrayIndex := 0; arrayIndex < length; arrayIndex++ { - array[arrayIndex] = doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvAttrField.Index(arrayIndex).Interface(), - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } - dataMap[mapKey] = array - case reflect.Map: - var ( - mapIter = rvAttrField.MapRange() - nestedMap = make(map[string]interface{}) - ) - for mapIter.Next() { - nestedMap[String(mapIter.Key().Interface())] = doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: mapIter.Value().Interface(), - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } - dataMap[mapKey] = nestedMap - default: - if rvField.IsValid() { - dataMap[mapKey] = reflectValue.Field(i).Interface() - } else { - dataMap[mapKey] = nil - } - } - } else { - // No recursive map value converting - if rvField.IsValid() { - dataMap[mapKey] = reflectValue.Field(i).Interface() - } else { - dataMap[mapKey] = nil - } - } - } - if !in.MustMapReturn && len(dataMap) == 0 { - return in.Value - } - return dataMap - - // The given value is type of slice. - case reflect.Array, reflect.Slice: - length := reflectValue.Len() - if length == 0 { - break - } - array := make([]interface{}, reflectValue.Len()) - for i := 0; i < length; i++ { - array[i] = doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: reflectValue.Index(i).Interface(), - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }) - } - return array - - default: - } - return in.Value -} - // MapStrStr converts `value` to map[string]string. // Note that there might be data copy for this map type converting. -func MapStrStr(value interface{}, option ...MapOption) map[string]string { +func MapStrStr(value any, option ...MapOption) map[string]string { if r, ok := value.(map[string]string); ok { return r } @@ -565,7 +68,7 @@ func MapStrStr(value interface{}, option ...MapOption) map[string]string { // MapStrStrDeep converts `value` to map[string]string recursively. // Note that there might be data copy for this map type converting. // Deprecated: used MapStrStr instead. -func MapStrStrDeep(value interface{}, tags ...string) map[string]string { +func MapStrStrDeep(value any, tags ...string) map[string]string { if r, ok := value.(map[string]string); ok { return r } diff --git a/util/gconv/gconv_maptomap.go b/util/gconv/gconv_maptomap.go index bc40a82c059..5986c332209 100644 --- a/util/gconv/gconv_maptomap.go +++ b/util/gconv/gconv_maptomap.go @@ -6,130 +6,9 @@ package gconv -import ( - "reflect" - - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" -) - // MapToMap converts any map type variable `params` to another map type variable `pointer` // using reflect. // See doMapToMap. func MapToMap(params any, pointer any, mapping ...map[string]string) error { return Scan(params, pointer, mapping...) } - -// doMapToMap converts any map type variable `params` to another map type variable `pointer`. -// -// The parameter `params` can be any type of map, like: -// map[string]string, map[string]struct, map[string]*struct, reflect.Value, etc. -// -// The parameter `pointer` should be type of *map, like: -// map[int]string, map[string]struct, map[string]*struct, reflect.Value, etc. -// -// The optional parameter `mapping` is used for struct attribute to map key mapping, which makes -// sense only if the items of original map `params` is type struct. -func doMapToMap(cf *ConvertConfig, params any, pointer any, mapping ...map[string]string) (err error) { - var ( - paramsRv reflect.Value - paramsKind reflect.Kind - keyToAttributeNameMapping map[string]string - ) - if len(mapping) > 0 { - keyToAttributeNameMapping = mapping[0] - } - if v, ok := params.(reflect.Value); ok { - paramsRv = v - } else { - paramsRv = reflect.ValueOf(params) - } - paramsKind = paramsRv.Kind() - if paramsKind == reflect.Ptr { - paramsRv = paramsRv.Elem() - paramsKind = paramsRv.Kind() - } - if paramsKind != reflect.Map { - return doMapToMap(cf, Map(params), pointer, mapping...) - } - // Empty params map, no need continue. - if paramsRv.Len() == 0 { - return nil - } - var pointerRv reflect.Value - if v, ok := pointer.(reflect.Value); ok { - pointerRv = v - } else { - pointerRv = reflect.ValueOf(pointer) - } - pointerKind := pointerRv.Kind() - for pointerKind == reflect.Ptr { - pointerRv = pointerRv.Elem() - pointerKind = pointerRv.Kind() - } - if pointerKind != reflect.Map { - return gerror.NewCodef( - gcode.CodeInvalidParameter, - `destination pointer should be type of *map, but got: %s`, - pointerKind, - ) - } - defer func() { - // Catch the panic, especially the reflection operation panics. - if exception := recover(); exception != nil { - if v, ok := exception.(error); ok && gerror.HasStack(v) { - err = v - } else { - err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception) - } - } - }() - var ( - paramsKeys = paramsRv.MapKeys() - pointerKeyType = pointerRv.Type().Key() - pointerValueType = pointerRv.Type().Elem() - pointerValueKind = pointerValueType.Kind() - dataMap = reflect.MakeMapWithSize(pointerRv.Type(), len(paramsKeys)) - ) - // Retrieve the true element type of target map. - if pointerValueKind == reflect.Ptr { - pointerValueKind = pointerValueType.Elem().Kind() - } - for _, key := range paramsKeys { - mapValue := reflect.New(pointerValueType).Elem() - switch pointerValueKind { - case reflect.Map, reflect.Struct: - if err = doStruct( - paramsRv.MapIndex(key).Interface(), mapValue, keyToAttributeNameMapping, "", - ); err != nil { - return err - } - default: - mapValue.Set( - reflect.ValueOf( - doConvert( - cf, doConvertInput{ - FromValue: paramsRv.MapIndex(key).Interface(), - ToTypeName: pointerValueType.String(), - ReferValue: mapValue, - Extra: nil, - }), - ), - ) - } - var mapKey = reflect.ValueOf( - doConvert( - cf, - doConvertInput{ - FromValue: key.Interface(), - ToTypeName: pointerKeyType.Name(), - ReferValue: reflect.New(pointerKeyType).Elem().Interface(), - Extra: nil, - }, - ), - ) - dataMap.SetMapIndex(mapKey, mapValue) - } - pointerRv.Set(dataMap) - return nil -} diff --git a/util/gconv/gconv_maptomaps.go b/util/gconv/gconv_maptomaps.go index 330ed40d045..aaf9ae2743d 100644 --- a/util/gconv/gconv_maptomaps.go +++ b/util/gconv/gconv_maptomaps.go @@ -6,121 +6,8 @@ package gconv -import ( - "reflect" - - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" -) - // MapToMaps converts any slice type variable `params` to another map slice type variable `pointer`. // See doMapToMaps. -func MapToMaps(params interface{}, pointer interface{}, mapping ...map[string]string) error { +func MapToMaps(params any, pointer any, mapping ...map[string]string) error { return Scan(params, pointer, mapping...) } - -// doMapToMaps converts any map type variable `params` to another map slice variable `pointer`. -// -// The parameter `params` can be type of []map, []*map, []struct, []*struct. -// -// The parameter `pointer` should be type of []map, []*map. -// -// The optional parameter `mapping` is used for struct attribute to map key mapping, which makes -// sense only if the item of `params` is type struct. -func doMapToMaps(params interface{}, pointer interface{}, paramKeyToAttrMap ...map[string]string) (err error) { - // Params and its element type check. - var ( - paramsRv reflect.Value - paramsKind reflect.Kind - ) - if v, ok := params.(reflect.Value); ok { - paramsRv = v - } else { - paramsRv = reflect.ValueOf(params) - } - paramsKind = paramsRv.Kind() - if paramsKind == reflect.Ptr { - paramsRv = paramsRv.Elem() - paramsKind = paramsRv.Kind() - } - if paramsKind != reflect.Array && paramsKind != reflect.Slice { - return gerror.NewCode( - gcode.CodeInvalidParameter, - "params should be type of slice, example: []map/[]*map/[]struct/[]*struct", - ) - } - var ( - paramsElem = paramsRv.Type().Elem() - paramsElemKind = paramsElem.Kind() - ) - if paramsElemKind == reflect.Ptr { - paramsElem = paramsElem.Elem() - paramsElemKind = paramsElem.Kind() - } - if paramsElemKind != reflect.Map && - paramsElemKind != reflect.Struct && - paramsElemKind != reflect.Interface { - return gerror.NewCodef( - gcode.CodeInvalidParameter, - "params element should be type of map/*map/struct/*struct, but got: %s", - paramsElemKind, - ) - } - // Empty slice, no need continue. - if paramsRv.Len() == 0 { - return nil - } - // Pointer and its element type check. - var ( - pointerRv = reflect.ValueOf(pointer) - pointerKind = pointerRv.Kind() - ) - for pointerKind == reflect.Ptr { - pointerRv = pointerRv.Elem() - pointerKind = pointerRv.Kind() - } - if pointerKind != reflect.Array && pointerKind != reflect.Slice { - return gerror.NewCode(gcode.CodeInvalidParameter, "pointer should be type of *[]map/*[]*map") - } - var ( - pointerElemType = pointerRv.Type().Elem() - pointerElemKind = pointerElemType.Kind() - ) - if pointerElemKind == reflect.Ptr { - pointerElemKind = pointerElemType.Elem().Kind() - } - if pointerElemKind != reflect.Map { - return gerror.NewCode(gcode.CodeInvalidParameter, "pointer element should be type of map/*map") - } - defer func() { - // Catch the panic, especially the reflection operation panics. - if exception := recover(); exception != nil { - if v, ok := exception.(error); ok && gerror.HasStack(v) { - err = v - } else { - err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception) - } - } - }() - var ( - pointerSlice = reflect.MakeSlice(pointerRv.Type(), paramsRv.Len(), paramsRv.Len()) - ) - for i := 0; i < paramsRv.Len(); i++ { - var item reflect.Value - if pointerElemType.Kind() == reflect.Ptr { - item = reflect.New(pointerElemType.Elem()) - if err = MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap...); err != nil { - return err - } - pointerSlice.Index(i).Set(item) - } else { - item = reflect.New(pointerElemType) - if err = MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap...); err != nil { - return err - } - pointerSlice.Index(i).Set(item.Elem()) - } - } - pointerRv.Set(pointerSlice) - return -} diff --git a/util/gconv/gconv_scan.go b/util/gconv/gconv_scan.go index 5ced0c5d8bd..806438668af 100644 --- a/util/gconv/gconv_scan.go +++ b/util/gconv/gconv_scan.go @@ -6,15 +6,6 @@ package gconv -import ( - "reflect" - - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" -) - // Scan automatically checks the type of `pointer` and converts `params` to `pointer`. // It supports various types of parameter conversions, including: // 1. Basic types (int, string, float, etc.) @@ -26,326 +17,5 @@ import ( // The `paramKeyToAttrMap` parameter is used for mapping between attribute names and parameter keys. // TODO: change `paramKeyToAttrMap` to `ScanOption` to be more scalable; add `DeepCopy` option for `ScanOption`. func Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) { - return ScanWithConfig(defaultConvertConfig, srcValue, dstPointer, paramKeyToAttrMap...) -} - -func ScanWithConfig(cf *ConvertConfig, srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) { - // Check if srcValue is nil, in which case no conversion is needed - if srcValue == nil { - return nil - } - // Check if dstPointer is nil, which is an invalid parameter - if dstPointer == nil { - return gerror.NewCode( - gcode.CodeInvalidParameter, - `destination pointer should not be nil`, - ) - } - - // Get the reflection type and value of dstPointer - var ( - dstPointerReflectType reflect.Type - dstPointerReflectValue reflect.Value - ) - if v, ok := dstPointer.(reflect.Value); ok { - dstPointerReflectValue = v - dstPointerReflectType = v.Type() - } else { - dstPointerReflectValue = reflect.ValueOf(dstPointer) - // Do not use dstPointerReflectValue.Type() as dstPointerReflectValue might be zero - dstPointerReflectType = reflect.TypeOf(dstPointer) - } - - // Validate the kind of dstPointer - var dstPointerReflectKind = dstPointerReflectType.Kind() - if dstPointerReflectKind != reflect.Ptr { - // If dstPointer is not a pointer, try to get its address - if dstPointerReflectValue.CanAddr() { - dstPointerReflectValue = dstPointerReflectValue.Addr() - dstPointerReflectType = dstPointerReflectValue.Type() - dstPointerReflectKind = dstPointerReflectType.Kind() - } else { - // If dstPointer is not a pointer and cannot be addressed, return an error - return gerror.NewCodef( - gcode.CodeInvalidParameter, - `destination pointer should be type of pointer, but got type: %v`, - dstPointerReflectType, - ) - } - } - - // Get the reflection value of srcValue - var srcValueReflectValue reflect.Value - if v, ok := srcValue.(reflect.Value); ok { - srcValueReflectValue = v - } else { - srcValueReflectValue = reflect.ValueOf(srcValue) - } - - // Get the element type and kind of dstPointer - var ( - dstPointerReflectValueElem = dstPointerReflectValue.Elem() - dstPointerReflectValueElemKind = dstPointerReflectValueElem.Kind() - ) - // Handle multiple level pointers - if dstPointerReflectValueElemKind == reflect.Ptr { - if dstPointerReflectValueElem.IsNil() { - // Create a new value for the pointer dereference - nextLevelPtr := reflect.New(dstPointerReflectValueElem.Type().Elem()) - // Recursively scan into the dereferenced pointer - if err = Scan(srcValueReflectValue, nextLevelPtr, paramKeyToAttrMap...); err == nil { - dstPointerReflectValueElem.Set(nextLevelPtr) - } - return - } - return Scan(srcValueReflectValue, dstPointerReflectValueElem, paramKeyToAttrMap...) - } - - // Check if srcValue and dstPointer are the same type, in which case direct assignment can be performed - if ok := doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem); ok { - return nil - } - - // Handle different destination types - switch dstPointerReflectValueElemKind { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - // Convert to int type - dstPointerReflectValueElem.SetInt(Int64(srcValue)) - return nil - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - // Convert to uint type - dstPointerReflectValueElem.SetUint(Uint64(srcValue)) - return nil - - case reflect.Float32, reflect.Float64: - // Convert to float type - dstPointerReflectValueElem.SetFloat(Float64(srcValue)) - return nil - - case reflect.String: - // Convert to string type - dstPointerReflectValueElem.SetString(String(srcValue)) - return nil - - case reflect.Bool: - // Convert to bool type - dstPointerReflectValueElem.SetBool(Bool(srcValue)) - return nil - - case reflect.Slice: - // Handle slice type conversion - var ( - dstElemType = dstPointerReflectValueElem.Type().Elem() - dstElemKind = dstElemType.Kind() - ) - // The slice element might be a pointer type - if dstElemKind == reflect.Ptr { - dstElemType = dstElemType.Elem() - dstElemKind = dstElemType.Kind() - } - // Special handling for struct or map slice elements - if dstElemKind == reflect.Struct || dstElemKind == reflect.Map { - return doScanForComplicatedTypes(cf, srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...) - } - // Handle basic type slice conversions - var srcValueReflectValueKind = srcValueReflectValue.Kind() - if srcValueReflectValueKind == reflect.Slice || srcValueReflectValueKind == reflect.Array { - var ( - srcLen = srcValueReflectValue.Len() - newSlice = reflect.MakeSlice(dstPointerReflectValueElem.Type(), srcLen, srcLen) - ) - for i := 0; i < srcLen; i++ { - srcElem := srcValueReflectValue.Index(i).Interface() - switch dstElemType.Kind() { - case reflect.String: - newSlice.Index(i).SetString(String(srcElem)) - case reflect.Int: - newSlice.Index(i).SetInt(Int64(srcElem)) - case reflect.Int64: - newSlice.Index(i).SetInt(Int64(srcElem)) - case reflect.Float64: - newSlice.Index(i).SetFloat(Float64(srcElem)) - case reflect.Bool: - newSlice.Index(i).SetBool(Bool(srcElem)) - default: - return Scan( - srcElem, newSlice.Index(i).Addr().Interface(), paramKeyToAttrMap..., - ) - } - } - dstPointerReflectValueElem.Set(newSlice) - return nil - } - return doScanForComplicatedTypes(cf, srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...) - - default: - // Handle complex types (structs, maps, etc.) - return doScanForComplicatedTypes(cf, srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...) - } -} - -// doScanForComplicatedTypes handles the scanning of complex data types. -// It supports converting between maps, structs, and slices of these types. -// The function first attempts JSON conversion, then falls back to specific type handling. -// -// It supports `pointer` in type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct` for converting. -// -// Parameters: -// - srcValue: The source value to convert from -// - dstPointer: The destination pointer to convert to -// - dstPointerReflectType: The reflection type of the destination pointer -// - paramKeyToAttrMap: Optional mapping between parameter keys and struct attribute names -func doScanForComplicatedTypes( - cf *ConvertConfig, - srcValue, dstPointer any, - dstPointerReflectType reflect.Type, - paramKeyToAttrMap ...map[string]string, -) error { - // Try JSON conversion first - ok, err := doConvertWithJsonCheck(srcValue, dstPointer) - if err != nil { - return err - } - if ok { - return nil - } - - // Handle specific type conversions - var ( - dstPointerReflectTypeElem = dstPointerReflectType.Elem() - dstPointerReflectTypeElemKind = dstPointerReflectTypeElem.Kind() - keyToAttributeNameMapping map[string]string - ) - if len(paramKeyToAttrMap) > 0 { - keyToAttributeNameMapping = paramKeyToAttrMap[0] - } - - // Handle different destination types - switch dstPointerReflectTypeElemKind { - case reflect.Map: - // Convert map to map - return doMapToMap(cf, srcValue, dstPointer, paramKeyToAttrMap...) - - case reflect.Array, reflect.Slice: - var ( - sliceElem = dstPointerReflectTypeElem.Elem() - sliceElemKind = sliceElem.Kind() - ) - // Handle pointer elements - for sliceElemKind == reflect.Ptr { - sliceElem = sliceElem.Elem() - sliceElemKind = sliceElem.Kind() - } - if sliceElemKind == reflect.Map { - // Convert to slice of maps - return doMapToMaps(srcValue, dstPointer, paramKeyToAttrMap...) - } - // Convert to slice of structs - return doStructs(srcValue, dstPointer, keyToAttributeNameMapping, "") - - default: - // Convert to single struct - return doStruct(srcValue, dstPointer, keyToAttributeNameMapping, "") - } -} - -// doConvertWithTypeCheck supports `pointer` in type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct` -// for converting. -func doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem reflect.Value) (ok bool) { - if !dstPointerReflectValueElem.IsValid() || !srcValueReflectValue.IsValid() { - return false - } - switch { - // Examples: - // UploadFile => UploadFile - // []UploadFile => []UploadFile - // *UploadFile => *UploadFile - // *[]UploadFile => *[]UploadFile - // map[int][int] => map[int][int] - // []map[int][int] => []map[int][int] - // *[]map[int][int] => *[]map[int][int] - case dstPointerReflectValueElem.Type() == srcValueReflectValue.Type(): - dstPointerReflectValueElem.Set(srcValueReflectValue) - return true - - // Examples: - // UploadFile => *UploadFile - // []UploadFile => *[]UploadFile - // map[int][int] => *map[int][int] - // []map[int][int] => *[]map[int][int] - case dstPointerReflectValueElem.Kind() == reflect.Ptr && - dstPointerReflectValueElem.Elem().IsValid() && - dstPointerReflectValueElem.Elem().Type() == srcValueReflectValue.Type(): - dstPointerReflectValueElem.Elem().Set(srcValueReflectValue) - return true - - // Examples: - // *UploadFile => UploadFile - // *[]UploadFile => []UploadFile - // *map[int][int] => map[int][int] - // *[]map[int][int] => []map[int][int] - case srcValueReflectValue.Kind() == reflect.Ptr && - srcValueReflectValue.Elem().IsValid() && - dstPointerReflectValueElem.Type() == srcValueReflectValue.Elem().Type(): - dstPointerReflectValueElem.Set(srcValueReflectValue.Elem()) - return true - - default: - return false - } -} - -// doConvertWithJsonCheck attempts to convert the source value to the destination -// using JSON marshaling and unmarshaling. This is particularly useful for complex -// types that can be represented as JSON. -// -// Parameters: -// - srcValue: The source value to convert from -// - dstPointer: The destination pointer to convert to -// -// Returns: -// - bool: true if JSON conversion was successful -// - error: any error that occurred during conversion -func doConvertWithJsonCheck(srcValue any, dstPointer any) (ok bool, err error) { - switch valueResult := srcValue.(type) { - case []byte: - if json.Valid(valueResult) { - if dstPointerReflectType, ok := dstPointer.(reflect.Value); ok { - if dstPointerReflectType.Kind() == reflect.Ptr { - if dstPointerReflectType.IsNil() { - return false, nil - } - return true, json.UnmarshalUseNumber(valueResult, dstPointerReflectType.Interface()) - } else if dstPointerReflectType.CanAddr() { - return true, json.UnmarshalUseNumber(valueResult, dstPointerReflectType.Addr().Interface()) - } - } else { - return true, json.UnmarshalUseNumber(valueResult, dstPointer) - } - } - - case string: - if valueBytes := []byte(valueResult); json.Valid(valueBytes) { - if dstPointerReflectType, ok := dstPointer.(reflect.Value); ok { - if dstPointerReflectType.Kind() == reflect.Ptr { - if dstPointerReflectType.IsNil() { - return false, nil - } - return true, json.UnmarshalUseNumber(valueBytes, dstPointerReflectType.Interface()) - } else if dstPointerReflectType.CanAddr() { - return true, json.UnmarshalUseNumber(valueBytes, dstPointerReflectType.Addr().Interface()) - } - } else { - return true, json.UnmarshalUseNumber(valueBytes, dstPointer) - } - } - - default: - // The `params` might be struct that implements interface function Interface, eg: gvar.Var. - if v, ok := srcValue.(localinterface.IInterface); ok { - return doConvertWithJsonCheck(v.Interface(), dstPointer) - } - } - return false, nil + return defaultConverter.Scan(srcValue, dstPointer, paramKeyToAttrMap...) } diff --git a/util/gconv/gconv_struct.go b/util/gconv/gconv_struct.go index e47ee395f4f..d3fe9570cc6 100644 --- a/util/gconv/gconv_struct.go +++ b/util/gconv/gconv_struct.go @@ -6,19 +6,6 @@ package gconv -import ( - "reflect" - "strings" - - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/utils" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" - "github.com/gogf/gf/v2/util/gconv/internal/structcache" -) - // Struct maps the params key-value pairs to the corresponding struct object's attributes. // The third parameter `mapping` is unnecessary, indicating the mapping rules between the // custom key name and the attribute name(case-sensitive). @@ -40,625 +27,5 @@ func Struct(params any, pointer any, paramKeyToAttrMap ...map[string]string) (er // specified priorityTagAndFieldName for `params` key-value items to struct attribute names mapping. // The parameter `priorityTag` supports multiple priorityTagAndFieldName that can be joined with char ','. func StructTag(params any, pointer any, priorityTag string) (err error) { - return doStruct(params, pointer, nil, priorityTag) -} - -// doStruct is the core internal converting function for any data to struct. -func doStruct( - params any, - pointer any, - paramKeyToAttrMap map[string]string, - priorityTag string, -) (err error) { - return doStructWithConfig(defaultConvertConfig, params, pointer, paramKeyToAttrMap, priorityTag) -} - -// doStruct is the core internal converting function for any data to struct. -func doStructWithConfig( - cf *ConvertConfig, - params any, - pointer any, - paramKeyToAttrMap map[string]string, - priorityTag string, -) (err error) { - if params == nil { - // If `params` is nil, no conversion. - return nil - } - if pointer == nil { - return gerror.NewCode(gcode.CodeInvalidParameter, "object pointer cannot be nil") - } - - // JSON content converting. - ok, err := doConvertWithJsonCheck(params, pointer) - if err != nil { - return err - } - if ok { - return nil - } - - defer func() { - // Catch the panic, especially the reflection operation panics. - if exception := recover(); exception != nil { - if v, ok := exception.(error); ok && gerror.HasStack(v) { - err = v - } else { - err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception) - } - } - }() - - var ( - paramsReflectValue reflect.Value - paramsInterface any // DO NOT use `params` directly as it might be type `reflect.Value` - pointerReflectValue reflect.Value - pointerReflectKind reflect.Kind - pointerElemReflectValue reflect.Value // The reflection value to struct element. - ) - if v, ok := params.(reflect.Value); ok { - paramsReflectValue = v - } else { - paramsReflectValue = reflect.ValueOf(params) - } - paramsInterface = paramsReflectValue.Interface() - if v, ok := pointer.(reflect.Value); ok { - pointerReflectValue = v - pointerElemReflectValue = v - } else { - pointerReflectValue = reflect.ValueOf(pointer) - pointerReflectKind = pointerReflectValue.Kind() - if pointerReflectKind != reflect.Ptr { - return gerror.NewCodef( - gcode.CodeInvalidParameter, - "destination pointer should be type of '*struct', but got '%v'", - pointerReflectKind, - ) - } - // Using IsNil on reflect.Ptr variable is OK. - if !pointerReflectValue.IsValid() || pointerReflectValue.IsNil() { - return gerror.NewCode( - gcode.CodeInvalidParameter, - "destination pointer cannot be nil", - ) - } - pointerElemReflectValue = pointerReflectValue.Elem() - } - - // If `params` and `pointer` are the same type, the do directly assignment. - // For performance enhancement purpose. - if ok = doConvertWithTypeCheck(paramsReflectValue, pointerElemReflectValue); ok { - return nil - } - - // custom convert. - if ok, err = cf.callCustomConverter(paramsReflectValue, pointerReflectValue); ok { - return err - } - - // Normal unmarshalling interfaces checks. - if ok, err = bindVarToReflectValueWithInterfaceCheck(pointerReflectValue, paramsInterface); ok { - return err - } - - // It automatically creates struct object if necessary. - // For example, if `pointer` is **User, then `elem` is *User, which is a pointer to User. - if pointerElemReflectValue.Kind() == reflect.Ptr { - if !pointerElemReflectValue.IsValid() || pointerElemReflectValue.IsNil() { - e := reflect.New(pointerElemReflectValue.Type().Elem()) - pointerElemReflectValue.Set(e) - defer func() { - if err != nil { - // If it is converted failed, it reset the `pointer` to nil. - pointerReflectValue.Elem().Set(reflect.Zero(pointerReflectValue.Type().Elem())) - } - }() - } - // if v, ok := pointerElemReflectValue.Interface().(localinterface.IUnmarshalValue); ok { - // return v.UnmarshalValue(params) - // } - // Note that it's `pointerElemReflectValue` here not `pointerReflectValue`. - if ok, err = bindVarToReflectValueWithInterfaceCheck(pointerElemReflectValue, paramsInterface); ok { - return err - } - // Retrieve its element, may be struct at last. - pointerElemReflectValue = pointerElemReflectValue.Elem() - } - paramsMap, ok := paramsInterface.(map[string]any) - if !ok { - // paramsMap is the map[string]any type variable for params. - // DO NOT use MapDeep here. - paramsMap = doMapConvert(paramsInterface, recursiveTypeAuto, true) - if paramsMap == nil { - return gerror.NewCodef( - gcode.CodeInvalidParameter, - `convert params from "%#v" to "map[string]any" failed`, - params, - ) - } - } - // Nothing to be done as the parameters are empty. - if len(paramsMap) == 0 { - return nil - } - // Get struct info from cache or parse struct and cache the struct info. - cachedStructInfo := cf.internalConvertConfig.GetCachedStructInfo( - pointerElemReflectValue.Type(), priorityTag, - ) - // Nothing to be converted. - if cachedStructInfo == nil { - return nil - } - // For the structure types of 0 tagOrFiledNameToFieldInfoMap, - // they also need to be cached to prevent invalid logic - if cachedStructInfo.HasNoFields() { - return nil - } - var ( - // Indicates that those values have been used and cannot be reused. - usedParamsKeyOrTagNameMap = structcache.GetUsedParamsKeyOrTagNameMapFromPool() - cachedFieldInfo *structcache.CachedFieldInfo - paramsValue any - ) - defer structcache.PutUsedParamsKeyOrTagNameMapToPool(usedParamsKeyOrTagNameMap) - - // Firstly, search according to custom mapping rules. - // If a possible direct assignment is found, reduce the number of subsequent map searches. - for paramKey, fieldName := range paramKeyToAttrMap { - paramsValue, ok = paramsMap[paramKey] - if !ok { - continue - } - cachedFieldInfo = cachedStructInfo.GetFieldInfo(fieldName) - if cachedFieldInfo != nil { - fieldValue := cachedFieldInfo.GetFieldReflectValueFrom(pointerElemReflectValue) - if err = bindVarToStructField( - cf, - cachedFieldInfo, - fieldValue, - paramsValue, - paramKeyToAttrMap, - ); err != nil { - return err - } - if len(cachedFieldInfo.OtherSameNameField) > 0 { - if err = setOtherSameNameField( - cf, cachedFieldInfo, paramsValue, pointerReflectValue, paramKeyToAttrMap, - ); err != nil { - return err - } - } - usedParamsKeyOrTagNameMap[paramKey] = struct{}{} - } - } - // Already done converting for given `paramsMap`. - if len(usedParamsKeyOrTagNameMap) == len(paramsMap) { - return nil - } - return bindStructWithLoopFieldInfos( - cf, paramsMap, pointerElemReflectValue, paramKeyToAttrMap, usedParamsKeyOrTagNameMap, cachedStructInfo, - ) -} - -func setOtherSameNameField( - cf *ConvertConfig, - cachedFieldInfo *structcache.CachedFieldInfo, - srcValue any, - structValue reflect.Value, - paramKeyToAttrMap map[string]string, -) (err error) { - // loop the same field name of all sub attributes. - for _, otherFieldInfo := range cachedFieldInfo.OtherSameNameField { - fieldValue := cachedFieldInfo.GetOtherFieldReflectValueFrom(structValue, otherFieldInfo.FieldIndexes) - if err = bindVarToStructField(cf, otherFieldInfo, fieldValue, srcValue, paramKeyToAttrMap); err != nil { - return err - } - } - return nil -} - -func bindStructWithLoopFieldInfos( - cf *ConvertConfig, - paramsMap map[string]any, - structValue reflect.Value, - paramKeyToAttrMap map[string]string, - usedParamsKeyOrTagNameMap map[string]struct{}, - cachedStructInfo *structcache.CachedStructInfo, -) (err error) { - var ( - cachedFieldInfo *structcache.CachedFieldInfo - fuzzLastKey string - fieldValue reflect.Value - paramKey string - paramValue any - matched bool - ok bool - ) - for _, cachedFieldInfo = range cachedStructInfo.GetFieldConvertInfos() { - for _, fieldTag := range cachedFieldInfo.PriorityTagAndFieldName { - if paramValue, ok = paramsMap[fieldTag]; !ok { - continue - } - fieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue) - if err = bindVarToStructField( - cf, cachedFieldInfo, fieldValue, paramValue, paramKeyToAttrMap, - ); err != nil { - return err - } - // handle same field name in nested struct. - if len(cachedFieldInfo.OtherSameNameField) > 0 { - if err = setOtherSameNameField( - cf, cachedFieldInfo, paramValue, structValue, paramKeyToAttrMap, - ); err != nil { - return err - } - } - usedParamsKeyOrTagNameMap[fieldTag] = struct{}{} - matched = true - break - } - if matched { - matched = false - continue - } - - fuzzLastKey = cachedFieldInfo.LastFuzzyKey.Load().(string) - if paramValue, ok = paramsMap[fuzzLastKey]; !ok { - paramKey, paramValue = fuzzyMatchingFieldName( - cachedFieldInfo.RemoveSymbolsFieldName, paramsMap, usedParamsKeyOrTagNameMap, - ) - ok = paramKey != "" - cachedFieldInfo.LastFuzzyKey.Store(paramKey) - } - if ok { - fieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue) - if paramValue != nil { - if err = bindVarToStructField( - cf, cachedFieldInfo, fieldValue, paramValue, paramKeyToAttrMap, - ); err != nil { - return err - } - // handle same field name in nested struct. - if len(cachedFieldInfo.OtherSameNameField) > 0 { - if err = setOtherSameNameField( - cf, cachedFieldInfo, paramValue, structValue, paramKeyToAttrMap, - ); err != nil { - return err - } - } - } - usedParamsKeyOrTagNameMap[paramKey] = struct{}{} - } - } - return nil -} - -// fuzzy matching rule: -// to match field name and param key in case-insensitive and without symbols. -func fuzzyMatchingFieldName( - fieldName string, - paramsMap map[string]any, - usedParamsKeyMap map[string]struct{}, -) (string, any) { - for paramKey, paramValue := range paramsMap { - if _, ok := usedParamsKeyMap[paramKey]; ok { - continue - } - removeParamKeyUnderline := utils.RemoveSymbols(paramKey) - if strings.EqualFold(fieldName, removeParamKeyUnderline) { - return paramKey, paramValue - } - } - return "", nil -} - -// bindVarToStructField sets value to struct object attribute by name. -// each value to attribute converting comes into in this function. -func bindVarToStructField( - cf *ConvertConfig, - cachedFieldInfo *structcache.CachedFieldInfo, - fieldValue reflect.Value, - srcValue any, - paramKeyToAttrMap map[string]string, -) (err error) { - if !fieldValue.IsValid() { - return nil - } - // CanSet checks whether attribute is public accessible. - if !fieldValue.CanSet() { - return nil - } - defer func() { - if exception := recover(); exception != nil { - if err = bindVarToReflectValue(cf, fieldValue, srcValue, paramKeyToAttrMap); err != nil { - err = gerror.Wrapf(err, `error binding srcValue to attribute "%s"`, cachedFieldInfo.FieldName()) - } - } - }() - // Directly converting. - if empty.IsNil(srcValue) { - fieldValue.Set(reflect.Zero(fieldValue.Type())) - return nil - } - // Try to call custom converter. - // Issue: https://github.com/gogf/gf/issues/3099 - var ( - customConverterInput reflect.Value - ok bool - ) - if cachedFieldInfo.IsCustomConvert { - if customConverterInput, ok = srcValue.(reflect.Value); !ok { - customConverterInput = reflect.ValueOf(srcValue) - } - if ok, err = cf.callCustomConverter(customConverterInput, fieldValue); ok || err != nil { - return - } - } - if cachedFieldInfo.IsCommonInterface { - if ok, err = bindVarToReflectValueWithInterfaceCheck(fieldValue, srcValue); ok || err != nil { - return - } - } - // Common types use fast assignment logic - if cachedFieldInfo.ConvertFunc != nil { - return cachedFieldInfo.ConvertFunc(srcValue, fieldValue) - } - doConvertWithReflectValueSet( - cf, fieldValue, doConvertInput{ - FromValue: srcValue, - ToTypeName: cachedFieldInfo.StructField.Type.String(), - ReferValue: fieldValue, - }, - ) - return nil -} - -// bindVarToReflectValueWithInterfaceCheck does bind using common interfaces checks. -func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value any) (bool, error) { - var pointer any - if reflectValue.Kind() != reflect.Ptr && reflectValue.CanAddr() { - reflectValueAddr := reflectValue.Addr() - if reflectValueAddr.IsNil() || !reflectValueAddr.IsValid() { - return false, nil - } - // Not a pointer, but can token address, that makes it can be unmarshalled. - pointer = reflectValue.Addr().Interface() - } else { - if reflectValue.IsNil() || !reflectValue.IsValid() { - return false, nil - } - pointer = reflectValue.Interface() - } - // UnmarshalValue. - if v, ok := pointer.(localinterface.IUnmarshalValue); ok { - return ok, v.UnmarshalValue(value) - } - // UnmarshalText. - if v, ok := pointer.(localinterface.IUnmarshalText); ok { - var valueBytes []byte - if b, ok := value.([]byte); ok { - valueBytes = b - } else if s, ok := value.(string); ok { - valueBytes = []byte(s) - } else if f, ok := value.(localinterface.IString); ok { - valueBytes = []byte(f.String()) - } - if len(valueBytes) > 0 { - return ok, v.UnmarshalText(valueBytes) - } - } - // UnmarshalJSON. - if v, ok := pointer.(localinterface.IUnmarshalJSON); ok { - var valueBytes []byte - if b, ok := value.([]byte); ok { - valueBytes = b - } else if s, ok := value.(string); ok { - valueBytes = []byte(s) - } else if f, ok := value.(localinterface.IString); ok { - valueBytes = []byte(f.String()) - } - - if len(valueBytes) > 0 { - // If it is not a valid JSON string, it then adds char `"` on its both sides to make it is. - if !json.Valid(valueBytes) { - newValueBytes := make([]byte, len(valueBytes)+2) - newValueBytes[0] = '"' - newValueBytes[len(newValueBytes)-1] = '"' - copy(newValueBytes[1:], valueBytes) - valueBytes = newValueBytes - } - return ok, v.UnmarshalJSON(valueBytes) - } - } - if v, ok := pointer.(localinterface.ISet); ok { - v.Set(value) - return ok, nil - } - return false, nil -} - -// bindVarToReflectValue sets `value` to reflect value object `structFieldValue`. -func bindVarToReflectValue( - cf *ConvertConfig, structFieldValue reflect.Value, value any, paramKeyToAttrMap map[string]string, -) (err error) { - // JSON content converting. - ok, err := doConvertWithJsonCheck(value, structFieldValue) - if err != nil { - return err - } - if ok { - return nil - } - - kind := structFieldValue.Kind() - // Converting using `Set` interface implements, for some types. - switch kind { - case reflect.Slice, reflect.Array, reflect.Ptr, reflect.Interface: - if !structFieldValue.IsNil() { - if v, ok := structFieldValue.Interface().(localinterface.ISet); ok { - v.Set(value) - return nil - } - } - } - - // Converting using reflection by kind. - switch kind { - case reflect.Map: - return doMapToMap(cf, value, structFieldValue, paramKeyToAttrMap) - - case reflect.Struct: - // Recursively converting for struct attribute. - if err = doStruct(value, structFieldValue, nil, ""); err != nil { - // Note there's reflect conversion mechanism here. - structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type())) - } - - // Note that the slice element might be type of struct, - // so it uses Struct function doing the converting internally. - case reflect.Slice, reflect.Array: - var ( - reflectArray reflect.Value - reflectValue = reflect.ValueOf(value) - ) - if reflectValue.Kind() == reflect.Slice || reflectValue.Kind() == reflect.Array { - reflectArray = reflect.MakeSlice(structFieldValue.Type(), reflectValue.Len(), reflectValue.Len()) - if reflectValue.Len() > 0 { - var ( - elemType = reflectArray.Index(0).Type() - elemTypeName string - converted bool - ) - for i := 0; i < reflectValue.Len(); i++ { - converted = false - elemTypeName = elemType.Name() - if elemTypeName == "" { - elemTypeName = elemType.String() - } - var elem reflect.Value - if elemType.Kind() == reflect.Ptr { - elem = reflect.New(elemType.Elem()).Elem() - } else { - elem = reflect.New(elemType).Elem() - } - if elem.Kind() == reflect.Struct { - if err = doStruct(reflectValue.Index(i).Interface(), elem, nil, ""); err == nil { - converted = true - } - } - if !converted { - doConvertWithReflectValueSet( - cf, elem, doConvertInput{ - FromValue: reflectValue.Index(i).Interface(), - ToTypeName: elemTypeName, - ReferValue: elem, - }, - ) - } - if elemType.Kind() == reflect.Ptr { - // Before it sets the `elem` to array, do pointer converting if necessary. - elem = elem.Addr() - } - reflectArray.Index(i).Set(elem) - } - } - } else { - var ( - elem reflect.Value - elemType = structFieldValue.Type().Elem() - elemTypeName = elemType.Name() - converted bool - ) - switch reflectValue.Kind() { - case reflect.String: - // Value is empty string. - if reflectValue.IsZero() { - var elemKind = elemType.Kind() - // Try to find the original type kind of the slice element. - if elemKind == reflect.Ptr { - elemKind = elemType.Elem().Kind() - } - switch elemKind { - case reflect.String: - // Empty string cannot be assigned to string slice. - return nil - } - } - } - if elemTypeName == "" { - elemTypeName = elemType.String() - } - if elemType.Kind() == reflect.Ptr { - elem = reflect.New(elemType.Elem()).Elem() - } else { - elem = reflect.New(elemType).Elem() - } - if elem.Kind() == reflect.Struct { - if err = doStruct(value, elem, nil, ""); err == nil { - converted = true - } - } - if !converted { - doConvertWithReflectValueSet( - cf, elem, doConvertInput{ - FromValue: value, - ToTypeName: elemTypeName, - ReferValue: elem, - }, - ) - } - if elemType.Kind() == reflect.Ptr { - // Before it sets the `elem` to array, do pointer converting if necessary. - elem = elem.Addr() - } - reflectArray = reflect.MakeSlice(structFieldValue.Type(), 1, 1) - reflectArray.Index(0).Set(elem) - } - structFieldValue.Set(reflectArray) - - case reflect.Ptr: - if structFieldValue.IsNil() || structFieldValue.IsZero() { - // Nil or empty pointer, it creates a new one. - item := reflect.New(structFieldValue.Type().Elem()) - if ok, err = bindVarToReflectValueWithInterfaceCheck(item, value); ok { - structFieldValue.Set(item) - return err - } - elem := item.Elem() - if err = bindVarToReflectValue(cf, elem, value, paramKeyToAttrMap); err == nil { - structFieldValue.Set(elem.Addr()) - } - } else { - // Not empty pointer, it assigns values to it. - return bindVarToReflectValue(cf, structFieldValue.Elem(), value, paramKeyToAttrMap) - } - - // It mainly and specially handles the interface of nil value. - case reflect.Interface: - if value == nil { - // Specially. - structFieldValue.Set(reflect.ValueOf((*any)(nil))) - } else { - // Note there's reflect conversion mechanism here. - structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type())) - } - - default: - defer func() { - if exception := recover(); exception != nil { - err = gerror.NewCodef( - gcode.CodeInternalPanic, - `cannot convert value "%+v" to type "%s":%+v`, - value, - structFieldValue.Type().String(), - exception, - ) - } - }() - // It here uses reflect converting `value` to type of the attribute and assigns - // the result value to the attribute. It might fail and panic if the usual Go - // conversion rules do not allow conversion. - structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type())) - } - return nil + return defaultConverter.Struct(params, pointer, nil, priorityTag) } diff --git a/util/gconv/gconv_structs.go b/util/gconv/gconv_structs.go index 867fcdd2bbd..238b801e2db 100644 --- a/util/gconv/gconv_structs.go +++ b/util/gconv/gconv_structs.go @@ -6,128 +6,20 @@ package gconv -import ( - "reflect" - - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" -) - // Structs converts any slice to given struct slice. // Also see Scan, Struct. -func Structs(params interface{}, pointer interface{}, paramKeyToAttrMap ...map[string]string) (err error) { +func Structs(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) { return Scan(params, pointer, paramKeyToAttrMap...) } // SliceStruct is alias of Structs. -func SliceStruct(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) { +func SliceStruct(params any, pointer any, mapping ...map[string]string) (err error) { return Structs(params, pointer, mapping...) } // StructsTag acts as Structs but also with support for priority tag feature, which retrieves the // specified priorityTagAndFieldName for `params` key-value items to struct attribute names mapping. // The parameter `priorityTag` supports multiple priorityTagAndFieldName that can be joined with char ','. -func StructsTag(params interface{}, pointer interface{}, priorityTag string) (err error) { - return doStructs(params, pointer, nil, priorityTag) -} - -// doStructs converts any slice to given struct slice. -// -// It automatically checks and converts json string to []map if `params` is string/[]byte. -// -// The parameter `pointer` should be type of pointer to slice of struct. -// Note that if `pointer` is a pointer to another pointer of type of slice of struct, -// it will create the struct/pointer internally. -func doStructs( - params interface{}, pointer interface{}, paramKeyToAttrMap map[string]string, priorityTag string, -) (err error) { - defer func() { - // Catch the panic, especially the reflection operation panics. - if exception := recover(); exception != nil { - if v, ok := exception.(error); ok && gerror.HasStack(v) { - err = v - } else { - err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception) - } - } - }() - - // Pointer type check. - pointerRv, ok := pointer.(reflect.Value) - if !ok { - pointerRv = reflect.ValueOf(pointer) - if kind := pointerRv.Kind(); kind != reflect.Ptr { - return gerror.NewCodef( - gcode.CodeInvalidParameter, - "pointer should be type of pointer, but got: %v", kind, - ) - } - } - // Converting `params` to map slice. - var ( - paramsList []interface{} - paramsRv = reflect.ValueOf(params) - paramsKind = paramsRv.Kind() - ) - for paramsKind == reflect.Ptr { - paramsRv = paramsRv.Elem() - paramsKind = paramsRv.Kind() - } - switch paramsKind { - case reflect.Slice, reflect.Array: - paramsList = make([]interface{}, paramsRv.Len()) - for i := 0; i < paramsRv.Len(); i++ { - paramsList[i] = paramsRv.Index(i).Interface() - } - default: - var paramsMaps = Maps(params) - paramsList = make([]interface{}, len(paramsMaps)) - for i := 0; i < len(paramsMaps); i++ { - paramsList[i] = paramsMaps[i] - } - } - // If `params` is an empty slice, no conversion. - if len(paramsList) == 0 { - return nil - } - var ( - reflectElemArray = reflect.MakeSlice(pointerRv.Type().Elem(), len(paramsList), len(paramsList)) - itemType = reflectElemArray.Index(0).Type() - itemTypeKind = itemType.Kind() - pointerRvElem = pointerRv.Elem() - pointerRvLength = pointerRvElem.Len() - ) - if itemTypeKind == reflect.Ptr { - // Pointer element. - for i := 0; i < len(paramsList); i++ { - var tempReflectValue reflect.Value - if i < pointerRvLength { - // Might be nil. - tempReflectValue = pointerRvElem.Index(i).Elem() - } - if !tempReflectValue.IsValid() { - tempReflectValue = reflect.New(itemType.Elem()).Elem() - } - if err = doStruct(paramsList[i], tempReflectValue, paramKeyToAttrMap, priorityTag); err != nil { - return err - } - reflectElemArray.Index(i).Set(tempReflectValue.Addr()) - } - } else { - // Struct element. - for i := 0; i < len(paramsList); i++ { - var tempReflectValue reflect.Value - if i < pointerRvLength { - tempReflectValue = pointerRvElem.Index(i) - } else { - tempReflectValue = reflect.New(itemType).Elem() - } - if err = doStruct(paramsList[i], tempReflectValue, paramKeyToAttrMap, priorityTag); err != nil { - return err - } - reflectElemArray.Index(i).Set(tempReflectValue) - } - } - pointerRv.Elem().Set(reflectElemArray) - return nil +func StructsTag(params any, pointer any, priorityTag string) (err error) { + return defaultConverter.Structs(params, pointer, nil, priorityTag) } diff --git a/util/gconv/gconv_time.go b/util/gconv/gconv_time.go index 202b5b557a6..1102e0e875e 100644 --- a/util/gconv/gconv_time.go +++ b/util/gconv/gconv_time.go @@ -9,40 +9,21 @@ package gconv import ( "time" - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/utils" "github.com/gogf/gf/v2/os/gtime" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) // Time converts `any` to time.Time. -func Time(any interface{}, format ...string) time.Time { - // It's already this type. - if len(format) == 0 { - if v, ok := any.(time.Time); ok { - return v - } - } - if t := GTime(any, format...); t != nil { - return t.Time - } - return time.Time{} +func Time(any any, format ...string) time.Time { + t, _ := defaultConverter.Time(any, format...) + return t } // Duration converts `any` to time.Duration. // If `any` is string, then it uses time.ParseDuration to convert it. // If `any` is numeric, then it converts `any` as nanoseconds. -func Duration(any interface{}) time.Duration { - // It's already this type. - if v, ok := any.(time.Duration); ok { - return v - } - s := String(any) - if !utils.IsNumeric(s) { - d, _ := gtime.ParseDuration(s) - return d - } - return time.Duration(Int64(any)) +func Duration(any any) time.Duration { + d, _ := defaultConverter.Duration(any) + return d } // GTime converts `any` to *gtime.Time. @@ -50,43 +31,7 @@ func Duration(any interface{}) time.Duration { // It returns the converted value that matched the first format of the formats slice. // If no `format` given, it converts `any` using gtime.NewFromTimeStamp if `any` is numeric, // or using gtime.StrToTime if `any` is string. -func GTime(any interface{}, format ...string) *gtime.Time { - if empty.IsNil(any) { - return nil - } - if v, ok := any.(localinterface.IGTime); ok { - return v.GTime(format...) - } - // It's already this type. - if len(format) == 0 { - if v, ok := any.(*gtime.Time); ok { - return v - } - if t, ok := any.(time.Time); ok { - return gtime.New(t) - } - if t, ok := any.(*time.Time); ok { - return gtime.New(t) - } - } - s := String(any) - if len(s) == 0 { - return gtime.New() - } - // Priority conversion using given format. - if len(format) > 0 { - for _, item := range format { - t, err := gtime.StrToTimeFormat(s, item) - if t != nil && err == nil { - return t - } - } - return nil - } - if utils.IsNumeric(s) { - return gtime.NewFromTimeStamp(Int64(s)) - } else { - t, _ := gtime.StrToTime(s) - return t - } +func GTime(any any, format ...string) *gtime.Time { + t, _ := defaultConverter.GTime(any, format...) + return t } diff --git a/util/gconv/gconv_uint.go b/util/gconv/gconv_uint.go index 75e876f51b7..b7c9f66fd44 100644 --- a/util/gconv/gconv_uint.go +++ b/util/gconv/gconv_uint.go @@ -6,181 +6,32 @@ package gconv -import ( - "math" - "reflect" - "strconv" - - "github.com/gogf/gf/v2/encoding/gbinary" - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" -) - // Uint converts `any` to uint. func Uint(any any) uint { - v, _ := doUint(any) + v, _ := defaultConverter.Uint(any) return v } -func doUint(any any) (uint, error) { - if empty.IsNil(any) { - return 0, nil - } - if v, ok := any.(uint); ok { - return v, nil - } - v, err := doUint64(any) - return uint(v), err -} - // Uint8 converts `any` to uint8. func Uint8(any any) uint8 { - v, _ := doUint8(any) + v, _ := defaultConverter.Uint8(any) return v } -func doUint8(any any) (uint8, error) { - if empty.IsNil(any) { - return 0, nil - } - if v, ok := any.(uint8); ok { - return v, nil - } - v, err := doUint64(any) - return uint8(v), err -} - // Uint16 converts `any` to uint16. func Uint16(any any) uint16 { - v, _ := doUint16(any) + v, _ := defaultConverter.Uint16(any) return v } -func doUint16(any any) (uint16, error) { - if empty.IsNil(any) { - return 0, nil - } - if v, ok := any.(uint16); ok { - return v, nil - } - v, err := doUint64(any) - return uint16(v), err -} - // Uint32 converts `any` to uint32. func Uint32(any any) uint32 { - v, _ := doUint32(any) + v, _ := defaultConverter.Uint32(any) return v } -func doUint32(any any) (uint32, error) { - if empty.IsNil(any) { - return 0, nil - } - if v, ok := any.(uint32); ok { - return v, nil - } - v, err := doUint64(any) - return uint32(v), err -} - // Uint64 converts `any` to uint64. func Uint64(any any) uint64 { - v, _ := doUint64(any) + v, _ := defaultConverter.Uint64(any) return v } - -func doUint64(any any) (uint64, error) { - if empty.IsNil(any) { - return 0, nil - } - if v, ok := any.(uint64); ok { - return v, nil - } - rv := reflect.ValueOf(any) - switch rv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - val := rv.Int() - if val < 0 { - return uint64(val), gerror.NewCodef( - gcode.CodeInvalidParameter, - `cannot convert negative value "%d" to uint64`, - val, - ) - } - return uint64(val), nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return rv.Uint(), nil - case reflect.Uintptr: - return rv.Uint(), nil - case reflect.Float32, reflect.Float64: - val := rv.Float() - if val < 0 { - return uint64(val), gerror.NewCodef( - gcode.CodeInvalidParameter, - `cannot convert negative value "%f" to uint64`, - val, - ) - } - return uint64(val), nil - case reflect.Bool: - if rv.Bool() { - return 1, nil - } - return 0, nil - case reflect.Ptr: - if rv.IsNil() { - return 0, nil - } - if f, ok := any.(localinterface.IUint64); ok { - return f.Uint64(), nil - } - return doUint64(rv.Elem().Interface()) - case reflect.Slice: - if rv.Type().Elem().Kind() == reflect.Uint8 { - return gbinary.DecodeToUint64(rv.Bytes()), nil - } - return 0, gerror.NewCodef( - gcode.CodeInvalidParameter, - `unsupport slice type "%s" for converting to uint64`, - rv.Type().String(), - ) - case reflect.String: - var s = rv.String() - // Hexadecimal - if len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X') { - v, err := strconv.ParseUint(s[2:], 16, 64) - if err == nil { - return v, nil - } - return 0, gerror.WrapCodef( - gcode.CodeInvalidParameter, - err, - `cannot convert hexadecimal string "%s" to uint64`, - s, - ) - } - // Decimal - if v, err := strconv.ParseUint(s, 10, 64); err == nil { - return v, nil - } - // Float64 - if v, err := doFloat64(any); err == nil { - if math.IsNaN(v) { - return 0, nil - } - return uint64(v), nil - } - default: - if f, ok := any.(localinterface.IUint64); ok { - return f.Uint64(), nil - } - } - return 0, gerror.NewCodef( - gcode.CodeInvalidParameter, - `unsupport value type "%s" for converting to uint64`, - reflect.TypeOf(any).String(), - ) -} diff --git a/util/gconv/gconv_z_bench_struct_test.go b/util/gconv/gconv_z_bench_struct_test.go index 5fb2efe5928..a447181b3de 100644 --- a/util/gconv/gconv_z_bench_struct_test.go +++ b/util/gconv/gconv_z_bench_struct_test.go @@ -92,7 +92,7 @@ func Benchmark_Struct_Basic(b *testing.B) { func Benchmark_doStruct_Fields8_Basic_MapToStruct(b *testing.B) { for i := 0; i < b.N; i++ { - doStruct(structMapFields8, structPointer8, map[string]string{}, "") + defaultConverter.Struct(structMapFields8, structPointer8, map[string]string{}, "") } } diff --git a/util/gconv/internal/structcache/structcache.go b/util/gconv/internal/structcache/structcache.go index e99fd84c63f..ace2236da2c 100644 --- a/util/gconv/internal/structcache/structcache.go +++ b/util/gconv/internal/structcache/structcache.go @@ -10,9 +10,7 @@ package structcache import ( "reflect" "sync" - "time" - "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) @@ -23,45 +21,28 @@ type ConvertConfig struct { // map[reflect.Type]*CachedStructInfo cachedStructsInfoMap sync.Map - // customConvertTypeMap is used to store whether field types are registered to custom conversions - // For example: - // func (src *TypeA) (dst *TypeB,err error) - // This map will store `TypeB` for quick judgment during assignment. - // TODO remove? - customConvertTypeMap map[reflect.Type]struct{} + // typeConverterFuncMap is used to store whether field types are registered to custom conversions + typeConverterFuncMap map[reflect.Type]struct{} // anyToTypeConvertMap for custom type converting from any to its reflect.Value. anyToTypeConvertMap map[reflect.Type]AnyConvertFunc } -// CommonTypeConverter holds some converting functions of common types for internal usage. -type CommonTypeConverter struct { - Int64 func(v any) (int64, error) - Uint64 func(v any) (uint64, error) - String func(v any) (string, error) - Float32 func(v any) (float32, error) - Float64 func(v any) (float64, error) - Time func(v any, format ...string) (time.Time, error) - GTime func(v any, format ...string) (*gtime.Time, error) - Bytes func(v any) ([]byte, error) - Bool func(v any) (bool, error) -} - // NewConvertConfig creates and returns a new ConvertConfig object. func NewConvertConfig() *ConvertConfig { return &ConvertConfig{ cachedStructsInfoMap: sync.Map{}, - customConvertTypeMap: make(map[reflect.Type]struct{}), + typeConverterFuncMap: make(map[reflect.Type]struct{}), anyToTypeConvertMap: make(map[reflect.Type]AnyConvertFunc), } } -// RegisterCustomConvertType registers custom -func (cf *ConvertConfig) RegisterCustomConvertType(fieldType reflect.Type) { +// RegisterTypeConvertFunc registers converting function for custom type. +func (cf *ConvertConfig) RegisterTypeConvertFunc(fieldType reflect.Type) { if fieldType.Kind() == reflect.Ptr { fieldType = fieldType.Elem() } - cf.customConvertTypeMap[fieldType] = struct{}{} + cf.typeConverterFuncMap[fieldType] = struct{}{} } // RegisterAnyConvertFunc registers custom type converting function for specified type. diff --git a/util/gconv/internal/structcache/structcache_cached.go b/util/gconv/internal/structcache/structcache_cached.go index ef092f2922d..98611ae1661 100644 --- a/util/gconv/internal/structcache/structcache_cached.go +++ b/util/gconv/internal/structcache/structcache_cached.go @@ -29,7 +29,7 @@ func (cf *ConvertConfig) GetCachedStructInfo(structType reflect.Type, priorityTa // else create one. // it parses and generates a cache info for given struct type. - cachedStructInfo = NewCachedStructInfo(cf.customConvertTypeMap, cf.anyToTypeConvertMap) + cachedStructInfo = NewCachedStructInfo(cf.typeConverterFuncMap, cf.anyToTypeConvertMap) var ( priorityTagArray []string parentIndex = make([]int, 0) diff --git a/util/gconv/internal/structcache/structcache_cached_struct_info.go b/util/gconv/internal/structcache/structcache_cached_struct_info.go index e1e7e408489..b78a3806c1e 100644 --- a/util/gconv/internal/structcache/structcache_cached_struct_info.go +++ b/util/gconv/internal/structcache/structcache_cached_struct_info.go @@ -18,11 +18,9 @@ type CachedStructInfo struct { // All sub attributes field info slice. fieldConvertInfos []*CachedFieldInfo - // customConvertTypeMap is used to store whether field types are registered to custom conversions - // For example: - // func (src *TypeA) (dst *TypeB,err error) - // This map will store `TypeB` for quick judgment during assignment. - customConvertTypeMap map[reflect.Type]struct{} + // typeConverterFuncMap is used to store whether field types are registered to custom conversions, + // for enhance converting performance in runtime. + typeConverterFuncMap map[reflect.Type]struct{} // anyToTypeConvertMap for custom type converting from any to its reflect.Value. anyToTypeConvertMap map[reflect.Type]AnyConvertFunc @@ -39,13 +37,13 @@ type CachedStructInfo struct { // NewCachedStructInfo creates and returns a new CachedStructInfo object. func NewCachedStructInfo( - customConvertTypeMap map[reflect.Type]struct{}, + typeConverterFuncMap map[reflect.Type]struct{}, anyToTypeConvertMap map[reflect.Type]AnyConvertFunc, ) *CachedStructInfo { return &CachedStructInfo{ tagOrFiledNameToFieldInfoMap: make(map[string]*CachedFieldInfo), fieldConvertInfos: make([]*CachedFieldInfo, 0), - customConvertTypeMap: customConvertTypeMap, + typeConverterFuncMap: typeConverterFuncMap, anyToTypeConvertMap: anyToTypeConvertMap, } } @@ -188,6 +186,6 @@ func (csi *CachedStructInfo) checkTypeHasCustomConvert(fieldType reflect.Type) b if fieldType.Kind() == reflect.Ptr { fieldType = fieldType.Elem() } - _, ok := csi.customConvertTypeMap[fieldType] + _, ok := csi.typeConverterFuncMap[fieldType] return ok } From bd5b6a1ed747c9d3d69a87d1fc4f5806ffb8814c Mon Sep 17 00:00:00 2001 From: John Guo Date: Sun, 2 Mar 2025 22:16:48 +0800 Subject: [PATCH 24/48] up --- util/gconv/gconv.go | 2 +- util/gconv/gconv_convert.go | 18 +- util/gconv/gconv_converter.go | 529 ++-------- util/gconv/gconv_converter_bool.go | 3 +- util/gconv/gconv_converter_builtin.go | 16 +- util/gconv/gconv_converter_bytes.go | 2 +- util/gconv/gconv_converter_convert.go | 522 ++++++++++ util/gconv/gconv_converter_doMapConvert.go | 504 +++++++++ util/gconv/gconv_converter_float.go | 4 +- util/gconv/gconv_converter_int.go | 10 +- util/gconv/gconv_converter_map.go | 983 +++++++++--------- util/gconv/gconv_converter_maps.go | 7 - util/gconv/gconv_converter_maptomap.go | 42 +- util/gconv/gconv_converter_maptomaps.go | 2 +- util/gconv/gconv_converter_rune.go | 4 +- util/gconv/gconv_converter_scan.go | 4 +- util/gconv/gconv_converter_slice_any.go | 142 +++ util/gconv/gconv_converter_slice_float.go | 417 ++++++++ util/gconv/gconv_converter_slice_int.go | 536 ++++++++++ util/gconv/gconv_converter_slice_map.go | 59 ++ util/gconv/gconv_converter_slice_str.go | 216 ++++ util/gconv/gconv_converter_slice_uint.go | 527 ++++++++++ util/gconv/gconv_converter_string.go | 2 +- util/gconv/gconv_converter_struct.go | 12 +- util/gconv/gconv_converter_structs.go | 2 +- util/gconv/gconv_converter_time.go | 6 +- util/gconv/gconv_converter_uint.go | 10 +- util/gconv/gconv_slice_any.go | 132 +-- util/gconv/gconv_slice_float.go | 278 +---- util/gconv/gconv_slice_int.go | 453 +------- util/gconv/gconv_slice_str.go | 149 +-- util/gconv/gconv_slice_uint.go | 432 +------- .../gconv/internal/structcache/structcache.go | 19 +- .../structcache/structcache_cached.go | 8 +- 34 files changed, 3598 insertions(+), 2454 deletions(-) create mode 100644 util/gconv/gconv_converter_convert.go create mode 100644 util/gconv/gconv_converter_doMapConvert.go delete mode 100644 util/gconv/gconv_converter_maps.go create mode 100644 util/gconv/gconv_converter_slice_any.go create mode 100644 util/gconv/gconv_converter_slice_float.go create mode 100644 util/gconv/gconv_converter_slice_int.go create mode 100644 util/gconv/gconv_converter_slice_map.go create mode 100644 util/gconv/gconv_converter_slice_str.go create mode 100644 util/gconv/gconv_converter_slice_uint.go diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index 00748eb06ec..be49d479a4a 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -39,7 +39,7 @@ var ( // RegisterConverter registers custom converter. // Deprecated: use RegisterTypeConverterFunc instead for clear func RegisterConverter(fn any) (err error) { - return defaultConverter.RegisterTypeConverterFunc(fn) + return RegisterTypeConverterFunc(fn) } // RegisterTypeConverterFunc registers custom converter. diff --git a/util/gconv/gconv_convert.go b/util/gconv/gconv_convert.go index 6603469a23d..53db02f1cd9 100644 --- a/util/gconv/gconv_convert.go +++ b/util/gconv/gconv_convert.go @@ -15,7 +15,7 @@ import ( // The optional parameter `extraParams` is used for additional necessary parameter for this conversion. // It supports common basic types conversion as its conversion based on type name string. func Convert(fromValue any, toTypeName string, extraParams ...any) any { - return defaultConverter.doConvert( + result, _ := defaultConverter.doConvert( doConvertInput{ FromValue: fromValue, ToTypeName: toTypeName, @@ -23,6 +23,7 @@ func Convert(fromValue any, toTypeName string, extraParams ...any) any { Extra: extraParams, }, ) + return result } // ConvertWithRefer converts the variable `fromValue` to the type referred by value `referValue`. @@ -36,12 +37,11 @@ func ConvertWithRefer(fromValue any, referValue any, extraParams ...any) any { } else { referValueRf = reflect.ValueOf(referValue) } - return defaultConverter.doConvert( - doConvertInput{ - FromValue: fromValue, - ToTypeName: referValueRf.Type().String(), - ReferValue: referValue, - Extra: extraParams, - }, - ) + result, _ := defaultConverter.doConvert(doConvertInput{ + FromValue: fromValue, + ToTypeName: referValueRf.Type().String(), + ReferValue: referValue, + Extra: extraParams, + }) + return result } diff --git a/util/gconv/gconv_converter.go b/util/gconv/gconv_converter.go index 2a4803cd32a..68fe71a14f8 100644 --- a/util/gconv/gconv_converter.go +++ b/util/gconv/gconv_converter.go @@ -7,14 +7,11 @@ package gconv import ( - "context" "reflect" "time" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/intlog" - "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/gconv/internal/structcache" ) @@ -26,9 +23,49 @@ type ( ) // Converter is the manager for type converting. -type Converter struct { - internalConvertConfig *structcache.ConvertConfig - typeConverterFuncMap map[converterInType]map[converterOutType]converterFunc +type Converter interface { + RegisterTypeConverterFunc(fn any) (err error) + ConverterForInt + ConverterForUint + String(any any) (string, error) + Bool(any any) (bool, error) + Bytes(any any) ([]byte, error) + Float32(any any) (float32, error) + Float64(any any) (float64, error) + + doMapConvert( + value any, recursive recursiveType, mustMapReturn bool, option ...MapOption, + ) map[string]any + MapToMap(params any, pointer any, mapping ...map[string]string) (err error) + MapToMaps(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) + Rune(any any) (rune, error) + Runes(any any) ([]rune, error) + Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) + Time(any interface{}, format ...string) (time.Time, error) + Duration(any interface{}) (time.Duration, error) + GTime(any interface{}, format ...string) (*gtime.Time, error) +} + +type ConverterForInt interface { + Int(any any) (int, error) + Int8(any any) (int8, error) + Int16(any any) (int16, error) + Int32(any any) (int32, error) + Int64(any any) (int64, error) +} + +type ConverterForUint interface { + Uint(any any) (uint, error) + Uint8(any any) (uint8, error) + Uin16(any any) (uint16, error) + Uint32(any any) (uint32, error) + Uint64(any any) (uint64, error) +} + +// impConverter implements the interface Converter. +type impConverter struct { + internalConverter *structcache.Converter + typeConverterFuncMap map[converterInType]map[converterOutType]converterFunc } var ( @@ -57,48 +94,15 @@ var ( ) // NewConverter creates and returns management object for type converting. -func NewConverter() *Converter { - cf := &Converter{ - internalConvertConfig: structcache.NewConvertConfig(), - typeConverterFuncMap: make(map[converterInType]map[converterOutType]converterFunc), +func NewConverter() *impConverter { + cf := &impConverter{ + internalConverter: structcache.NewConverter(), + typeConverterFuncMap: make(map[converterInType]map[converterOutType]converterFunc), } cf.registerBuiltInConverter() return cf } -func (c *Converter) registerBuiltInConverter() { - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForInt64, intType, int8Type, int16Type, int32Type, int64Type, - ) - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForUint64, uintType, uint8Type, uint16Type, uint32Type, uint64Type, - ) - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForString, stringType, - ) - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForFloat64, float32Type, float64Type, - ) - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForBool, boolType, - ) - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForBytes, bytesType, - ) - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForTime, timeType, - ) - c.registerAnyConvertFuncForTypes( - c.builtInAnyConvertFuncForGTime, gtimeType, - ) -} - -func (c *Converter) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, types ...reflect.Type) { - for _, t := range types { - c.internalConvertConfig.RegisterAnyConvertFunc(t, convertFunc) - } -} - // RegisterTypeConverterFunc registers custom converter. // It must be registered before you use this custom converting feature. // It is suggested to do it in boot procedure of the process. @@ -107,7 +111,7 @@ func (c *Converter) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, t // 1. The parameter `fn` must be defined as pattern `func(T1) (T2, error)`. // It will convert type `T1` to type `T2`. // 2. The `T1` should not be type of pointer, but the `T2` should be type of pointer. -func (c *Converter) RegisterTypeConverterFunc(fn any) (err error) { +func (c *impConverter) RegisterTypeConverterFunc(fn any) (err error) { var ( fnReflectType = reflect.TypeOf(fn) errType = reflect.TypeOf((*error)(nil)).Elem() @@ -160,418 +164,39 @@ func (c *Converter) RegisterTypeConverterFunc(fn any) (err error) { return } registeredOutTypeMap[outType] = reflect.ValueOf(fn) - c.internalConvertConfig.RegisterTypeConvertFunc(outType) + c.internalConverter.RegisterTypeConvertFunc(outType) return } -func (c *Converter) getRegisteredConverterFuncAndSrcType( - srcReflectValue, dstReflectValueForRefer reflect.Value, -) (f converterFunc, srcType reflect.Type, ok bool) { - if len(c.typeConverterFuncMap) == 0 { - return reflect.Value{}, nil, false - } - srcType = srcReflectValue.Type() - for srcType.Kind() == reflect.Pointer { - srcType = srcType.Elem() - } - var registeredOutTypeMap map[converterOutType]converterFunc - // firstly, it searches the map by input parameter type. - registeredOutTypeMap, ok = c.typeConverterFuncMap[srcType] - if !ok { - return reflect.Value{}, nil, false - } - var dstType = dstReflectValueForRefer.Type() - if dstType.Kind() == reflect.Pointer { - // Might be **struct, which is support as designed. - if dstType.Elem().Kind() == reflect.Pointer { - dstType = dstType.Elem() - } - } else if dstReflectValueForRefer.IsValid() && dstReflectValueForRefer.CanAddr() { - dstType = dstReflectValueForRefer.Addr().Type() - } else { - dstType = reflect.PointerTo(dstType) - } - // secondly, it searches the input parameter type map - // and finds the result converter function by the output parameter type. - f, ok = registeredOutTypeMap[dstType] - if !ok { - return reflect.Value{}, nil, false - } - return -} - -func (c *Converter) callCustomConverterWithRefer( - srcReflectValue, referReflectValue reflect.Value, -) (dstReflectValue reflect.Value, converted bool, err error) { - registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, referReflectValue) - if !ok { - return reflect.Value{}, false, nil - } - dstReflectValue = reflect.New(referReflectValue.Type()).Elem() - converted, err = c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) - return -} - -// callCustomConverter call the custom converter. It will try some possible type. -func (c *Converter) callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) { - registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, dstReflectValue) - if !ok { - return false, nil - } - return c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) -} - -func (c *Converter) doCallCustomConverter( - srcReflectValue reflect.Value, - dstReflectValue reflect.Value, - registeredConverterFunc converterFunc, - srcType reflect.Type, -) (converted bool, err error) { - // Converter function calling. - for srcReflectValue.Type() != srcType { - srcReflectValue = srcReflectValue.Elem() - } - result := registeredConverterFunc.Call([]reflect.Value{srcReflectValue}) - if !result[1].IsNil() { - return false, result[1].Interface().(error) - } - // The `result[0]` is a pointer. - if result[0].IsNil() { - return false, nil - } - var resultValue = result[0] - for { - if resultValue.Type() == dstReflectValue.Type() && dstReflectValue.CanSet() { - dstReflectValue.Set(resultValue) - converted = true - } else if dstReflectValue.Kind() == reflect.Pointer { - if resultValue.Type() == dstReflectValue.Elem().Type() && dstReflectValue.Elem().CanSet() { - dstReflectValue.Elem().Set(resultValue) - converted = true - } - } - if converted { - break - } - if resultValue.Kind() == reflect.Pointer { - resultValue = resultValue.Elem() - } else { - break - } - } - - return converted, nil -} - -type doConvertInput struct { - FromValue interface{} // Value that is converted from. - ToTypeName string // Target value type name in string. - ReferValue interface{} // Referred value, a value in type `ToTypeName`. Note that its type might be reflect.Value. - Extra []interface{} // Extra values for implementing the converting. - - // Marks that the value is already converted and set to `ReferValue`. Caller can ignore the returned result. - // It is an attribute for internal usage purpose. - alreadySetToReferValue bool -} - -// doConvert does commonly use types converting. -func (c *Converter) doConvert(in doConvertInput) (convertedValue interface{}) { - switch in.ToTypeName { - case "int": - return Int(in.FromValue) - case "*int": - if _, ok := in.FromValue.(*int); ok { - return in.FromValue - } - v := Int(in.FromValue) - return &v - - case "int8": - return Int8(in.FromValue) - case "*int8": - if _, ok := in.FromValue.(*int8); ok { - return in.FromValue - } - v := Int8(in.FromValue) - return &v - - case "int16": - return Int16(in.FromValue) - case "*int16": - if _, ok := in.FromValue.(*int16); ok { - return in.FromValue - } - v := Int16(in.FromValue) - return &v - - case "int32": - return Int32(in.FromValue) - case "*int32": - if _, ok := in.FromValue.(*int32); ok { - return in.FromValue - } - v := Int32(in.FromValue) - return &v - - case "int64": - return Int64(in.FromValue) - case "*int64": - if _, ok := in.FromValue.(*int64); ok { - return in.FromValue - } - v := Int64(in.FromValue) - return &v - - case "uint": - return Uint(in.FromValue) - case "*uint": - if _, ok := in.FromValue.(*uint); ok { - return in.FromValue - } - v := Uint(in.FromValue) - return &v - - case "uint8": - return Uint8(in.FromValue) - case "*uint8": - if _, ok := in.FromValue.(*uint8); ok { - return in.FromValue - } - v := Uint8(in.FromValue) - return &v - - case "uint16": - return Uint16(in.FromValue) - case "*uint16": - if _, ok := in.FromValue.(*uint16); ok { - return in.FromValue - } - v := Uint16(in.FromValue) - return &v - - case "uint32": - return Uint32(in.FromValue) - case "*uint32": - if _, ok := in.FromValue.(*uint32); ok { - return in.FromValue - } - v := Uint32(in.FromValue) - return &v - - case "uint64": - return Uint64(in.FromValue) - case "*uint64": - if _, ok := in.FromValue.(*uint64); ok { - return in.FromValue - } - v := Uint64(in.FromValue) - return &v - - case "float32": - return Float32(in.FromValue) - case "*float32": - if _, ok := in.FromValue.(*float32); ok { - return in.FromValue - } - v := Float32(in.FromValue) - return &v - - case "float64": - return Float64(in.FromValue) - case "*float64": - if _, ok := in.FromValue.(*float64); ok { - return in.FromValue - } - v := Float64(in.FromValue) - return &v - - case "bool": - return Bool(in.FromValue) - case "*bool": - if _, ok := in.FromValue.(*bool); ok { - return in.FromValue - } - v := Bool(in.FromValue) - return &v - - case "string": - return String(in.FromValue) - case "*string": - if _, ok := in.FromValue.(*string); ok { - return in.FromValue - } - v := String(in.FromValue) - return &v - - case "[]byte": - return Bytes(in.FromValue) - case "[]int": - return Ints(in.FromValue) - case "[]int32": - return Int32s(in.FromValue) - case "[]int64": - return Int64s(in.FromValue) - case "[]uint": - return Uints(in.FromValue) - case "[]uint8": - return Bytes(in.FromValue) - case "[]uint32": - return Uint32s(in.FromValue) - case "[]uint64": - return Uint64s(in.FromValue) - case "[]float32": - return Float32s(in.FromValue) - case "[]float64": - return Float64s(in.FromValue) - case "[]string": - return Strings(in.FromValue) - - case "Time", "time.Time": - if len(in.Extra) > 0 { - return Time(in.FromValue, String(in.Extra[0])) - } - return Time(in.FromValue) - case "*time.Time": - var v time.Time - if len(in.Extra) > 0 { - v = Time(in.FromValue, String(in.Extra[0])) - } else { - if _, ok := in.FromValue.(*time.Time); ok { - return in.FromValue - } - v = Time(in.FromValue) - } - return &v - - case "GTime", "gtime.Time": - if len(in.Extra) > 0 { - if v := GTime(in.FromValue, String(in.Extra[0])); v != nil { - return *v - } else { - return *gtime.New() - } - } - if v := GTime(in.FromValue); v != nil { - return *v - } else { - return *gtime.New() - } - case "*gtime.Time": - if len(in.Extra) > 0 { - if v := GTime(in.FromValue, String(in.Extra[0])); v != nil { - return v - } else { - return gtime.New() - } - } - if v := GTime(in.FromValue); v != nil { - return v - } else { - return gtime.New() - } - - case "Duration", "time.Duration": - return Duration(in.FromValue) - case "*time.Duration": - if _, ok := in.FromValue.(*time.Duration); ok { - return in.FromValue - } - v := Duration(in.FromValue) - return &v - - case "map[string]string": - return MapStrStr(in.FromValue) - - case "map[string]interface {}": - return Map(in.FromValue) - - case "[]map[string]interface {}": - return Maps(in.FromValue) - - case "RawMessage", "json.RawMessage": - // issue 3449 - bytes, err := json.Marshal(in.FromValue) - if err != nil { - intlog.Errorf(context.TODO(), `%+v`, err) - } - return bytes - - default: - if in.ReferValue != nil { - var referReflectValue reflect.Value - if v, ok := in.ReferValue.(reflect.Value); ok { - referReflectValue = v - } else { - referReflectValue = reflect.ValueOf(in.ReferValue) - } - var fromReflectValue reflect.Value - if v, ok := in.FromValue.(reflect.Value); ok { - fromReflectValue = v - } else { - fromReflectValue = reflect.ValueOf(in.FromValue) - } - - // custom converter. - if dstReflectValue, ok, _ := c.callCustomConverterWithRefer(fromReflectValue, referReflectValue); ok { - return dstReflectValue.Interface() - } - - defer func() { - if recover() != nil { - in.alreadySetToReferValue = false - if err := c.bindVarToReflectValue(referReflectValue, in.FromValue, nil); err == nil { - in.alreadySetToReferValue = true - convertedValue = referReflectValue.Interface() - } - } - }() - switch referReflectValue.Kind() { - case reflect.Ptr: - // Type converting for custom type pointers. - // Eg: - // type PayMode int - // type Req struct{ - // Mode *PayMode - // } - // - // Struct(`{"Mode": 1000}`, &req) - originType := referReflectValue.Type().Elem() - switch originType.Kind() { - case reflect.Struct: - // Not support some kinds. - default: - in.ToTypeName = originType.Kind().String() - in.ReferValue = nil - refElementValue := reflect.ValueOf(c.doConvert(in)) - originTypeValue := reflect.New(refElementValue.Type()).Elem() - originTypeValue.Set(refElementValue) - in.alreadySetToReferValue = true - return originTypeValue.Addr().Convert(referReflectValue.Type()).Interface() - } - - case reflect.Map: - var targetValue = reflect.New(referReflectValue.Type()).Elem() - if err := c.MapToMap(in.FromValue, targetValue); err == nil { - in.alreadySetToReferValue = true - } - return targetValue.Interface() - - default: - - } - in.ToTypeName = referReflectValue.Kind().String() - in.ReferValue = nil - in.alreadySetToReferValue = true - convertedValue = reflect.ValueOf(c.doConvert(in)).Convert(referReflectValue.Type()).Interface() - return convertedValue - } - return in.FromValue - } +func (c *impConverter) registerBuiltInConverter() { + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForInt64, intType, int8Type, int16Type, int32Type, int64Type, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForUint64, uintType, uint8Type, uint16Type, uint32Type, uint64Type, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForString, stringType, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForFloat64, float32Type, float64Type, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForBool, boolType, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForBytes, bytesType, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForTime, timeType, + ) + c.registerAnyConvertFuncForTypes( + c.builtInAnyConvertFuncForGTime, gtimeType, + ) } -func (c *Converter) doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput) { - convertedValue := c.doConvert(in) - if !in.alreadySetToReferValue { - reflectValue.Set(reflect.ValueOf(convertedValue)) +func (c *impConverter) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, types ...reflect.Type) { + for _, t := range types { + c.internalConverter.RegisterAnyConvertFunc(t, convertFunc) } } diff --git a/util/gconv/gconv_converter_bool.go b/util/gconv/gconv_converter_bool.go index 94e26bea237..5b080d9df92 100644 --- a/util/gconv/gconv_converter_bool.go +++ b/util/gconv/gconv_converter_bool.go @@ -14,7 +14,8 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *Converter) Bool(any any) (bool, error) { +// Bool converts `any` to bool. +func (c *impConverter) Bool(any any) (bool, error) { if empty.IsNil(any) { return false, nil } diff --git a/util/gconv/gconv_converter_builtin.go b/util/gconv/gconv_converter_builtin.go index 5009e6d462f..2d8a3aee101 100644 --- a/util/gconv/gconv_converter_builtin.go +++ b/util/gconv/gconv_converter_builtin.go @@ -13,7 +13,7 @@ import ( "github.com/gogf/gf/v2/os/gtime" ) -func (c *Converter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) error { v, err := c.Int64(from) if err != nil { return err @@ -22,7 +22,7 @@ func (c *Converter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) er return nil } -func (c *Converter) builtInAnyConvertFuncForUint64(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForUint64(from any, to reflect.Value) error { v, err := c.Uint64(from) if err != nil { return err @@ -31,7 +31,7 @@ func (c *Converter) builtInAnyConvertFuncForUint64(from any, to reflect.Value) e return nil } -func (c *Converter) builtInAnyConvertFuncForString(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForString(from any, to reflect.Value) error { v, err := c.String(from) if err != nil { return err @@ -40,7 +40,7 @@ func (c *Converter) builtInAnyConvertFuncForString(from any, to reflect.Value) e return nil } -func (c *Converter) builtInAnyConvertFuncForFloat64(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForFloat64(from any, to reflect.Value) error { v, err := c.Float64(from) if err != nil { return err @@ -49,7 +49,7 @@ func (c *Converter) builtInAnyConvertFuncForFloat64(from any, to reflect.Value) return nil } -func (c *Converter) builtInAnyConvertFuncForBool(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForBool(from any, to reflect.Value) error { v, err := c.Bool(from) if err != nil { return err @@ -58,7 +58,7 @@ func (c *Converter) builtInAnyConvertFuncForBool(from any, to reflect.Value) err return nil } -func (c *Converter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) error { v, err := c.Bytes(from) if err != nil { return err @@ -67,7 +67,7 @@ func (c *Converter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) er return nil } -func (c *Converter) builtInAnyConvertFuncForTime(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForTime(from any, to reflect.Value) error { t, err := c.Time(from) if err != nil { return err @@ -76,7 +76,7 @@ func (c *Converter) builtInAnyConvertFuncForTime(from any, to reflect.Value) err return nil } -func (c *Converter) builtInAnyConvertFuncForGTime(from any, to reflect.Value) error { +func (c *impConverter) builtInAnyConvertFuncForGTime(from any, to reflect.Value) error { v, err := c.GTime(from) if err != nil { return err diff --git a/util/gconv/gconv_converter_bytes.go b/util/gconv/gconv_converter_bytes.go index 3237bd4bbfd..437f9078021 100644 --- a/util/gconv/gconv_converter_bytes.go +++ b/util/gconv/gconv_converter_bytes.go @@ -17,7 +17,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *Converter) Bytes(any any) ([]byte, error) { +func (c *impConverter) Bytes(any any) ([]byte, error) { if empty.IsNil(any) { return nil, nil } diff --git a/util/gconv/gconv_converter_convert.go b/util/gconv/gconv_converter_convert.go new file mode 100644 index 00000000000..74ca4660ff7 --- /dev/null +++ b/util/gconv/gconv_converter_convert.go @@ -0,0 +1,522 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + "time" + + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/os/gtime" +) + +type doConvertInput struct { + FromValue any // Value that is converted from. + ToTypeName string // Target value type name in string. + ReferValue any // Referred value, a value in type `ToTypeName`. Note that its type might be reflect.Value. + Extra []any // Extra values for implementing the converting. + + // Marks that the value is already converted and set to `ReferValue`. Caller can ignore the returned result. + // It is an attribute for internal usage purpose. + alreadySetToReferValue bool +} + +// doConvert does commonly use types converting. +func (c *impConverter) doConvert(in doConvertInput) (convertedValue any, err error) { + switch in.ToTypeName { + case "int": + return c.Int(in.FromValue) + case "*int": + if _, ok := in.FromValue.(*int); ok { + return in.FromValue, nil + } + v, err := c.Int(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "int8": + return c.Int8(in.FromValue) + case "*int8": + if _, ok := in.FromValue.(*int8); ok { + return in.FromValue, nil + } + v, err := c.Int8(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "int16": + return c.Int16(in.FromValue) + case "*int16": + if _, ok := in.FromValue.(*int16); ok { + return in.FromValue, nil + } + v, err := c.Int16(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "int32": + return c.Int32(in.FromValue) + case "*int32": + if _, ok := in.FromValue.(*int32); ok { + return in.FromValue, nil + } + v, err := c.Int32(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "int64": + return c.Int64(in.FromValue) + case "*int64": + if _, ok := in.FromValue.(*int64); ok { + return in.FromValue, nil + } + v, err := c.Int64(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "uint": + return c.Uint(in.FromValue) + case "*uint": + if _, ok := in.FromValue.(*uint); ok { + return in.FromValue, nil + } + v, err := c.Uint(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "uint8": + return c.Uint8(in.FromValue) + case "*uint8": + if _, ok := in.FromValue.(*uint8); ok { + return in.FromValue, nil + } + v, err := c.Uint8(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "uint16": + return c.Uint16(in.FromValue) + case "*uint16": + if _, ok := in.FromValue.(*uint16); ok { + return in.FromValue, nil + } + v, err := c.Uint16(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "uint32": + return c.Uint32(in.FromValue) + case "*uint32": + if _, ok := in.FromValue.(*uint32); ok { + return in.FromValue, nil + } + v, err := c.Uint32(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "uint64": + return c.Uint64(in.FromValue) + case "*uint64": + if _, ok := in.FromValue.(*uint64); ok { + return in.FromValue, nil + } + v, err := c.Uint64(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "float32": + return c.Float32(in.FromValue) + case "*float32": + if _, ok := in.FromValue.(*float32); ok { + return in.FromValue, nil + } + v, err := c.Float32(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "float64": + return c.Float64(in.FromValue) + case "*float64": + if _, ok := in.FromValue.(*float64); ok { + return in.FromValue, nil + } + v, err := c.Float64(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "bool": + return c.Bool(in.FromValue) + case "*bool": + if _, ok := in.FromValue.(*bool); ok { + return in.FromValue, nil + } + v, err := c.Bool(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "string": + return c.String(in.FromValue) + case "*string": + if _, ok := in.FromValue.(*string); ok { + return in.FromValue, nil + } + v, err := c.String(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "[]byte": + return c.Bytes(in.FromValue) + case "[]int": + return c.SliceInt(in.FromValue, SliceOption{}) + case "[]int32": + return c.SliceInt32(in.FromValue, SliceOption{}) + case "[]int64": + return c.SliceInt64(in.FromValue, SliceOption{}) + case "[]uint": + return c.SliceUint(in.FromValue, SliceOption{}) + case "[]uint8": + return c.Bytes(in.FromValue) + case "[]uint32": + return c.SliceUint32(in.FromValue, SliceOption{}) + case "[]uint64": + return c.SliceUint64(in.FromValue, SliceOption{}) + case "[]float32": + return c.SliceFloat32(in.FromValue, SliceOption{}) + case "[]float64": + return c.SliceFloat64(in.FromValue, SliceOption{}) + case "[]string": + return c.SliceStr(in.FromValue, SliceOption{}) + + case "Time", "time.Time": + if len(in.Extra) > 0 { + s, err := c.String(in.Extra[0]) + if err != nil { + return nil, err + } + return c.Time(in.FromValue, s) + } + return c.Time(in.FromValue) + case "*time.Time": + var v time.Time + if len(in.Extra) > 0 { + s, err := c.String(in.Extra[0]) + if err != nil { + return time.Time{}, err + } + v, err = c.Time(in.FromValue, s) + if err != nil { + return time.Time{}, err + } + } else { + if _, ok := in.FromValue.(*time.Time); ok { + return in.FromValue, nil + } + v, err = c.Time(in.FromValue) + if err != nil { + return time.Time{}, err + } + } + return &v, nil + + case "GTime", "gtime.Time": + if len(in.Extra) > 0 { + s, err := c.String(in.Extra[0]) + if err != nil { + return *gtime.New(), err + } + v, err := c.GTime(in.FromValue, s) + if err != nil { + return *gtime.New(), err + } + if v != nil { + return *v, nil + } + return *gtime.New(), nil + } + v, err := c.GTime(in.FromValue) + if err != nil { + return *gtime.New(), err + } + if v != nil { + return *v, nil + } + return *gtime.New(), nil + case "*gtime.Time": + if len(in.Extra) > 0 { + s, err := c.String(in.Extra[0]) + if err != nil { + return gtime.New(), err + } + v, err := c.GTime(in.FromValue, s) + if err != nil { + return gtime.New(), err + } + if v != nil { + return v, nil + } + return gtime.New(), nil + } + v, err := c.GTime(in.FromValue) + if err != nil { + return gtime.New(), err + } + if v != nil { + return v, nil + } + return gtime.New(), nil + + case "Duration", "time.Duration": + return c.Duration(in.FromValue) + case "*time.Duration": + if _, ok := in.FromValue.(*time.Duration); ok { + return in.FromValue, nil + } + v, err := c.Duration(in.FromValue) + if err != nil { + return nil, err + } + return &v, nil + + case "map[string]string": + return MapStrStr(in.FromValue), nil + + case "map[string]interface {}": + return Map(in.FromValue, MapOption{}), nil + + case "[]map[string]interface {}": + return c.SliceMap(in.FromValue, SliceOption{}, MapOption{}) + + case "RawMessage", "json.RawMessage": + // issue 3449 + bytes, err := json.Marshal(in.FromValue) + if err != nil { + return nil, err + } + return bytes, nil + + default: + if in.ReferValue != nil { + var referReflectValue reflect.Value + if v, ok := in.ReferValue.(reflect.Value); ok { + referReflectValue = v + } else { + referReflectValue = reflect.ValueOf(in.ReferValue) + } + var fromReflectValue reflect.Value + if v, ok := in.FromValue.(reflect.Value); ok { + fromReflectValue = v + } else { + fromReflectValue = reflect.ValueOf(in.FromValue) + } + + // custom converter. + dstReflectValue, ok, err := c.callCustomConverterWithRefer(fromReflectValue, referReflectValue) + if err != nil { + return nil, err + } + if ok { + return dstReflectValue.Interface(), nil + } + + defer func() { + if recover() != nil { + in.alreadySetToReferValue = false + if err := c.bindVarToReflectValue(referReflectValue, in.FromValue, nil); err == nil { + in.alreadySetToReferValue = true + convertedValue = referReflectValue.Interface() + } + } + }() + switch referReflectValue.Kind() { + case reflect.Ptr: + // Type converting for custom type pointers. + // Eg: + // type PayMode int + // type Req struct{ + // Mode *PayMode + // } + // + // Struct(`{"Mode": 1000}`, &req) + originType := referReflectValue.Type().Elem() + switch originType.Kind() { + case reflect.Struct: + // Not support some kinds. + default: + in.ToTypeName = originType.Kind().String() + in.ReferValue = nil + result, err := c.doConvert(in) + if err != nil { + return nil, err + } + refElementValue := reflect.ValueOf(result) + originTypeValue := reflect.New(refElementValue.Type()).Elem() + originTypeValue.Set(refElementValue) + in.alreadySetToReferValue = true + return originTypeValue.Addr().Convert(referReflectValue.Type()).Interface(), nil + } + + case reflect.Map: + var targetValue = reflect.New(referReflectValue.Type()).Elem() + if err = c.MapToMap(in.FromValue, targetValue); err == nil { + in.alreadySetToReferValue = true + } + return targetValue.Interface(), nil + + default: + + } + in.ToTypeName = referReflectValue.Kind().String() + in.ReferValue = nil + in.alreadySetToReferValue = true + result, err := c.doConvert(in) + if err != nil { + return nil, err + } + convertedValue = reflect.ValueOf(result).Convert(referReflectValue.Type()).Interface() + return convertedValue, nil + } + return in.FromValue, nil + } +} + +func (c *impConverter) doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput) error { + convertedValue, err := c.doConvert(in) + if err != nil { + return err + } + if !in.alreadySetToReferValue { + reflectValue.Set(reflect.ValueOf(convertedValue)) + } + return err +} + +func (c *impConverter) getRegisteredConverterFuncAndSrcType( + srcReflectValue, dstReflectValueForRefer reflect.Value, +) (f converterFunc, srcType reflect.Type, ok bool) { + if len(c.typeConverterFuncMap) == 0 { + return reflect.Value{}, nil, false + } + srcType = srcReflectValue.Type() + for srcType.Kind() == reflect.Pointer { + srcType = srcType.Elem() + } + var registeredOutTypeMap map[converterOutType]converterFunc + // firstly, it searches the map by input parameter type. + registeredOutTypeMap, ok = c.typeConverterFuncMap[srcType] + if !ok { + return reflect.Value{}, nil, false + } + var dstType = dstReflectValueForRefer.Type() + if dstType.Kind() == reflect.Pointer { + // Might be **struct, which is support as designed. + if dstType.Elem().Kind() == reflect.Pointer { + dstType = dstType.Elem() + } + } else if dstReflectValueForRefer.IsValid() && dstReflectValueForRefer.CanAddr() { + dstType = dstReflectValueForRefer.Addr().Type() + } else { + dstType = reflect.PointerTo(dstType) + } + // secondly, it searches the input parameter type map + // and finds the result converter function by the output parameter type. + f, ok = registeredOutTypeMap[dstType] + if !ok { + return reflect.Value{}, nil, false + } + return +} + +func (c *impConverter) callCustomConverterWithRefer( + srcReflectValue, referReflectValue reflect.Value, +) (dstReflectValue reflect.Value, converted bool, err error) { + registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, referReflectValue) + if !ok { + return reflect.Value{}, false, nil + } + dstReflectValue = reflect.New(referReflectValue.Type()).Elem() + converted, err = c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) + return +} + +// callCustomConverter call the custom converter. It will try some possible type. +func (c *impConverter) callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) { + registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, dstReflectValue) + if !ok { + return false, nil + } + return c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) +} + +func (c *impConverter) doCallCustomConverter( + srcReflectValue reflect.Value, + dstReflectValue reflect.Value, + registeredConverterFunc converterFunc, + srcType reflect.Type, +) (converted bool, err error) { + // Converter function calling. + for srcReflectValue.Type() != srcType { + srcReflectValue = srcReflectValue.Elem() + } + result := registeredConverterFunc.Call([]reflect.Value{srcReflectValue}) + if !result[1].IsNil() { + return false, result[1].Interface().(error) + } + // The `result[0]` is a pointer. + if result[0].IsNil() { + return false, nil + } + var resultValue = result[0] + for { + if resultValue.Type() == dstReflectValue.Type() && dstReflectValue.CanSet() { + dstReflectValue.Set(resultValue) + converted = true + } else if dstReflectValue.Kind() == reflect.Pointer { + if resultValue.Type() == dstReflectValue.Elem().Type() && dstReflectValue.Elem().CanSet() { + dstReflectValue.Elem().Set(resultValue) + converted = true + } + } + if converted { + break + } + if resultValue.Kind() == reflect.Pointer { + resultValue = resultValue.Elem() + } else { + break + } + } + + return converted, nil +} diff --git a/util/gconv/gconv_converter_doMapConvert.go b/util/gconv/gconv_converter_doMapConvert.go new file mode 100644 index 00000000000..fb33f965853 --- /dev/null +++ b/util/gconv/gconv_converter_doMapConvert.go @@ -0,0 +1,504 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + "strings" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" + "github.com/gogf/gf/v2/util/gtag" +) + +// MapConvert implements the map converting. +// It automatically checks and converts json string to map if `value` is string/[]byte. +// +// TODO completely implement the recursive converting for all types, especially the map. +func (c *impConverter) doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool, option ...MapOption) map[string]interface{} { + if value == nil { + return nil + } + // It redirects to its underlying value if it has implemented interface iVal. + if v, ok := value.(localinterface.IVal); ok { + value = v.Val() + } + var ( + usedOption = getUsedMapOption(option...) + newTags = gtag.StructTagPriority + ) + if usedOption.Deep { + recursive = recursiveTypeTrue + } + switch len(usedOption.Tags) { + case 0: + // No need handling. + case 1: + newTags = append(strings.Split(usedOption.Tags[0], ","), gtag.StructTagPriority...) + default: + newTags = append(usedOption.Tags, gtag.StructTagPriority...) + } + // Assert the common combination of types, and finally it uses reflection. + dataMap := make(map[string]interface{}) + switch r := value.(type) { + case string: + // If it is a JSON string, automatically unmarshal it! + if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { + if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil { + return nil + } + } else { + return nil + } + case []byte: + // If it is a JSON string, automatically unmarshal it! + if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { + if err := json.UnmarshalUseNumber(r, &dataMap); err != nil { + return nil + } + } else { + return nil + } + case map[interface{}]interface{}: + recursiveOption := usedOption + recursiveOption.Tags = newTags + for k, v := range r { + dataMap[String(k)] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: v, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + }, + ) + } + case map[interface{}]string: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]int: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]uint: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]float32: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]float64: + for k, v := range r { + dataMap[String(k)] = v + } + case map[string]bool: + for k, v := range r { + dataMap[k] = v + } + case map[string]int: + for k, v := range r { + dataMap[k] = v + } + case map[string]uint: + for k, v := range r { + dataMap[k] = v + } + case map[string]float32: + for k, v := range r { + dataMap[k] = v + } + case map[string]float64: + for k, v := range r { + dataMap[k] = v + } + case map[string]string: + for k, v := range r { + dataMap[k] = v + } + case map[string]interface{}: + if recursive == recursiveTypeTrue { + recursiveOption := usedOption + recursiveOption.Tags = newTags + // A copy of current map. + for k, v := range r { + dataMap[k] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: v, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + }, + ) + } + } else { + // It returns the map directly without any changing. + return r + } + case map[int]interface{}: + recursiveOption := usedOption + recursiveOption.Tags = newTags + for k, v := range r { + dataMap[String(k)] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: v, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + }, + ) + } + case map[int]string: + for k, v := range r { + dataMap[String(k)] = v + } + case map[uint]string: + for k, v := range r { + dataMap[String(k)] = v + } + + default: + // Not a common type, it then uses reflection for conversion. + var reflectValue reflect.Value + if v, ok := value.(reflect.Value); ok { + reflectValue = v + } else { + reflectValue = reflect.ValueOf(value) + } + reflectKind := reflectValue.Kind() + // If it is a pointer, we should find its real data type. + for reflectKind == reflect.Ptr { + reflectValue = reflectValue.Elem() + reflectKind = reflectValue.Kind() + } + switch reflectKind { + // If `value` is type of array, it converts the value of even number index as its key and + // the value of odd number index as its corresponding value, for example: + // []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"} + // []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil} + case reflect.Slice, reflect.Array: + length := reflectValue.Len() + for i := 0; i < length; i += 2 { + if i+1 < length { + dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface() + } else { + dataMap[String(reflectValue.Index(i).Interface())] = nil + } + } + case reflect.Map, reflect.Struct, reflect.Interface: + recursiveOption := usedOption + recursiveOption.Tags = newTags + convertedValue := c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: true, + Value: value, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + MustMapReturn: mustMapReturn, + }, + ) + if m, ok := convertedValue.(map[string]interface{}); ok { + return m + } + return nil + default: + return nil + } + } + return dataMap +} + +func getUsedMapOption(option ...MapOption) MapOption { + var usedOption MapOption + if len(option) > 0 { + usedOption = option[0] + } + return usedOption +} + +type doMapConvertForMapOrStructValueInput struct { + IsRoot bool // It returns directly if it is not root and with no recursive converting. + Value interface{} // Current operation value. + RecursiveType recursiveType // The type from top function entry. + RecursiveOption bool // Whether convert recursively for `current` operation. + Option MapOption // Map converting option. + MustMapReturn bool // Must return map instead of Value when empty. +} + +func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} { + if !in.IsRoot && !in.RecursiveOption { + return in.Value + } + + var reflectValue reflect.Value + if v, ok := in.Value.(reflect.Value); ok { + reflectValue = v + in.Value = v.Interface() + } else { + reflectValue = reflect.ValueOf(in.Value) + } + reflectKind := reflectValue.Kind() + // If it is a pointer, we should find its real data type. + for reflectKind == reflect.Ptr { + reflectValue = reflectValue.Elem() + reflectKind = reflectValue.Kind() + } + switch reflectKind { + case reflect.Map: + var ( + mapIter = reflectValue.MapRange() + dataMap = make(map[string]interface{}) + ) + for mapIter.Next() { + var ( + mapKeyValue = mapIter.Value() + mapValue interface{} + ) + switch { + case mapKeyValue.IsZero(): + if utils.CanCallIsNil(mapKeyValue) && mapKeyValue.IsNil() { + // quick check for nil value. + mapValue = nil + } else { + // in case of: + // exception recovered: reflect: call of reflect.Value.Interface on zero Value + mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface() + } + default: + mapValue = mapKeyValue.Interface() + } + dataMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: mapValue, + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } + return dataMap + + case reflect.Struct: + var dataMap = make(map[string]interface{}) + // Map converting interface check. + if v, ok := in.Value.(localinterface.IMapStrAny); ok { + // Value copy, in case of concurrent safety. + for mapK, mapV := range v.MapStrAny() { + if in.RecursiveOption { + dataMap[mapK] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: mapV, + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } else { + dataMap[mapK] = mapV + } + } + if len(dataMap) > 0 { + return dataMap + } + } + // Using reflect for converting. + var ( + rtField reflect.StructField + rvField reflect.Value + reflectType = reflectValue.Type() // attribute value type. + mapKey = "" // mapKey may be the tag name or the struct attribute name. + ) + for i := 0; i < reflectValue.NumField(); i++ { + rtField = reflectType.Field(i) + rvField = reflectValue.Field(i) + // Only convert the public attributes. + fieldName := rtField.Name + if !utils.IsLetterUpper(fieldName[0]) { + continue + } + mapKey = "" + fieldTag := rtField.Tag + for _, tag := range in.Option.Tags { + if mapKey = fieldTag.Get(tag); mapKey != "" { + break + } + } + if mapKey == "" { + mapKey = fieldName + } else { + // Support json tag feature: -, omitempty + mapKey = strings.TrimSpace(mapKey) + if mapKey == "-" { + continue + } + array := strings.Split(mapKey, ",") + if len(array) > 1 { + switch strings.TrimSpace(array[1]) { + case "omitempty": + if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) { + continue + } else { + mapKey = strings.TrimSpace(array[0]) + } + default: + mapKey = strings.TrimSpace(array[0]) + } + } + if mapKey == "" { + mapKey = fieldName + } + } + if in.RecursiveOption || rtField.Anonymous { + // Do map converting recursively. + var ( + rvAttrField = rvField + rvAttrKind = rvField.Kind() + ) + if rvAttrKind == reflect.Ptr { + rvAttrField = rvField.Elem() + rvAttrKind = rvAttrField.Kind() + } + switch rvAttrKind { + case reflect.Struct: + // Embedded struct and has no fields, just ignores it. + // Eg: gmeta.Meta + if rvAttrField.Type().NumField() == 0 { + continue + } + var ( + hasNoTag = mapKey == fieldName + // DO NOT use rvAttrField.Interface() here, + // as it might be changed from pointer to struct. + rvInterface = rvField.Interface() + ) + switch { + case hasNoTag && rtField.Anonymous: + // It means this attribute field has no tag. + // Overwrite the attribute with sub-struct attribute fields. + anonymousValue := c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvInterface, + RecursiveType: in.RecursiveType, + RecursiveOption: true, + Option: in.Option, + }) + if m, ok := anonymousValue.(map[string]interface{}); ok { + for k, v := range m { + dataMap[k] = v + } + } else { + dataMap[mapKey] = rvInterface + } + + // It means this attribute field has desired tag. + case !hasNoTag && rtField.Anonymous: + dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvInterface, + RecursiveType: in.RecursiveType, + RecursiveOption: true, + Option: in.Option, + }) + + default: + dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvInterface, + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }) + } + + // The struct attribute is type of slice. + case reflect.Array, reflect.Slice: + length := rvAttrField.Len() + if length == 0 { + dataMap[mapKey] = rvAttrField.Interface() + break + } + array := make([]interface{}, length) + for arrayIndex := 0; arrayIndex < length; arrayIndex++ { + array[arrayIndex] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvAttrField.Index(arrayIndex).Interface(), + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } + dataMap[mapKey] = array + case reflect.Map: + var ( + mapIter = rvAttrField.MapRange() + nestedMap = make(map[string]interface{}) + ) + for mapIter.Next() { + nestedMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: mapIter.Value().Interface(), + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } + dataMap[mapKey] = nestedMap + default: + if rvField.IsValid() { + dataMap[mapKey] = reflectValue.Field(i).Interface() + } else { + dataMap[mapKey] = nil + } + } + } else { + // No recursive map value converting + if rvField.IsValid() { + dataMap[mapKey] = reflectValue.Field(i).Interface() + } else { + dataMap[mapKey] = nil + } + } + } + if !in.MustMapReturn && len(dataMap) == 0 { + return in.Value + } + return dataMap + + // The given value is type of slice. + case reflect.Array, reflect.Slice: + length := reflectValue.Len() + if length == 0 { + break + } + array := make([]interface{}, reflectValue.Len()) + for i := 0; i < length; i++ { + array[i] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: reflectValue.Index(i).Interface(), + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }) + } + return array + + default: + } + return in.Value +} diff --git a/util/gconv/gconv_converter_float.go b/util/gconv/gconv_converter_float.go index 3c186ab5669..d9e5520d6c0 100644 --- a/util/gconv/gconv_converter_float.go +++ b/util/gconv/gconv_converter_float.go @@ -17,7 +17,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *Converter) Float32(any any) (float32, error) { +func (c *impConverter) Float32(any any) (float32, error) { if empty.IsNil(any) { return 0, nil } @@ -78,7 +78,7 @@ func (c *Converter) Float32(any any) (float32, error) { } } -func (c *Converter) Float64(any any) (float64, error) { +func (c *impConverter) Float64(any any) (float64, error) { if empty.IsNil(any) { return 0, nil } diff --git a/util/gconv/gconv_converter_int.go b/util/gconv/gconv_converter_int.go index cc23f314f7f..fb742471c57 100644 --- a/util/gconv/gconv_converter_int.go +++ b/util/gconv/gconv_converter_int.go @@ -18,7 +18,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *Converter) Int(any any) (int, error) { +func (c *impConverter) Int(any any) (int, error) { if v, ok := any.(int); ok { return v, nil } @@ -29,7 +29,7 @@ func (c *Converter) Int(any any) (int, error) { return int(v), nil } -func (c *Converter) Int8(any any) (int8, error) { +func (c *impConverter) Int8(any any) (int8, error) { if v, ok := any.(int8); ok { return v, nil } @@ -40,7 +40,7 @@ func (c *Converter) Int8(any any) (int8, error) { return int8(v), nil } -func (c *Converter) Int16(any any) (int16, error) { +func (c *impConverter) Int16(any any) (int16, error) { if v, ok := any.(int16); ok { return v, nil } @@ -51,7 +51,7 @@ func (c *Converter) Int16(any any) (int16, error) { return int16(v), nil } -func (c *Converter) Int32(any any) (int32, error) { +func (c *impConverter) Int32(any any) (int32, error) { if v, ok := any.(int32); ok { return v, nil } @@ -62,7 +62,7 @@ func (c *Converter) Int32(any any) (int32, error) { return int32(v), nil } -func (c *Converter) Int64(any any) (int64, error) { +func (c *impConverter) Int64(any any) (int64, error) { if empty.IsNil(any) { return 0, nil } diff --git a/util/gconv/gconv_converter_map.go b/util/gconv/gconv_converter_map.go index 13f7a3d221b..60a806e6f94 100644 --- a/util/gconv/gconv_converter_map.go +++ b/util/gconv/gconv_converter_map.go @@ -6,499 +6,492 @@ package gconv -import ( - "reflect" - "strings" - - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/utils" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" - "github.com/gogf/gf/v2/util/gtag" -) - -// MapConvert implements the map converting. -// It automatically checks and converts json string to map if `value` is string/[]byte. +//// MapStrStr converts `value` to map[string]string. +//// Note that there might be data copy for this map type converting. +//func (c *impConverter) MapStrStr(value any, option ...MapOption) (map[string]string, error) { +// if r, ok := value.(map[string]string); ok { +// return r, nil +// } +// m := Map(value, option...) +// if len(m) > 0 { +// vMap := make(map[string]string, len(m)) +// for k, v := range m { +// s, err := c.String(v) +// if err != nil { +// return nil, err +// } +// vMap[k] = s +// } +// return vMap, nil +// } +// return nil, nil +//} // -// TODO completely implement the recursive converting for all types, especially the map. -func (c *Converter) doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool, option ...MapOption) map[string]interface{} { - if value == nil { - return nil - } - // It redirects to its underlying value if it has implemented interface iVal. - if v, ok := value.(localinterface.IVal); ok { - value = v.Val() - } - var ( - usedOption = getUsedMapOption(option...) - newTags = gtag.StructTagPriority - ) - if usedOption.Deep { - recursive = recursiveTypeTrue - } - switch len(usedOption.Tags) { - case 0: - // No need handling. - case 1: - newTags = append(strings.Split(usedOption.Tags[0], ","), gtag.StructTagPriority...) - default: - newTags = append(usedOption.Tags, gtag.StructTagPriority...) - } - // Assert the common combination of types, and finally it uses reflection. - dataMap := make(map[string]interface{}) - switch r := value.(type) { - case string: - // If it is a JSON string, automatically unmarshal it! - if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { - if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil { - return nil - } - } else { - return nil - } - case []byte: - // If it is a JSON string, automatically unmarshal it! - if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { - if err := json.UnmarshalUseNumber(r, &dataMap); err != nil { - return nil - } - } else { - return nil - } - case map[interface{}]interface{}: - recursiveOption := usedOption - recursiveOption.Tags = newTags - for k, v := range r { - dataMap[String(k)] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: v, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - }, - ) - } - case map[interface{}]string: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]int: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]uint: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]float32: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]float64: - for k, v := range r { - dataMap[String(k)] = v - } - case map[string]bool: - for k, v := range r { - dataMap[k] = v - } - case map[string]int: - for k, v := range r { - dataMap[k] = v - } - case map[string]uint: - for k, v := range r { - dataMap[k] = v - } - case map[string]float32: - for k, v := range r { - dataMap[k] = v - } - case map[string]float64: - for k, v := range r { - dataMap[k] = v - } - case map[string]string: - for k, v := range r { - dataMap[k] = v - } - case map[string]interface{}: - if recursive == recursiveTypeTrue { - recursiveOption := usedOption - recursiveOption.Tags = newTags - // A copy of current map. - for k, v := range r { - dataMap[k] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: v, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - }, - ) - } - } else { - // It returns the map directly without any changing. - return r - } - case map[int]interface{}: - recursiveOption := usedOption - recursiveOption.Tags = newTags - for k, v := range r { - dataMap[String(k)] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: v, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - }, - ) - } - case map[int]string: - for k, v := range r { - dataMap[String(k)] = v - } - case map[uint]string: - for k, v := range r { - dataMap[String(k)] = v - } - - default: - // Not a common type, it then uses reflection for conversion. - var reflectValue reflect.Value - if v, ok := value.(reflect.Value); ok { - reflectValue = v - } else { - reflectValue = reflect.ValueOf(value) - } - reflectKind := reflectValue.Kind() - // If it is a pointer, we should find its real data type. - for reflectKind == reflect.Ptr { - reflectValue = reflectValue.Elem() - reflectKind = reflectValue.Kind() - } - switch reflectKind { - // If `value` is type of array, it converts the value of even number index as its key and - // the value of odd number index as its corresponding value, for example: - // []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"} - // []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil} - case reflect.Slice, reflect.Array: - length := reflectValue.Len() - for i := 0; i < length; i += 2 { - if i+1 < length { - dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface() - } else { - dataMap[String(reflectValue.Index(i).Interface())] = nil - } - } - case reflect.Map, reflect.Struct, reflect.Interface: - recursiveOption := usedOption - recursiveOption.Tags = newTags - convertedValue := c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: true, - Value: value, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - MustMapReturn: mustMapReturn, - }, - ) - if m, ok := convertedValue.(map[string]interface{}); ok { - return m - } - return nil - default: - return nil - } - } - return dataMap -} - -func getUsedMapOption(option ...MapOption) MapOption { - var usedOption MapOption - if len(option) > 0 { - usedOption = option[0] - } - return usedOption -} - -type doMapConvertForMapOrStructValueInput struct { - IsRoot bool // It returns directly if it is not root and with no recursive converting. - Value interface{} // Current operation value. - RecursiveType recursiveType // The type from top function entry. - RecursiveOption bool // Whether convert recursively for `current` operation. - Option MapOption // Map converting option. - MustMapReturn bool // Must return map instead of Value when empty. -} - -func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} { - if !in.IsRoot && !in.RecursiveOption { - return in.Value - } - - var reflectValue reflect.Value - if v, ok := in.Value.(reflect.Value); ok { - reflectValue = v - in.Value = v.Interface() - } else { - reflectValue = reflect.ValueOf(in.Value) - } - reflectKind := reflectValue.Kind() - // If it is a pointer, we should find its real data type. - for reflectKind == reflect.Ptr { - reflectValue = reflectValue.Elem() - reflectKind = reflectValue.Kind() - } - switch reflectKind { - case reflect.Map: - var ( - mapIter = reflectValue.MapRange() - dataMap = make(map[string]interface{}) - ) - for mapIter.Next() { - var ( - mapKeyValue = mapIter.Value() - mapValue interface{} - ) - switch { - case mapKeyValue.IsZero(): - if utils.CanCallIsNil(mapKeyValue) && mapKeyValue.IsNil() { - // quick check for nil value. - mapValue = nil - } else { - // in case of: - // exception recovered: reflect: call of reflect.Value.Interface on zero Value - mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface() - } - default: - mapValue = mapKeyValue.Interface() - } - dataMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: mapValue, - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } - return dataMap - - case reflect.Struct: - var dataMap = make(map[string]interface{}) - // Map converting interface check. - if v, ok := in.Value.(localinterface.IMapStrAny); ok { - // Value copy, in case of concurrent safety. - for mapK, mapV := range v.MapStrAny() { - if in.RecursiveOption { - dataMap[mapK] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: mapV, - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } else { - dataMap[mapK] = mapV - } - } - if len(dataMap) > 0 { - return dataMap - } - } - // Using reflect for converting. - var ( - rtField reflect.StructField - rvField reflect.Value - reflectType = reflectValue.Type() // attribute value type. - mapKey = "" // mapKey may be the tag name or the struct attribute name. - ) - for i := 0; i < reflectValue.NumField(); i++ { - rtField = reflectType.Field(i) - rvField = reflectValue.Field(i) - // Only convert the public attributes. - fieldName := rtField.Name - if !utils.IsLetterUpper(fieldName[0]) { - continue - } - mapKey = "" - fieldTag := rtField.Tag - for _, tag := range in.Option.Tags { - if mapKey = fieldTag.Get(tag); mapKey != "" { - break - } - } - if mapKey == "" { - mapKey = fieldName - } else { - // Support json tag feature: -, omitempty - mapKey = strings.TrimSpace(mapKey) - if mapKey == "-" { - continue - } - array := strings.Split(mapKey, ",") - if len(array) > 1 { - switch strings.TrimSpace(array[1]) { - case "omitempty": - if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) { - continue - } else { - mapKey = strings.TrimSpace(array[0]) - } - default: - mapKey = strings.TrimSpace(array[0]) - } - } - if mapKey == "" { - mapKey = fieldName - } - } - if in.RecursiveOption || rtField.Anonymous { - // Do map converting recursively. - var ( - rvAttrField = rvField - rvAttrKind = rvField.Kind() - ) - if rvAttrKind == reflect.Ptr { - rvAttrField = rvField.Elem() - rvAttrKind = rvAttrField.Kind() - } - switch rvAttrKind { - case reflect.Struct: - // Embedded struct and has no fields, just ignores it. - // Eg: gmeta.Meta - if rvAttrField.Type().NumField() == 0 { - continue - } - var ( - hasNoTag = mapKey == fieldName - // DO NOT use rvAttrField.Interface() here, - // as it might be changed from pointer to struct. - rvInterface = rvField.Interface() - ) - switch { - case hasNoTag && rtField.Anonymous: - // It means this attribute field has no tag. - // Overwrite the attribute with sub-struct attribute fields. - anonymousValue := c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvInterface, - RecursiveType: in.RecursiveType, - RecursiveOption: true, - Option: in.Option, - }) - if m, ok := anonymousValue.(map[string]interface{}); ok { - for k, v := range m { - dataMap[k] = v - } - } else { - dataMap[mapKey] = rvInterface - } - - // It means this attribute field has desired tag. - case !hasNoTag && rtField.Anonymous: - dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvInterface, - RecursiveType: in.RecursiveType, - RecursiveOption: true, - Option: in.Option, - }) - - default: - dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvInterface, - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }) - } - - // The struct attribute is type of slice. - case reflect.Array, reflect.Slice: - length := rvAttrField.Len() - if length == 0 { - dataMap[mapKey] = rvAttrField.Interface() - break - } - array := make([]interface{}, length) - for arrayIndex := 0; arrayIndex < length; arrayIndex++ { - array[arrayIndex] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvAttrField.Index(arrayIndex).Interface(), - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } - dataMap[mapKey] = array - case reflect.Map: - var ( - mapIter = rvAttrField.MapRange() - nestedMap = make(map[string]interface{}) - ) - for mapIter.Next() { - nestedMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: mapIter.Value().Interface(), - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } - dataMap[mapKey] = nestedMap - default: - if rvField.IsValid() { - dataMap[mapKey] = reflectValue.Field(i).Interface() - } else { - dataMap[mapKey] = nil - } - } - } else { - // No recursive map value converting - if rvField.IsValid() { - dataMap[mapKey] = reflectValue.Field(i).Interface() - } else { - dataMap[mapKey] = nil - } - } - } - if !in.MustMapReturn && len(dataMap) == 0 { - return in.Value - } - return dataMap - - // The given value is type of slice. - case reflect.Array, reflect.Slice: - length := reflectValue.Len() - if length == 0 { - break - } - array := make([]interface{}, reflectValue.Len()) - for i := 0; i < length; i++ { - array[i] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: reflectValue.Index(i).Interface(), - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }) - } - return array - - default: - } - return in.Value -} +//// Map implements the map converting. +//// It automatically checks and converts json string to map if `value` is string/[]byte. +//// +//// TODO completely implement the recursive converting for all types, especially the map. +//func (c *impConverter) Map(value any, option MapOption) (map[string]any, error) { +// if value == nil { +// return nil, nil +// } +// // It redirects to its underlying value if it has implemented interface iVal. +// if v, ok := value.(localinterface.IVal); ok { +// value = v.Val() +// } +// var ( +// newTags = gtag.StructTagPriority +// ) +// switch len(option.Tags) { +// case 0: +// // No need handling. +// case 1: +// newTags = append(strings.Split(option.Tags[0], ","), gtag.StructTagPriority...) +// default: +// newTags = append(option.Tags, gtag.StructTagPriority...) +// } +// // Assert the common combination of types, and finally it uses reflection. +// dataMap := make(map[string]any) +// switch r := value.(type) { +// case string: +// // If it is a JSON string, automatically unmarshal it! +// if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { +// if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil { +// return nil, err +// } +// } else { +// return nil, nil +// } +// case []byte: +// // If it is a JSON string, automatically unmarshal it! +// if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { +// if err := json.UnmarshalUseNumber(r, &dataMap); err != nil { +// return nil, err +// } +// } else { +// return nil, nil +// } +// case map[any]any: +// recursiveOption := option +// recursiveOption.Tags = newTags +// for k, v := range r { +// dataMap[String(k)] = c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: v, +// Recursive: option.Deep, +// Option: recursiveOption, +// }, +// ) +// } +// case map[any]string: +// for k, v := range r { +// dataMap[String(k)] = v +// } +// case map[any]int: +// for k, v := range r { +// dataMap[String(k)] = v +// } +// case map[any]uint: +// for k, v := range r { +// dataMap[String(k)] = v +// } +// case map[any]float32: +// for k, v := range r { +// dataMap[String(k)] = v +// } +// case map[any]float64: +// for k, v := range r { +// dataMap[String(k)] = v +// } +// case map[string]bool: +// for k, v := range r { +// dataMap[k] = v +// } +// case map[string]int: +// for k, v := range r { +// dataMap[k] = v +// } +// case map[string]uint: +// for k, v := range r { +// dataMap[k] = v +// } +// case map[string]float32: +// for k, v := range r { +// dataMap[k] = v +// } +// case map[string]float64: +// for k, v := range r { +// dataMap[k] = v +// } +// case map[string]string: +// for k, v := range r { +// dataMap[k] = v +// } +// case map[string]any: +// if option.Deep { +// recursiveOption := option +// recursiveOption.Tags = newTags +// // A copy of current map. +// for k, v := range r { +// dataMap[k] = c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: v, +// Recursive: option.Deep, +// Option: recursiveOption, +// }, +// ) +// } +// } else { +// // It returns the map directly without any changing. +// return r, nil +// } +// case map[int]any: +// recursiveOption := option +// recursiveOption.Tags = newTags +// for k, v := range r { +// dataMap[String(k)] = c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: v, +// Recursive: option.Deep, +// Option: recursiveOption, +// }, +// ) +// } +// case map[int]string: +// for k, v := range r { +// dataMap[String(k)] = v +// } +// case map[uint]string: +// for k, v := range r { +// dataMap[String(k)] = v +// } +// +// default: +// // Not a common type, it then uses reflection for conversion. +// var reflectValue reflect.Value +// if v, ok := value.(reflect.Value); ok { +// reflectValue = v +// } else { +// reflectValue = reflect.ValueOf(value) +// } +// reflectKind := reflectValue.Kind() +// // If it is a pointer, we should find its real data type. +// for reflectKind == reflect.Ptr { +// reflectValue = reflectValue.Elem() +// reflectKind = reflectValue.Kind() +// } +// switch reflectKind { +// // If `value` is type of array, it converts the value of even number index as its key and +// // the value of odd number index as its corresponding value, for example: +// // []string{"k1","v1","k2","v2"} => map[string]any{"k1":"v1", "k2":"v2"} +// // []string{"k1","v1","k2"} => map[string]any{"k1":"v1", "k2":nil} +// case reflect.Slice, reflect.Array: +// length := reflectValue.Len() +// for i := 0; i < length; i += 2 { +// if i+1 < length { +// dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface() +// } else { +// dataMap[String(reflectValue.Index(i).Interface())] = nil +// } +// } +// case reflect.Map, reflect.Struct, reflect.Interface: +// recursiveOption := option +// recursiveOption.Tags = newTags +// convertedValue := c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: true, +// Value: value, +// Recursive: option.Deep, +// Option: recursiveOption, +// MustMapReturn: option.EmptyEvenNil, +// }, +// ) +// if m, ok := convertedValue.(map[string]any); ok { +// return m, nil +// } +// return nil, nil +// default: +// return nil, nil +// } +// } +// return dataMap, nil +//} +// +//func getUsedMapOption(option ...MapOption) MapOption { +// var usedOption MapOption +// if len(option) > 0 { +// usedOption = option[0] +// } +// return usedOption +//} +// +//type doMapConvertForMapOrStructValueInput struct { +// IsRoot bool // It returns directly if it is not root and with no recursive converting. +// Value any // Current operation value. +// Recursive bool // Whether convert recursively for `current` operation. +// Option MapOption // Map converting option. +// MustMapReturn bool // Must return map instead of Value when empty. +//} +// +//func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) any { +// if !in.IsRoot && !in.Recursive { +// return in.Value +// } +// +// var reflectValue reflect.Value +// if v, ok := in.Value.(reflect.Value); ok { +// reflectValue = v +// in.Value = v.Interface() +// } else { +// reflectValue = reflect.ValueOf(in.Value) +// } +// reflectKind := reflectValue.Kind() +// // If it is a pointer, we should find its real data type. +// for reflectKind == reflect.Ptr { +// reflectValue = reflectValue.Elem() +// reflectKind = reflectValue.Kind() +// } +// switch reflectKind { +// case reflect.Map: +// var ( +// mapIter = reflectValue.MapRange() +// dataMap = make(map[string]any) +// ) +// for mapIter.Next() { +// var ( +// mapKeyValue = mapIter.Value() +// mapValue any +// ) +// switch { +// case mapKeyValue.IsZero(): +// if utils.CanCallIsNil(mapKeyValue) && mapKeyValue.IsNil() { +// // quick check for nil value. +// mapValue = nil +// } else { +// // in case of: +// // exception recovered: reflect: call of reflect.Value.Interface on zero Value +// mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface() +// } +// default: +// mapValue = mapKeyValue.Interface() +// } +// dataMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: mapValue, +// Recursive: in.Recursive, +// Option: in.Option, +// }, +// ) +// } +// return dataMap +// +// case reflect.Struct: +// var dataMap = make(map[string]any) +// // Map converting interface check. +// if v, ok := in.Value.(localinterface.IMapStrAny); ok { +// // Value copy, in case of concurrent safety. +// for mapK, mapV := range v.MapStrAny() { +// if in.Recursive { +// dataMap[mapK] = c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: mapV, +// Recursive: in.Recursive, +// Option: in.Option, +// }, +// ) +// } else { +// dataMap[mapK] = mapV +// } +// } +// if len(dataMap) > 0 { +// return dataMap +// } +// } +// // Using reflect for converting. +// var ( +// rtField reflect.StructField +// rvField reflect.Value +// reflectType = reflectValue.Type() // attribute value type. +// mapKey = "" // mapKey may be the tag name or the struct attribute name. +// ) +// for i := 0; i < reflectValue.NumField(); i++ { +// rtField = reflectType.Field(i) +// rvField = reflectValue.Field(i) +// // Only convert the public attributes. +// fieldName := rtField.Name +// if !utils.IsLetterUpper(fieldName[0]) { +// continue +// } +// mapKey = "" +// fieldTag := rtField.Tag +// for _, tag := range in.Option.Tags { +// if mapKey = fieldTag.Get(tag); mapKey != "" { +// break +// } +// } +// if mapKey == "" { +// mapKey = fieldName +// } else { +// // Support json tag feature: -, omitempty +// mapKey = strings.TrimSpace(mapKey) +// if mapKey == "-" { +// continue +// } +// array := strings.Split(mapKey, ",") +// if len(array) > 1 { +// switch strings.TrimSpace(array[1]) { +// case "omitempty": +// if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) { +// continue +// } else { +// mapKey = strings.TrimSpace(array[0]) +// } +// default: +// mapKey = strings.TrimSpace(array[0]) +// } +// } +// if mapKey == "" { +// mapKey = fieldName +// } +// } +// if in.Recursive || rtField.Anonymous { +// // Do map converting recursively. +// var ( +// rvAttrField = rvField +// rvAttrKind = rvField.Kind() +// ) +// if rvAttrKind == reflect.Ptr { +// rvAttrField = rvField.Elem() +// rvAttrKind = rvAttrField.Kind() +// } +// switch rvAttrKind { +// case reflect.Struct: +// // Embedded struct and has no fields, just ignores it. +// // Eg: gmeta.Meta +// if rvAttrField.Type().NumField() == 0 { +// continue +// } +// var ( +// hasNoTag = mapKey == fieldName +// // DO NOT use rvAttrField.Interface() here, +// // as it might be changed from pointer to struct. +// rvInterface = rvField.Interface() +// ) +// switch { +// case hasNoTag && rtField.Anonymous: +// // It means this attribute field has no tag. +// // Overwrite the attribute with sub-struct attribute fields. +// anonymousValue := c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: rvInterface, +// Recursive: true, +// Option: in.Option, +// }) +// if m, ok := anonymousValue.(map[string]any); ok { +// for k, v := range m { +// dataMap[k] = v +// } +// } else { +// dataMap[mapKey] = rvInterface +// } +// +// // It means this attribute field has desired tag. +// case !hasNoTag && rtField.Anonymous: +// dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: rvInterface, +// Recursive: true, +// Option: in.Option, +// }) +// +// default: +// dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: rvInterface, +// Recursive: in.Recursive, +// Option: in.Option, +// }) +// } +// +// // The struct attribute is type of slice. +// case reflect.Array, reflect.Slice: +// length := rvAttrField.Len() +// if length == 0 { +// dataMap[mapKey] = rvAttrField.Interface() +// break +// } +// array := make([]any, length) +// for arrayIndex := 0; arrayIndex < length; arrayIndex++ { +// array[arrayIndex] = c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: rvAttrField.Index(arrayIndex).Interface(), +// Recursive: in.Recursive, +// Option: in.Option, +// }, +// ) +// } +// dataMap[mapKey] = array +// case reflect.Map: +// var ( +// mapIter = rvAttrField.MapRange() +// nestedMap = make(map[string]any) +// ) +// for mapIter.Next() { +// nestedMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( +// doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: mapIter.Value().Interface(), +// Recursive: in.Recursive, +// Option: in.Option, +// }, +// ) +// } +// dataMap[mapKey] = nestedMap +// default: +// if rvField.IsValid() { +// dataMap[mapKey] = reflectValue.Field(i).Interface() +// } else { +// dataMap[mapKey] = nil +// } +// } +// } else { +// // No recursive map value converting +// if rvField.IsValid() { +// dataMap[mapKey] = reflectValue.Field(i).Interface() +// } else { +// dataMap[mapKey] = nil +// } +// } +// } +// if !in.MustMapReturn && len(dataMap) == 0 { +// return in.Value +// } +// return dataMap +// +// // The given value is type of slice. +// case reflect.Array, reflect.Slice: +// length := reflectValue.Len() +// if length == 0 { +// break +// } +// array := make([]any, reflectValue.Len()) +// for i := 0; i < length; i++ { +// array[i] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ +// IsRoot: false, +// Value: reflectValue.Index(i).Interface(), +// Recursive: in.Recursive, +// Option: in.Option, +// }) +// } +// return array +// +// default: +// } +// return in.Value +//} diff --git a/util/gconv/gconv_converter_maps.go b/util/gconv/gconv_converter_maps.go deleted file mode 100644 index a5c4126a56b..00000000000 --- a/util/gconv/gconv_converter_maps.go +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package gconv diff --git a/util/gconv/gconv_converter_maptomap.go b/util/gconv/gconv_converter_maptomap.go index 46a6bf8795f..5026ce2239c 100644 --- a/util/gconv/gconv_converter_maptomap.go +++ b/util/gconv/gconv_converter_maptomap.go @@ -23,7 +23,7 @@ import ( // // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes // sense only if the items of original map `params` is type struct. -func (c *Converter) MapToMap(params any, pointer any, mapping ...map[string]string) (err error) { +func (c *impConverter) MapToMap(params any, pointer any, mapping ...map[string]string) (err error) { var ( paramsRv reflect.Value paramsKind reflect.Kind @@ -98,27 +98,27 @@ func (c *Converter) MapToMap(params any, pointer any, mapping ...map[string]stri return err } default: - mapValue.Set( - reflect.ValueOf( - c.doConvert(doConvertInput{ - FromValue: paramsRv.MapIndex(key).Interface(), - ToTypeName: pointerValueType.String(), - ReferValue: mapValue, - Extra: nil, - }), - ), - ) + convertResult, err := c.doConvert(doConvertInput{ + FromValue: paramsRv.MapIndex(key).Interface(), + ToTypeName: pointerValueType.String(), + ReferValue: mapValue, + Extra: nil, + }) + if err != nil { + return err + } + mapValue.Set(reflect.ValueOf(convertResult)) } - var mapKey = reflect.ValueOf( - c.doConvert( - doConvertInput{ - FromValue: key.Interface(), - ToTypeName: pointerKeyType.Name(), - ReferValue: reflect.New(pointerKeyType).Elem().Interface(), - Extra: nil, - }, - ), - ) + convertResult, err := c.doConvert(doConvertInput{ + FromValue: key.Interface(), + ToTypeName: pointerKeyType.Name(), + ReferValue: reflect.New(pointerKeyType).Elem().Interface(), + Extra: nil, + }) + if err != nil { + return err + } + var mapKey = reflect.ValueOf(convertResult) dataMap.SetMapIndex(mapKey, mapValue) } pointerRv.Set(dataMap) diff --git a/util/gconv/gconv_converter_maptomaps.go b/util/gconv/gconv_converter_maptomaps.go index 2c33ebfdc0d..9783a4e6fae 100644 --- a/util/gconv/gconv_converter_maptomaps.go +++ b/util/gconv/gconv_converter_maptomaps.go @@ -21,7 +21,7 @@ import ( // // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes // sense only if the item of `params` is type struct. -func (c *Converter) MapToMaps(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) { +func (c *impConverter) MapToMaps(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) { // Params and its element type check. var ( paramsRv reflect.Value diff --git a/util/gconv/gconv_converter_rune.go b/util/gconv/gconv_converter_rune.go index b5bff899edb..0a6c5fdcaad 100644 --- a/util/gconv/gconv_converter_rune.go +++ b/util/gconv/gconv_converter_rune.go @@ -6,7 +6,7 @@ package gconv -func (c *Converter) Rune(any any) (rune, error) { +func (c *impConverter) Rune(any any) (rune, error) { if v, ok := any.(rune); ok { return v, nil } @@ -17,7 +17,7 @@ func (c *Converter) Rune(any any) (rune, error) { return v, nil } -func (c *Converter) Runes(any any) ([]rune, error) { +func (c *impConverter) Runes(any any) ([]rune, error) { if v, ok := any.([]rune); ok { return v, nil } diff --git a/util/gconv/gconv_converter_scan.go b/util/gconv/gconv_converter_scan.go index 269b3de94c5..ccd012e7800 100644 --- a/util/gconv/gconv_converter_scan.go +++ b/util/gconv/gconv_converter_scan.go @@ -15,7 +15,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *Converter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) { +func (c *impConverter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) { // Check if srcValue is nil, in which case no conversion is needed if srcValue == nil { return nil @@ -182,7 +182,7 @@ func (c *Converter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[ // - dstPointer: The destination pointer to convert to // - dstPointerReflectType: The reflection type of the destination pointer // - paramKeyToAttrMap: Optional mapping between parameter keys and struct attribute names -func (c *Converter) doScanForComplicatedTypes( +func (c *impConverter) doScanForComplicatedTypes( srcValue, dstPointer any, dstPointerReflectType reflect.Type, paramKeyToAttrMap ...map[string]string, diff --git a/util/gconv/gconv_converter_slice_any.go b/util/gconv/gconv_converter_slice_any.go new file mode 100644 index 00000000000..d9d0c2a6246 --- /dev/null +++ b/util/gconv/gconv_converter_slice_any.go @@ -0,0 +1,142 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/reflection" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +type SliceOption struct { + // FailBreak specifies whether to break converting the next element + // if one element conversion fails in slice. + FailBreak bool +} + +// SliceAny converts `any` to []any. +func (c *impConverter) SliceAny(any interface{}, option SliceOption) ([]any, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + array []interface{} + ) + switch value := any.(type) { + case []interface{}: + array = value + case []string: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []int: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []int8: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []int16: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []int32: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []int64: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []uint: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + + case []uint16: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []uint32: + for _, v := range value { + array = append(array, v) + } + case []uint64: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []bool: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []float32: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + case []float64: + array = make([]interface{}, len(value)) + for k, v := range value { + array[k] = v + } + } + if array != nil { + return array, err + } + if v, ok := any.(localinterface.IInterfaces); ok { + return v.Interfaces(), err + } + + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]interface{}, length) + ) + for i := 0; i < length; i++ { + slice[i] = originValueAndKind.OriginValue.Index(i).Interface() + } + return slice, err + + default: + return []interface{}{any}, err + } +} diff --git a/util/gconv/gconv_converter_slice_float.go b/util/gconv/gconv_converter_slice_float.go new file mode 100644 index 00000000000..201e927f76e --- /dev/null +++ b/util/gconv/gconv_converter_slice_float.go @@ -0,0 +1,417 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/reflection" + "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +// SliceFloat32 converts `any` to []float32. +func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]float32, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + f float32 + array []float32 = nil + ) + switch value := any.(type) { + case []string: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int8: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int16: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int32: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int64: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []float32{}, err + } + if utils.IsNumeric(value) { + f, err = c.Float32(value) + if err != nil && option.FailBreak { + return nil, err + } + return []float32{f}, err + } + case []uint16: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint32: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint64: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []bool: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []float32: + array = value + case []float64: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []interface{}: + array = make([]float32, len(value)) + for k, v := range value { + f, err = c.Float32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + } + if array != nil { + return array, err + } + if v, ok := any.(localinterface.IFloats); ok { + return c.SliceFloat32(v.Floats(), option) + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceFloat32(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]float32, length) + ) + for i := 0; i < length; i++ { + f, err = c.Float32(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = f + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []float32{}, err + } + f, err = c.Float32(any) + if err != nil && option.FailBreak { + return nil, err + } + return []float32{f}, err + } +} + +// SliceFloat64 converts `any` to []float64. +func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]float64, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + f float64 + array []float64 = nil + ) + switch value := any.(type) { + case []string: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int8: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int16: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int32: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []int64: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []float64{}, err + } + if utils.IsNumeric(value) { + f, err = c.Float64(value) + if err != nil && option.FailBreak { + return nil, err + } + return []float64{f}, err + } + case []uint16: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint32: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []uint64: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []bool: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []float32: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + case []float64: + array = value + case []interface{}: + array = make([]float64, len(value)) + for k, v := range value { + f, err = c.Float64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = f + } + } + if array != nil { + return array, err + } + if v, ok := any.(localinterface.IFloats); ok { + return v.Floats(), err + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceFloat64(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]float64, length) + ) + for i := 0; i < length; i++ { + f, err = c.Float64(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = f + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []float64{}, err + } + f, err = c.Float64(any) + if err != nil && option.FailBreak { + return nil, err + } + return []float64{f}, err + } +} diff --git a/util/gconv/gconv_converter_slice_int.go b/util/gconv/gconv_converter_slice_int.go new file mode 100644 index 00000000000..4dcc6cc8d7d --- /dev/null +++ b/util/gconv/gconv_converter_slice_int.go @@ -0,0 +1,536 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/reflection" + "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +// SliceInt converts `any` to []int. +func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + ii int + array []int = nil + ) + switch value := any.(type) { + case []string: + array = make([]int, len(value)) + for k, v := range value { + ii, err = c.Int(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []int: + array = value + case []int8: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []int16: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []int32: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []int64: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []uint: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []int{}, err + } + if utils.IsNumeric(value) { + ii, err = c.Int(value) + if err != nil && option.FailBreak { + return nil, err + } + return []int{ii}, err + } + case []uint16: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []uint32: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []uint64: + array = make([]int, len(value)) + for k, v := range value { + array[k] = int(v) + } + case []bool: + array = make([]int, len(value)) + for k, v := range value { + if v { + array[k] = 1 + } else { + array[k] = 0 + } + } + case []float32: + array = make([]int, len(value)) + for k, v := range value { + ii, err = c.Int(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []float64: + array = make([]int, len(value)) + for k, v := range value { + ii, err = c.Int(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []interface{}: + array = make([]int, len(value)) + for k, v := range value { + ii, err = c.Int(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case [][]byte: + array = make([]int, len(value)) + for k, v := range value { + ii, err = c.Int(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + } + if array != nil { + return array, err + } + if v, ok := any.(localinterface.IInts); ok { + return v.Ints(), err + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceInt(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]int, length) + ) + for i := 0; i < length; i++ { + ii, err = c.Int(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = ii + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []int{}, err + } + ii, err = c.Int(any) + if err != nil && option.FailBreak { + return nil, err + } + return []int{ii}, err + } +} + +// SliceInt32 converts `any` to []int32. +func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + ii int32 + array []int32 = nil + ) + switch value := any.(type) { + case []string: + array = make([]int32, len(value)) + for k, v := range value { + ii, err = c.Int32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []int: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []int8: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []int16: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []int32: + array = value + case []int64: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []uint: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []int32{}, err + } + if utils.IsNumeric(value) { + ii, err = c.Int32(value) + if err != nil && option.FailBreak { + return nil, err + } + return []int32{ii}, err + } + case []uint16: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []uint32: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []uint64: + array = make([]int32, len(value)) + for k, v := range value { + array[k] = int32(v) + } + case []bool: + array = make([]int32, len(value)) + for k, v := range value { + if v { + array[k] = 1 + } else { + array[k] = 0 + } + } + case []float32: + array = make([]int32, len(value)) + for k, v := range value { + ii, err = c.Int32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []float64: + array = make([]int32, len(value)) + for k, v := range value { + ii, err = c.Int32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []interface{}: + array = make([]int32, len(value)) + for k, v := range value { + ii, err = c.Int32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case [][]byte: + array = make([]int32, len(value)) + for k, v := range value { + ii, err = c.Int32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + } + if array != nil { + return array, err + } + if v, ok := any.(localinterface.IInts); ok { + return c.SliceInt32(v.Ints(), option) + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceInt32(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]int32, length) + ) + for i := 0; i < length; i++ { + ii, err = c.Int32(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = ii + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []int32{}, err + } + ii, err = c.Int32(any) + if err != nil && option.FailBreak { + return nil, err + } + return []int32{ii}, err + } +} + +// SliceInt64 converts `any` to []int64. +func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + ii int64 + array []int64 = nil + ) + switch value := any.(type) { + case []string: + array = make([]int64, len(value)) + for k, v := range value { + ii, err = c.Int64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []int: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []int8: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []int16: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []int32: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []int64: + array = value + case []uint: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []int64{}, err + } + if utils.IsNumeric(value) { + ii, err = c.Int64(value) + if err != nil && option.FailBreak { + return nil, err + } + return []int64{ii}, err + } + case []uint16: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []uint32: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []uint64: + array = make([]int64, len(value)) + for k, v := range value { + array[k] = int64(v) + } + case []bool: + array = make([]int64, len(value)) + for k, v := range value { + if v { + array[k] = 1 + } else { + array[k] = 0 + } + } + case []float32: + array = make([]int64, len(value)) + for k, v := range value { + ii, err = c.Int64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []float64: + array = make([]int64, len(value)) + for k, v := range value { + ii, err = c.Int64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case []interface{}: + array = make([]int64, len(value)) + for k, v := range value { + ii, err = c.Int64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + case [][]byte: + array = make([]int64, len(value)) + for k, v := range value { + ii, err = c.Int64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ii + } + } + if array != nil { + return array, err + } + if v, ok := any.(localinterface.IInts); ok { + return c.SliceInt64(v.Ints(), option) + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceInt64(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]int64, length) + ) + for i := 0; i < length; i++ { + ii, err = c.Int64(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = ii + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []int64{}, err + } + ii, err = c.Int64(any) + if err != nil && option.FailBreak { + return nil, err + } + return []int64{ii}, err + } +} diff --git a/util/gconv/gconv_converter_slice_map.go b/util/gconv/gconv_converter_slice_map.go new file mode 100644 index 00000000000..813833196f7 --- /dev/null +++ b/util/gconv/gconv_converter_slice_map.go @@ -0,0 +1,59 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import "github.com/gogf/gf/v2/internal/json" + +// SliceMap converts `value` to []map[string]any. +// Note that it automatically checks and converts json string to []map if `value` is string/[]byte. +func (c *impConverter) SliceMap(value any, sliceOption SliceOption, mapOption MapOption) ([]map[string]any, error) { + if value == nil { + return nil, nil + } + switch r := value.(type) { + case string: + list := make([]map[string]any, 0) + if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' { + if err := json.UnmarshalUseNumber([]byte(r), &list); err != nil { + return nil, err + } + return list, nil + } + return nil, nil + + case []byte: + list := make([]map[string]any, 0) + if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' { + if err := json.UnmarshalUseNumber(r, &list); err != nil { + return nil, err + } + return list, nil + } + return nil, nil + + case []map[string]any: + return r, nil + + default: + array, err := c.SliceAny(value, sliceOption) + if err != nil { + return nil, err + } + if len(array) == 0 { + return nil, nil + } + list := make([]map[string]any, len(array)) + for k, v := range array { + m := Map(v, mapOption) + //if err != nil { + // return nil, err + //} + list[k] = m + } + return list, nil + } +} diff --git a/util/gconv/gconv_converter_slice_str.go b/util/gconv/gconv_converter_slice_str.go new file mode 100644 index 00000000000..5f454b0eb18 --- /dev/null +++ b/util/gconv/gconv_converter_slice_str.go @@ -0,0 +1,216 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/reflection" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +// SliceStr converts `any` to []string. +func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + s string + array []string = nil + ) + switch value := any.(type) { + case []int: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []int8: + array = make([]string, len(value)) + for k, v := range value { + array[k] = String(v) + } + case []int16: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []int32: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []int64: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []uint: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + return array, err + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []string{}, err + } + return []string{value}, err + case []uint16: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []uint32: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []uint64: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []bool: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []float32: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []float64: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []interface{}: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + case []string: + array = value + case [][]byte: + array = make([]string, len(value)) + for k, v := range value { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = s + } + } + if array != nil { + return array, err + } + if v, ok := any.(localinterface.IStrings); ok { + return v.Strings(), err + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceStr(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]string, length) + ) + for i := 0; i < length; i++ { + s, err = c.String(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = s + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []string{}, err + } + s, err = c.String(any) + if err != nil && option.FailBreak { + return nil, err + } + return []string{s}, err + } +} diff --git a/util/gconv/gconv_converter_slice_uint.go b/util/gconv/gconv_converter_slice_uint.go new file mode 100644 index 00000000000..925c163a615 --- /dev/null +++ b/util/gconv/gconv_converter_slice_uint.go @@ -0,0 +1,527 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gconv + +import ( + "reflect" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/reflection" + "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" +) + +// SliceUint converts `any` to []uint. +func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + ui uint + array []uint = nil + ) + switch value := any.(type) { + case []string: + array = make([]uint, len(value)) + for k, v := range value { + ui, err = c.Uint(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []int8: + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case []int16: + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case []int32: + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case []int64: + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case []uint: + array = value + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []uint{}, err + } + if utils.IsNumeric(value) { + ui, err = c.Uint(value) + if err != nil && option.FailBreak { + return nil, err + } + return []uint{ui}, err + } + case []uint16: + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case []uint32: + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case []uint64: + array = make([]uint, len(value)) + for k, v := range value { + array[k] = uint(v) + } + case []bool: + array = make([]uint, len(value)) + for k, v := range value { + if v { + array[k] = 1 + } else { + array[k] = 0 + } + } + case []float32: + array = make([]uint, len(value)) + for k, v := range value { + ui, err = c.Uint(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []float64: + array = make([]uint, len(value)) + for k, v := range value { + ui, err = c.Uint(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []interface{}: + array = make([]uint, len(value)) + for k, v := range value { + ui, err = c.Uint(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case [][]byte: + array = make([]uint, len(value)) + for k, v := range value { + ui, err = c.Uint(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + } + + if array != nil { + return array, err + } + + // Default handler. + if v, ok := any.(localinterface.IUints); ok { + return v.Uints(), err + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceUint(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]uint, length) + ) + for i := 0; i < length; i++ { + ui, err = c.Uint(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = ui + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []uint{}, err + } + ui, err = c.Uint(any) + if err != nil && option.FailBreak { + return nil, err + } + return []uint{ui}, err + } +} + +// SliceUint32 converts `any` to []uint32. +func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint32, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + ui uint32 + array []uint32 = nil + ) + switch value := any.(type) { + case []string: + array = make([]uint32, len(value)) + for k, v := range value { + ui, err = c.Uint32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []int8: + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case []int16: + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case []int32: + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case []int64: + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case []uint: + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []uint32{}, err + } + if utils.IsNumeric(value) { + ui, err = c.Uint32(value) + if err != nil && option.FailBreak { + return nil, err + } + return []uint32{ui}, err + } + case []uint16: + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case []uint32: + array = value + case []uint64: + array = make([]uint32, len(value)) + for k, v := range value { + array[k] = uint32(v) + } + case []bool: + array = make([]uint32, len(value)) + for k, v := range value { + if v { + array[k] = 1 + } else { + array[k] = 0 + } + } + case []float32: + array = make([]uint32, len(value)) + for k, v := range value { + ui, err = c.Uint32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []float64: + array = make([]uint32, len(value)) + for k, v := range value { + ui, err = c.Uint32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []interface{}: + array = make([]uint32, len(value)) + for k, v := range value { + ui, err = c.Uint32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case [][]byte: + array = make([]uint32, len(value)) + for k, v := range value { + ui, err = c.Uint32(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + } + if array != nil { + return array, err + } + + // Default handler. + if v, ok := any.(localinterface.IUints); ok { + return c.SliceUint32(v.Uints(), option) + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceUint32(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]uint32, length) + ) + for i := 0; i < length; i++ { + ui, err = c.Uint32(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = ui + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []uint32{}, err + } + ui, err = c.Uint32(any) + if err != nil && option.FailBreak { + return nil, err + } + return []uint32{ui}, err + } +} + +// SliceUint64 converts `any` to []uint64. +func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint64, error) { + if empty.IsNil(any) { + return nil, nil + } + var ( + err error + ui uint64 + array []uint64 = nil + ) + switch value := any.(type) { + case []string: + array = make([]uint64, len(value)) + for k, v := range value { + ui, err = c.Uint64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []int8: + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case []int16: + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case []int32: + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case []int64: + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case []uint: + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case []uint8: + if json.Valid(value) { + if err = json.UnmarshalUseNumber(value, &array); array != nil { + return array, err + } + } + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case string: + byteValue := []byte(value) + if json.Valid(byteValue) { + if err = json.UnmarshalUseNumber(byteValue, &array); array != nil { + return array, err + } + } + if value == "" { + return []uint64{}, err + } + if utils.IsNumeric(value) { + ui, err = c.Uint64(value) + if err != nil && option.FailBreak { + return nil, err + } + return []uint64{ui}, err + } + case []uint16: + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case []uint32: + array = make([]uint64, len(value)) + for k, v := range value { + array[k] = uint64(v) + } + case []uint64: + array = value + case []bool: + array = make([]uint64, len(value)) + for k, v := range value { + if v { + array[k] = 1 + } else { + array[k] = 0 + } + } + case []float32: + array = make([]uint64, len(value)) + for k, v := range value { + ui, err = c.Uint64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []float64: + array = make([]uint64, len(value)) + for k, v := range value { + ui, err = c.Uint64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case []interface{}: + array = make([]uint64, len(value)) + for k, v := range value { + ui, err = c.Uint64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + case [][]byte: + array = make([]uint64, len(value)) + for k, v := range value { + ui, err = c.Uint64(v) + if err != nil && option.FailBreak { + return nil, err + } + array[k] = ui + } + } + if array != nil { + return array, err + } + // Default handler. + if v, ok := any.(localinterface.IUints); ok { + return c.SliceUint64(v.Uints(), option) + } + if v, ok := any.(localinterface.IInterfaces); ok { + return c.SliceUint64(v.Interfaces(), option) + } + // Not a common type, it then uses reflection for conversion. + originValueAndKind := reflection.OriginValueAndKind(any) + switch originValueAndKind.OriginKind { + case reflect.Slice, reflect.Array: + var ( + length = originValueAndKind.OriginValue.Len() + slice = make([]uint64, length) + ) + for i := 0; i < length; i++ { + ui, err = c.Uint64(originValueAndKind.OriginValue.Index(i).Interface()) + if err != nil && option.FailBreak { + return nil, err + } + slice[i] = ui + } + return slice, err + + default: + if originValueAndKind.OriginValue.IsZero() { + return []uint64{}, err + } + ui, err = c.Uint64(any) + if err != nil && option.FailBreak { + return nil, err + } + return []uint64{ui}, err + } +} diff --git a/util/gconv/gconv_converter_string.go b/util/gconv/gconv_converter_string.go index 07e60247bc0..dd38ac11904 100644 --- a/util/gconv/gconv_converter_string.go +++ b/util/gconv/gconv_converter_string.go @@ -20,7 +20,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *Converter) String(any any) (string, error) { +func (c *impConverter) String(any any) (string, error) { if empty.IsNil(any) { return "", nil } diff --git a/util/gconv/gconv_converter_struct.go b/util/gconv/gconv_converter_struct.go index 74f21c0bf16..ab254be3121 100644 --- a/util/gconv/gconv_converter_struct.go +++ b/util/gconv/gconv_converter_struct.go @@ -20,7 +20,7 @@ import ( ) // Struct is the core internal converting function for any data to struct. -func (c *Converter) Struct( +func (c *impConverter) Struct( params any, pointer any, paramKeyToAttrMap map[string]string, @@ -147,7 +147,7 @@ func (c *Converter) Struct( return nil } // Get struct info from cache or parse struct and cache the struct info. - cachedStructInfo := c.internalConvertConfig.GetCachedStructInfo( + cachedStructInfo := c.internalConverter.GetCachedStructInfo( pointerElemReflectValue.Type(), priorityTag, ) // Nothing to be converted. @@ -204,7 +204,7 @@ func (c *Converter) Struct( ) } -func (c *Converter) setOtherSameNameField( +func (c *impConverter) setOtherSameNameField( cachedFieldInfo *structcache.CachedFieldInfo, srcValue any, structValue reflect.Value, @@ -220,7 +220,7 @@ func (c *Converter) setOtherSameNameField( return nil } -func (c *Converter) bindStructWithLoopFieldInfos( +func (c *impConverter) bindStructWithLoopFieldInfos( paramsMap map[string]any, structValue reflect.Value, paramKeyToAttrMap map[string]string, @@ -316,7 +316,7 @@ func fuzzyMatchingFieldName( // bindVarToStructField sets value to struct object attribute by name. // each value to attribute converting comes into in this function. -func (c *Converter) bindVarToStructField( +func (c *impConverter) bindVarToStructField( cachedFieldInfo *structcache.CachedFieldInfo, fieldValue reflect.Value, srcValue any, @@ -439,7 +439,7 @@ func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value a } // bindVarToReflectValue sets `value` to reflect value object `structFieldValue`. -func (c *Converter) bindVarToReflectValue( +func (c *impConverter) bindVarToReflectValue( structFieldValue reflect.Value, value any, paramKeyToAttrMap map[string]string, ) (err error) { // JSON content converting. diff --git a/util/gconv/gconv_converter_structs.go b/util/gconv/gconv_converter_structs.go index 347cd5cbd11..dc722385dce 100644 --- a/util/gconv/gconv_converter_structs.go +++ b/util/gconv/gconv_converter_structs.go @@ -20,7 +20,7 @@ import ( // The parameter `pointer` should be type of pointer to slice of struct. // Note that if `pointer` is a pointer to another pointer of type of slice of struct, // it will create the struct/pointer internally. -func (c *Converter) Structs( +func (c *impConverter) Structs( params any, pointer any, paramKeyToAttrMap map[string]string, priorityTag string, ) (err error) { defer func() { diff --git a/util/gconv/gconv_converter_time.go b/util/gconv/gconv_converter_time.go index f1b1857582e..974daf45158 100644 --- a/util/gconv/gconv_converter_time.go +++ b/util/gconv/gconv_converter_time.go @@ -16,7 +16,7 @@ import ( ) // Time converts `any` to time.Time. -func (c *Converter) Time(any interface{}, format ...string) (time.Time, error) { +func (c *impConverter) Time(any interface{}, format ...string) (time.Time, error) { // It's already this type. if len(format) == 0 { if v, ok := any.(time.Time); ok { @@ -36,7 +36,7 @@ func (c *Converter) Time(any interface{}, format ...string) (time.Time, error) { // Duration converts `any` to time.Duration. // If `any` is string, then it uses time.ParseDuration to convert it. // If `any` is numeric, then it converts `any` as nanoseconds. -func (c *Converter) Duration(any interface{}) (time.Duration, error) { +func (c *impConverter) Duration(any interface{}) (time.Duration, error) { // It's already this type. if v, ok := any.(time.Duration); ok { return v, nil @@ -60,7 +60,7 @@ func (c *Converter) Duration(any interface{}) (time.Duration, error) { // It returns the converted value that matched the first format of the formats slice. // If no `format` given, it converts `any` using gtime.NewFromTimeStamp if `any` is numeric, // or using gtime.StrToTime if `any` is string. -func (c *Converter) GTime(any interface{}, format ...string) (*gtime.Time, error) { +func (c *impConverter) GTime(any interface{}, format ...string) (*gtime.Time, error) { if empty.IsNil(any) { return nil, nil } diff --git a/util/gconv/gconv_converter_uint.go b/util/gconv/gconv_converter_uint.go index a17ef2a7ad7..90691feedb9 100644 --- a/util/gconv/gconv_converter_uint.go +++ b/util/gconv/gconv_converter_uint.go @@ -18,7 +18,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *Converter) Uint(any any) (uint, error) { +func (c *impConverter) Uint(any any) (uint, error) { if empty.IsNil(any) { return 0, nil } @@ -29,7 +29,7 @@ func (c *Converter) Uint(any any) (uint, error) { return uint(v), err } -func (c *Converter) Uint8(any any) (uint8, error) { +func (c *impConverter) Uint8(any any) (uint8, error) { if empty.IsNil(any) { return 0, nil } @@ -40,7 +40,7 @@ func (c *Converter) Uint8(any any) (uint8, error) { return uint8(v), err } -func (c *Converter) Uint16(any any) (uint16, error) { +func (c *impConverter) Uint16(any any) (uint16, error) { if empty.IsNil(any) { return 0, nil } @@ -51,7 +51,7 @@ func (c *Converter) Uint16(any any) (uint16, error) { return uint16(v), err } -func (c *Converter) Uint32(any any) (uint32, error) { +func (c *impConverter) Uint32(any any) (uint32, error) { if empty.IsNil(any) { return 0, nil } @@ -62,7 +62,7 @@ func (c *Converter) Uint32(any any) (uint32, error) { return uint32(v), err } -func (c *Converter) Uint64(any any) (uint64, error) { +func (c *impConverter) Uint64(any any) (uint64, error) { if empty.IsNil(any) { return 0, nil } diff --git a/util/gconv/gconv_slice_any.go b/util/gconv/gconv_slice_any.go index 12de2ae3015..94436f2f28d 100644 --- a/util/gconv/gconv_slice_any.go +++ b/util/gconv/gconv_slice_any.go @@ -6,17 +6,6 @@ package gconv -import ( - "bytes" - "reflect" - "strings" - - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/reflection" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" -) - // SliceAny is alias of Interfaces. func SliceAny(any interface{}) []interface{} { return Interfaces(any) @@ -24,123 +13,6 @@ func SliceAny(any interface{}) []interface{} { // Interfaces converts `any` to []interface{}. func Interfaces(any interface{}) []interface{} { - if empty.IsNil(any) { - return nil - } - var array []interface{} - switch value := any.(type) { - case []interface{}: - array = value - case []string: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []int: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []int8: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []int16: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []int32: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []int64: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []uint: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - - case []uint16: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []uint32: - for _, v := range value { - array = append(array, v) - } - case []uint64: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []bool: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []float32: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - case []float64: - array = make([]interface{}, len(value)) - for k, v := range value { - array[k] = v - } - } - if array != nil { - return array - } - if v, ok := any.(localinterface.IInterfaces); ok { - return v.Interfaces() - } - - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]interface{}, length) - ) - for i := 0; i < length; i++ { - slice[i] = originValueAndKind.OriginValue.Index(i).Interface() - } - return slice - - default: - return []interface{}{any} - } + result, _ := defaultConverter.SliceAny(any, SliceOption{}) + return result } diff --git a/util/gconv/gconv_slice_float.go b/util/gconv/gconv_slice_float.go index 9d23d700249..7803f2f46f6 100644 --- a/util/gconv/gconv_slice_float.go +++ b/util/gconv/gconv_slice_float.go @@ -6,18 +6,6 @@ package gconv -import ( - "bytes" - "reflect" - "strings" - - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/reflection" - "github.com/gogf/gf/v2/internal/utils" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" -) - // SliceFloat is alias of Floats. func SliceFloat(any interface{}) []float64 { return Floats(any) @@ -40,270 +28,12 @@ func Floats(any interface{}) []float64 { // Float32s converts `any` to []float32. func Float32s(any interface{}) []float32 { - if empty.IsNil(any) { - return nil - } - var ( - array []float32 = nil - ) - switch value := any.(type) { - case []string: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []int: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []int8: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []int16: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []int32: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []int64: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []uint: - for _, v := range value { - array = append(array, Float32(v)) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []float32{} - } - if utils.IsNumeric(value) { - return []float32{Float32(value)} - } - case []uint16: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []uint32: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []uint64: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []bool: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []float32: - array = value - case []float64: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - case []interface{}: - array = make([]float32, len(value)) - for k, v := range value { - array[k] = Float32(v) - } - } - if array != nil { - return array - } - if v, ok := any.(localinterface.IFloats); ok { - return Float32s(v.Floats()) - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Float32s(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]float32, length) - ) - for i := 0; i < length; i++ { - slice[i] = Float32(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []float32{} - } - return []float32{Float32(any)} - } + result, _ := defaultConverter.SliceFloat32(any, SliceOption{}) + return result } // Float64s converts `any` to []float64. func Float64s(any interface{}) []float64 { - if empty.IsNil(any) { - return nil - } - var ( - array []float64 = nil - ) - switch value := any.(type) { - case []string: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []int: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []int8: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []int16: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []int32: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []int64: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []uint: - for _, v := range value { - array = append(array, Float64(v)) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []float64{} - } - if utils.IsNumeric(value) { - return []float64{Float64(value)} - } - case []uint16: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []uint32: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []uint64: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []bool: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []float32: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - case []float64: - array = value - case []interface{}: - array = make([]float64, len(value)) - for k, v := range value { - array[k] = Float64(v) - } - } - if array != nil { - return array - } - if v, ok := any.(localinterface.IFloats); ok { - return v.Floats() - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Floats(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]float64, length) - ) - for i := 0; i < length; i++ { - slice[i] = Float64(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []float64{} - } - return []float64{Float64(any)} - } + result, _ := defaultConverter.SliceFloat64(any, SliceOption{}) + return result } diff --git a/util/gconv/gconv_slice_int.go b/util/gconv/gconv_slice_int.go index 4b2931e08bf..adc48bf0394 100644 --- a/util/gconv/gconv_slice_int.go +++ b/util/gconv/gconv_slice_int.go @@ -6,464 +6,35 @@ package gconv -import ( - "bytes" - "reflect" - "strings" - - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/reflection" - "github.com/gogf/gf/v2/internal/utils" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" -) - // SliceInt is alias of Ints. -func SliceInt(any interface{}) []int { +func SliceInt(any any) []int { return Ints(any) } // SliceInt32 is alias of Int32s. -func SliceInt32(any interface{}) []int32 { +func SliceInt32(any any) []int32 { return Int32s(any) } // SliceInt64 is alias of Int64s. -func SliceInt64(any interface{}) []int64 { +func SliceInt64(any any) []int64 { return Int64s(any) } // Ints converts `any` to []int. -func Ints(any interface{}) []int { - if empty.IsNil(any) { - return nil - } - var ( - array []int = nil - ) - switch value := any.(type) { - case []string: - array = make([]int, len(value)) - for k, v := range value { - array[k] = Int(v) - } - case []int: - array = value - case []int8: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []int16: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []int32: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []int64: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []uint: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []int{} - } - if utils.IsNumeric(value) { - return []int{Int(value)} - } - case []uint16: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []uint32: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []uint64: - array = make([]int, len(value)) - for k, v := range value { - array[k] = int(v) - } - case []bool: - array = make([]int, len(value)) - for k, v := range value { - if v { - array[k] = 1 - } else { - array[k] = 0 - } - } - case []float32: - array = make([]int, len(value)) - for k, v := range value { - array[k] = Int(v) - } - case []float64: - array = make([]int, len(value)) - for k, v := range value { - array[k] = Int(v) - } - case []interface{}: - array = make([]int, len(value)) - for k, v := range value { - array[k] = Int(v) - } - case [][]byte: - array = make([]int, len(value)) - for k, v := range value { - array[k] = Int(v) - } - } - if array != nil { - return array - } - if v, ok := any.(localinterface.IInts); ok { - return v.Ints() - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Ints(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]int, length) - ) - for i := 0; i < length; i++ { - slice[i] = Int(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []int{} - } - return []int{Int(any)} - } +func Ints(any any) []int { + result, _ := defaultConverter.SliceInt(any, SliceOption{}) + return result } // Int32s converts `any` to []int32. -func Int32s(any interface{}) []int32 { - if empty.IsNil(any) { - return nil - } - var ( - array []int32 = nil - ) - switch value := any.(type) { - case []string: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = Int32(v) - } - case []int: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []int8: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []int16: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []int32: - array = value - case []int64: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []uint: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []int32{} - } - if utils.IsNumeric(value) { - return []int32{Int32(value)} - } - case []uint16: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []uint32: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []uint64: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = int32(v) - } - case []bool: - array = make([]int32, len(value)) - for k, v := range value { - if v { - array[k] = 1 - } else { - array[k] = 0 - } - } - case []float32: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = Int32(v) - } - case []float64: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = Int32(v) - } - case []interface{}: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = Int32(v) - } - case [][]byte: - array = make([]int32, len(value)) - for k, v := range value { - array[k] = Int32(v) - } - } - if array != nil { - return array - } - if v, ok := any.(localinterface.IInts); ok { - return Int32s(v.Ints()) - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Int32s(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]int32, length) - ) - for i := 0; i < length; i++ { - slice[i] = Int32(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []int32{} - } - return []int32{Int32(any)} - } +func Int32s(any any) []int32 { + result, _ := defaultConverter.SliceInt32(any, SliceOption{}) + return result } // Int64s converts `any` to []int64. -func Int64s(any interface{}) []int64 { - if empty.IsNil(any) { - return nil - } - var ( - array []int64 = nil - ) - switch value := any.(type) { - case []string: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = Int64(v) - } - case []int: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []int8: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []int16: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []int32: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []int64: - array = value - case []uint: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []int64{} - } - if utils.IsNumeric(value) { - return []int64{Int64(value)} - } - case []uint16: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []uint32: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []uint64: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = int64(v) - } - case []bool: - array = make([]int64, len(value)) - for k, v := range value { - if v { - array[k] = 1 - } else { - array[k] = 0 - } - } - case []float32: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = Int64(v) - } - case []float64: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = Int64(v) - } - case []interface{}: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = Int64(v) - } - case [][]byte: - array = make([]int64, len(value)) - for k, v := range value { - array[k] = Int64(v) - } - } - if array != nil { - return array - } - if v, ok := any.(localinterface.IInts); ok { - return Int64s(v.Ints()) - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Int64s(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]int64, length) - ) - for i := 0; i < length; i++ { - slice[i] = Int64(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []int64{} - } - return []int64{Int64(any)} - } +func Int64s(any any) []int64 { + result, _ := defaultConverter.SliceInt64(any, SliceOption{}) + return result } diff --git a/util/gconv/gconv_slice_str.go b/util/gconv/gconv_slice_str.go index ff2157b3c7a..05ee6d02dbd 100644 --- a/util/gconv/gconv_slice_str.go +++ b/util/gconv/gconv_slice_str.go @@ -6,17 +6,6 @@ package gconv -import ( - "bytes" - "reflect" - "strings" - - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/reflection" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" -) - // SliceStr is alias of Strings. func SliceStr(any interface{}) []string { return Strings(any) @@ -24,140 +13,6 @@ func SliceStr(any interface{}) []string { // Strings converts `any` to []string. func Strings(any interface{}) []string { - if empty.IsNil(any) { - return nil - } - var ( - array []string = nil - ) - switch value := any.(type) { - case []int: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []int8: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []int16: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []int32: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []int64: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []uint: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - return array - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []string{} - } - return []string{value} - case []uint16: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []uint32: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []uint64: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []bool: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []float32: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []float64: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []interface{}: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - case []string: - array = value - case [][]byte: - array = make([]string, len(value)) - for k, v := range value { - array[k] = String(v) - } - } - if array != nil { - return array - } - if v, ok := any.(localinterface.IStrings); ok { - return v.Strings() - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Strings(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]string, length) - ) - for i := 0; i < length; i++ { - slice[i] = String(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []string{} - } - return []string{String(any)} - } + result, _ := defaultConverter.SliceStr(any, SliceOption{}) + return result } diff --git a/util/gconv/gconv_slice_uint.go b/util/gconv/gconv_slice_uint.go index 00ae9e491b2..a3c9f44c455 100644 --- a/util/gconv/gconv_slice_uint.go +++ b/util/gconv/gconv_slice_uint.go @@ -6,18 +6,6 @@ package gconv -import ( - "bytes" - "reflect" - "strings" - - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/reflection" - "github.com/gogf/gf/v2/internal/utils" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" -) - // SliceUint is alias of Uints. func SliceUint(any interface{}) []uint { return Uints(any) @@ -35,426 +23,18 @@ func SliceUint64(any interface{}) []uint64 { // Uints converts `any` to []uint. func Uints(any interface{}) []uint { - if empty.IsNil(any) { - return nil - } - var ( - array []uint = nil - ) - switch value := any.(type) { - case []string: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = Uint(v) - } - case []int8: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case []int16: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case []int32: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case []int64: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case []uint: - array = value - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []uint{} - } - if utils.IsNumeric(value) { - return []uint{Uint(value)} - } - case []uint16: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case []uint32: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case []uint64: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = uint(v) - } - case []bool: - array = make([]uint, len(value)) - for k, v := range value { - if v { - array[k] = 1 - } else { - array[k] = 0 - } - } - case []float32: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = Uint(v) - } - case []float64: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = Uint(v) - } - case []interface{}: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = Uint(v) - } - case [][]byte: - array = make([]uint, len(value)) - for k, v := range value { - array[k] = Uint(v) - } - } - - if array != nil { - return array - } - - // Default handler. - if v, ok := any.(localinterface.IUints); ok { - return v.Uints() - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Uints(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]uint, length) - ) - for i := 0; i < length; i++ { - slice[i] = Uint(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []uint{} - } - return []uint{Uint(any)} - } + result, _ := defaultConverter.SliceUint(any, SliceOption{}) + return result } // Uint32s converts `any` to []uint32. func Uint32s(any interface{}) []uint32 { - if empty.IsNil(any) { - return nil - } - var ( - array []uint32 = nil - ) - switch value := any.(type) { - case []string: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = Uint32(v) - } - case []int8: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case []int16: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case []int32: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case []int64: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case []uint: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []uint32{} - } - if utils.IsNumeric(value) { - return []uint32{Uint32(value)} - } - case []uint16: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case []uint32: - array = value - case []uint64: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = uint32(v) - } - case []bool: - array = make([]uint32, len(value)) - for k, v := range value { - if v { - array[k] = 1 - } else { - array[k] = 0 - } - } - case []float32: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = Uint32(v) - } - case []float64: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = Uint32(v) - } - case []interface{}: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = Uint32(v) - } - case [][]byte: - array = make([]uint32, len(value)) - for k, v := range value { - array[k] = Uint32(v) - } - } - if array != nil { - return array - } - - // Default handler. - if v, ok := any.(localinterface.IUints); ok { - return Uint32s(v.Uints()) - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Uint32s(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]uint32, length) - ) - for i := 0; i < length; i++ { - slice[i] = Uint32(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []uint32{} - } - return []uint32{Uint32(any)} - } + result, _ := defaultConverter.SliceUint32(any, SliceOption{}) + return result } // Uint64s converts `any` to []uint64. func Uint64s(any interface{}) []uint64 { - if empty.IsNil(any) { - return nil - } - var ( - array []uint64 = nil - ) - switch value := any.(type) { - case []string: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = Uint64(v) - } - case []int8: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case []int16: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case []int32: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case []int64: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case []uint: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case []uint8: - if json.Valid(value) { - if _ = json.UnmarshalUseNumber(value, &array); array != nil { - return array - } - if bytes.EqualFold([]byte("null"), value) { - return nil - } - } - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case string: - byteValue := []byte(value) - if json.Valid(byteValue) { - if _ = json.UnmarshalUseNumber(byteValue, &array); array != nil { - return array - } - if strings.EqualFold(value, "null") { - return nil - } - } - if value == "" { - return []uint64{} - } - if utils.IsNumeric(value) { - return []uint64{Uint64(value)} - } - case []uint16: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case []uint32: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = uint64(v) - } - case []uint64: - array = value - case []bool: - array = make([]uint64, len(value)) - for k, v := range value { - if v { - array[k] = 1 - } else { - array[k] = 0 - } - } - case []float32: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = Uint64(v) - } - case []float64: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = Uint64(v) - } - case []interface{}: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = Uint64(v) - } - case [][]byte: - array = make([]uint64, len(value)) - for k, v := range value { - array[k] = Uint64(v) - } - } - if array != nil { - return array - } - // Default handler. - if v, ok := any.(localinterface.IUints); ok { - return Uint64s(v.Uints()) - } - if v, ok := any.(localinterface.IInterfaces); ok { - return Uint64s(v.Interfaces()) - } - // Not a common type, it then uses reflection for conversion. - originValueAndKind := reflection.OriginValueAndKind(any) - switch originValueAndKind.OriginKind { - case reflect.Slice, reflect.Array: - var ( - length = originValueAndKind.OriginValue.Len() - slice = make([]uint64, length) - ) - for i := 0; i < length; i++ { - slice[i] = Uint64(originValueAndKind.OriginValue.Index(i).Interface()) - } - return slice - - default: - if originValueAndKind.OriginValue.IsZero() { - return []uint64{} - } - return []uint64{Uint64(any)} - } + result, _ := defaultConverter.SliceUint64(any, SliceOption{}) + return result } diff --git a/util/gconv/internal/structcache/structcache.go b/util/gconv/internal/structcache/structcache.go index ace2236da2c..4f753132bc4 100644 --- a/util/gconv/internal/structcache/structcache.go +++ b/util/gconv/internal/structcache/structcache.go @@ -14,10 +14,8 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -type AnyConvertFunc func(from any, to reflect.Value) error - -// ConvertConfig is the configuration for type converting. -type ConvertConfig struct { +// Converter is the configuration for type converting. +type Converter struct { // map[reflect.Type]*CachedStructInfo cachedStructsInfoMap sync.Map @@ -28,9 +26,12 @@ type ConvertConfig struct { anyToTypeConvertMap map[reflect.Type]AnyConvertFunc } -// NewConvertConfig creates and returns a new ConvertConfig object. -func NewConvertConfig() *ConvertConfig { - return &ConvertConfig{ +// AnyConvertFunc is the function type for converting any to specified type. +type AnyConvertFunc func(from any, to reflect.Value) error + +// NewConverter creates and returns a new Converter object. +func NewConverter() *Converter { + return &Converter{ cachedStructsInfoMap: sync.Map{}, typeConverterFuncMap: make(map[reflect.Type]struct{}), anyToTypeConvertMap: make(map[reflect.Type]AnyConvertFunc), @@ -38,7 +39,7 @@ func NewConvertConfig() *ConvertConfig { } // RegisterTypeConvertFunc registers converting function for custom type. -func (cf *ConvertConfig) RegisterTypeConvertFunc(fieldType reflect.Type) { +func (cf *Converter) RegisterTypeConvertFunc(fieldType reflect.Type) { if fieldType.Kind() == reflect.Ptr { fieldType = fieldType.Elem() } @@ -46,7 +47,7 @@ func (cf *ConvertConfig) RegisterTypeConvertFunc(fieldType reflect.Type) { } // RegisterAnyConvertFunc registers custom type converting function for specified type. -func (cf *ConvertConfig) RegisterAnyConvertFunc(t reflect.Type, convertFunc AnyConvertFunc) { +func (cf *Converter) RegisterAnyConvertFunc(t reflect.Type, convertFunc AnyConvertFunc) { cf.anyToTypeConvertMap[t] = convertFunc } diff --git a/util/gconv/internal/structcache/structcache_cached.go b/util/gconv/internal/structcache/structcache_cached.go index 98611ae1661..44f1412dfb2 100644 --- a/util/gconv/internal/structcache/structcache_cached.go +++ b/util/gconv/internal/structcache/structcache_cached.go @@ -15,7 +15,7 @@ import ( // GetCachedStructInfo retrieves or parses and returns a cached info for certain struct type. // The given `structType` should be type of struct. -func (cf *ConvertConfig) GetCachedStructInfo(structType reflect.Type, priorityTag string) *CachedStructInfo { +func (cf *Converter) GetCachedStructInfo(structType reflect.Type, priorityTag string) *CachedStructInfo { if structType.Kind() != reflect.Struct { return nil } @@ -44,12 +44,12 @@ func (cf *ConvertConfig) GetCachedStructInfo(structType reflect.Type, priorityTa return cachedStructInfo } -func (cf *ConvertConfig) storeCachedStructInfo(structType reflect.Type, cachedStructInfo *CachedStructInfo) { +func (cf *Converter) storeCachedStructInfo(structType reflect.Type, cachedStructInfo *CachedStructInfo) { // Temporarily enabled as an experimental feature cf.cachedStructsInfoMap.Store(structType, cachedStructInfo) } -func (cf *ConvertConfig) getCachedConvertStructInfo(structType reflect.Type) (*CachedStructInfo, bool) { +func (cf *Converter) getCachedConvertStructInfo(structType reflect.Type) (*CachedStructInfo, bool) { // Temporarily enabled as an experimental feature v, ok := cf.cachedStructsInfoMap.Load(structType) if ok { @@ -60,7 +60,7 @@ func (cf *ConvertConfig) getCachedConvertStructInfo(structType reflect.Type) (*C // parseStructToCachedStructInfo parses given struct reflection type and stores its fields info into given CachedStructInfo. // It stores nothing into CachedStructInfo if given struct reflection type has no fields. -func (cf *ConvertConfig) parseStructToCachedStructInfo( +func (cf *Converter) parseStructToCachedStructInfo( structType reflect.Type, fieldIndexes []int, cachedStructInfo *CachedStructInfo, From 56a36f58ee02fcb9a88cbcb269b49af1794b6afb Mon Sep 17 00:00:00 2001 From: John Guo Date: Sun, 2 Mar 2025 22:28:22 +0800 Subject: [PATCH 25/48] up --- util/gconv/gconv_converter_doMapConvert.go | 504 ---------- util/gconv/gconv_converter_map.go | 1037 +++++++++++--------- util/gconv/gconv_converter_scan.go | 6 +- util/gconv/gconv_converter_struct.go | 9 +- util/gconv/gconv_map.go | 40 +- 5 files changed, 569 insertions(+), 1027 deletions(-) delete mode 100644 util/gconv/gconv_converter_doMapConvert.go diff --git a/util/gconv/gconv_converter_doMapConvert.go b/util/gconv/gconv_converter_doMapConvert.go deleted file mode 100644 index fb33f965853..00000000000 --- a/util/gconv/gconv_converter_doMapConvert.go +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package gconv - -import ( - "reflect" - "strings" - - "github.com/gogf/gf/v2/internal/empty" - "github.com/gogf/gf/v2/internal/json" - "github.com/gogf/gf/v2/internal/utils" - "github.com/gogf/gf/v2/util/gconv/internal/localinterface" - "github.com/gogf/gf/v2/util/gtag" -) - -// MapConvert implements the map converting. -// It automatically checks and converts json string to map if `value` is string/[]byte. -// -// TODO completely implement the recursive converting for all types, especially the map. -func (c *impConverter) doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool, option ...MapOption) map[string]interface{} { - if value == nil { - return nil - } - // It redirects to its underlying value if it has implemented interface iVal. - if v, ok := value.(localinterface.IVal); ok { - value = v.Val() - } - var ( - usedOption = getUsedMapOption(option...) - newTags = gtag.StructTagPriority - ) - if usedOption.Deep { - recursive = recursiveTypeTrue - } - switch len(usedOption.Tags) { - case 0: - // No need handling. - case 1: - newTags = append(strings.Split(usedOption.Tags[0], ","), gtag.StructTagPriority...) - default: - newTags = append(usedOption.Tags, gtag.StructTagPriority...) - } - // Assert the common combination of types, and finally it uses reflection. - dataMap := make(map[string]interface{}) - switch r := value.(type) { - case string: - // If it is a JSON string, automatically unmarshal it! - if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { - if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil { - return nil - } - } else { - return nil - } - case []byte: - // If it is a JSON string, automatically unmarshal it! - if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { - if err := json.UnmarshalUseNumber(r, &dataMap); err != nil { - return nil - } - } else { - return nil - } - case map[interface{}]interface{}: - recursiveOption := usedOption - recursiveOption.Tags = newTags - for k, v := range r { - dataMap[String(k)] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: v, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - }, - ) - } - case map[interface{}]string: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]int: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]uint: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]float32: - for k, v := range r { - dataMap[String(k)] = v - } - case map[interface{}]float64: - for k, v := range r { - dataMap[String(k)] = v - } - case map[string]bool: - for k, v := range r { - dataMap[k] = v - } - case map[string]int: - for k, v := range r { - dataMap[k] = v - } - case map[string]uint: - for k, v := range r { - dataMap[k] = v - } - case map[string]float32: - for k, v := range r { - dataMap[k] = v - } - case map[string]float64: - for k, v := range r { - dataMap[k] = v - } - case map[string]string: - for k, v := range r { - dataMap[k] = v - } - case map[string]interface{}: - if recursive == recursiveTypeTrue { - recursiveOption := usedOption - recursiveOption.Tags = newTags - // A copy of current map. - for k, v := range r { - dataMap[k] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: v, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - }, - ) - } - } else { - // It returns the map directly without any changing. - return r - } - case map[int]interface{}: - recursiveOption := usedOption - recursiveOption.Tags = newTags - for k, v := range r { - dataMap[String(k)] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: v, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - }, - ) - } - case map[int]string: - for k, v := range r { - dataMap[String(k)] = v - } - case map[uint]string: - for k, v := range r { - dataMap[String(k)] = v - } - - default: - // Not a common type, it then uses reflection for conversion. - var reflectValue reflect.Value - if v, ok := value.(reflect.Value); ok { - reflectValue = v - } else { - reflectValue = reflect.ValueOf(value) - } - reflectKind := reflectValue.Kind() - // If it is a pointer, we should find its real data type. - for reflectKind == reflect.Ptr { - reflectValue = reflectValue.Elem() - reflectKind = reflectValue.Kind() - } - switch reflectKind { - // If `value` is type of array, it converts the value of even number index as its key and - // the value of odd number index as its corresponding value, for example: - // []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"} - // []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil} - case reflect.Slice, reflect.Array: - length := reflectValue.Len() - for i := 0; i < length; i += 2 { - if i+1 < length { - dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface() - } else { - dataMap[String(reflectValue.Index(i).Interface())] = nil - } - } - case reflect.Map, reflect.Struct, reflect.Interface: - recursiveOption := usedOption - recursiveOption.Tags = newTags - convertedValue := c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: true, - Value: value, - RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, - Option: recursiveOption, - MustMapReturn: mustMapReturn, - }, - ) - if m, ok := convertedValue.(map[string]interface{}); ok { - return m - } - return nil - default: - return nil - } - } - return dataMap -} - -func getUsedMapOption(option ...MapOption) MapOption { - var usedOption MapOption - if len(option) > 0 { - usedOption = option[0] - } - return usedOption -} - -type doMapConvertForMapOrStructValueInput struct { - IsRoot bool // It returns directly if it is not root and with no recursive converting. - Value interface{} // Current operation value. - RecursiveType recursiveType // The type from top function entry. - RecursiveOption bool // Whether convert recursively for `current` operation. - Option MapOption // Map converting option. - MustMapReturn bool // Must return map instead of Value when empty. -} - -func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} { - if !in.IsRoot && !in.RecursiveOption { - return in.Value - } - - var reflectValue reflect.Value - if v, ok := in.Value.(reflect.Value); ok { - reflectValue = v - in.Value = v.Interface() - } else { - reflectValue = reflect.ValueOf(in.Value) - } - reflectKind := reflectValue.Kind() - // If it is a pointer, we should find its real data type. - for reflectKind == reflect.Ptr { - reflectValue = reflectValue.Elem() - reflectKind = reflectValue.Kind() - } - switch reflectKind { - case reflect.Map: - var ( - mapIter = reflectValue.MapRange() - dataMap = make(map[string]interface{}) - ) - for mapIter.Next() { - var ( - mapKeyValue = mapIter.Value() - mapValue interface{} - ) - switch { - case mapKeyValue.IsZero(): - if utils.CanCallIsNil(mapKeyValue) && mapKeyValue.IsNil() { - // quick check for nil value. - mapValue = nil - } else { - // in case of: - // exception recovered: reflect: call of reflect.Value.Interface on zero Value - mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface() - } - default: - mapValue = mapKeyValue.Interface() - } - dataMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: mapValue, - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } - return dataMap - - case reflect.Struct: - var dataMap = make(map[string]interface{}) - // Map converting interface check. - if v, ok := in.Value.(localinterface.IMapStrAny); ok { - // Value copy, in case of concurrent safety. - for mapK, mapV := range v.MapStrAny() { - if in.RecursiveOption { - dataMap[mapK] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: mapV, - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } else { - dataMap[mapK] = mapV - } - } - if len(dataMap) > 0 { - return dataMap - } - } - // Using reflect for converting. - var ( - rtField reflect.StructField - rvField reflect.Value - reflectType = reflectValue.Type() // attribute value type. - mapKey = "" // mapKey may be the tag name or the struct attribute name. - ) - for i := 0; i < reflectValue.NumField(); i++ { - rtField = reflectType.Field(i) - rvField = reflectValue.Field(i) - // Only convert the public attributes. - fieldName := rtField.Name - if !utils.IsLetterUpper(fieldName[0]) { - continue - } - mapKey = "" - fieldTag := rtField.Tag - for _, tag := range in.Option.Tags { - if mapKey = fieldTag.Get(tag); mapKey != "" { - break - } - } - if mapKey == "" { - mapKey = fieldName - } else { - // Support json tag feature: -, omitempty - mapKey = strings.TrimSpace(mapKey) - if mapKey == "-" { - continue - } - array := strings.Split(mapKey, ",") - if len(array) > 1 { - switch strings.TrimSpace(array[1]) { - case "omitempty": - if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) { - continue - } else { - mapKey = strings.TrimSpace(array[0]) - } - default: - mapKey = strings.TrimSpace(array[0]) - } - } - if mapKey == "" { - mapKey = fieldName - } - } - if in.RecursiveOption || rtField.Anonymous { - // Do map converting recursively. - var ( - rvAttrField = rvField - rvAttrKind = rvField.Kind() - ) - if rvAttrKind == reflect.Ptr { - rvAttrField = rvField.Elem() - rvAttrKind = rvAttrField.Kind() - } - switch rvAttrKind { - case reflect.Struct: - // Embedded struct and has no fields, just ignores it. - // Eg: gmeta.Meta - if rvAttrField.Type().NumField() == 0 { - continue - } - var ( - hasNoTag = mapKey == fieldName - // DO NOT use rvAttrField.Interface() here, - // as it might be changed from pointer to struct. - rvInterface = rvField.Interface() - ) - switch { - case hasNoTag && rtField.Anonymous: - // It means this attribute field has no tag. - // Overwrite the attribute with sub-struct attribute fields. - anonymousValue := c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvInterface, - RecursiveType: in.RecursiveType, - RecursiveOption: true, - Option: in.Option, - }) - if m, ok := anonymousValue.(map[string]interface{}); ok { - for k, v := range m { - dataMap[k] = v - } - } else { - dataMap[mapKey] = rvInterface - } - - // It means this attribute field has desired tag. - case !hasNoTag && rtField.Anonymous: - dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvInterface, - RecursiveType: in.RecursiveType, - RecursiveOption: true, - Option: in.Option, - }) - - default: - dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvInterface, - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }) - } - - // The struct attribute is type of slice. - case reflect.Array, reflect.Slice: - length := rvAttrField.Len() - if length == 0 { - dataMap[mapKey] = rvAttrField.Interface() - break - } - array := make([]interface{}, length) - for arrayIndex := 0; arrayIndex < length; arrayIndex++ { - array[arrayIndex] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvAttrField.Index(arrayIndex).Interface(), - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } - dataMap[mapKey] = array - case reflect.Map: - var ( - mapIter = rvAttrField.MapRange() - nestedMap = make(map[string]interface{}) - ) - for mapIter.Next() { - nestedMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( - doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: mapIter.Value().Interface(), - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }, - ) - } - dataMap[mapKey] = nestedMap - default: - if rvField.IsValid() { - dataMap[mapKey] = reflectValue.Field(i).Interface() - } else { - dataMap[mapKey] = nil - } - } - } else { - // No recursive map value converting - if rvField.IsValid() { - dataMap[mapKey] = reflectValue.Field(i).Interface() - } else { - dataMap[mapKey] = nil - } - } - } - if !in.MustMapReturn && len(dataMap) == 0 { - return in.Value - } - return dataMap - - // The given value is type of slice. - case reflect.Array, reflect.Slice: - length := reflectValue.Len() - if length == 0 { - break - } - array := make([]interface{}, reflectValue.Len()) - for i := 0; i < length; i++ { - array[i] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: reflectValue.Index(i).Interface(), - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }) - } - return array - - default: - } - return in.Value -} diff --git a/util/gconv/gconv_converter_map.go b/util/gconv/gconv_converter_map.go index 60a806e6f94..83b980c1521 100644 --- a/util/gconv/gconv_converter_map.go +++ b/util/gconv/gconv_converter_map.go @@ -6,492 +6,555 @@ package gconv -//// MapStrStr converts `value` to map[string]string. -//// Note that there might be data copy for this map type converting. -//func (c *impConverter) MapStrStr(value any, option ...MapOption) (map[string]string, error) { -// if r, ok := value.(map[string]string); ok { -// return r, nil -// } -// m := Map(value, option...) -// if len(m) > 0 { -// vMap := make(map[string]string, len(m)) -// for k, v := range m { -// s, err := c.String(v) -// if err != nil { -// return nil, err -// } -// vMap[k] = s -// } -// return vMap, nil -// } -// return nil, nil -//} -// -//// Map implements the map converting. -//// It automatically checks and converts json string to map if `value` is string/[]byte. -//// -//// TODO completely implement the recursive converting for all types, especially the map. -//func (c *impConverter) Map(value any, option MapOption) (map[string]any, error) { -// if value == nil { -// return nil, nil -// } -// // It redirects to its underlying value if it has implemented interface iVal. -// if v, ok := value.(localinterface.IVal); ok { -// value = v.Val() -// } -// var ( -// newTags = gtag.StructTagPriority -// ) -// switch len(option.Tags) { -// case 0: -// // No need handling. -// case 1: -// newTags = append(strings.Split(option.Tags[0], ","), gtag.StructTagPriority...) -// default: -// newTags = append(option.Tags, gtag.StructTagPriority...) -// } -// // Assert the common combination of types, and finally it uses reflection. -// dataMap := make(map[string]any) -// switch r := value.(type) { -// case string: -// // If it is a JSON string, automatically unmarshal it! -// if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { -// if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil { -// return nil, err -// } -// } else { -// return nil, nil -// } -// case []byte: -// // If it is a JSON string, automatically unmarshal it! -// if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { -// if err := json.UnmarshalUseNumber(r, &dataMap); err != nil { -// return nil, err -// } -// } else { -// return nil, nil -// } -// case map[any]any: -// recursiveOption := option -// recursiveOption.Tags = newTags -// for k, v := range r { -// dataMap[String(k)] = c.doMapConvertForMapOrStructValue( -// doMapConvertForMapOrStructValueInput{ -// IsRoot: false, -// Value: v, -// Recursive: option.Deep, -// Option: recursiveOption, -// }, -// ) -// } -// case map[any]string: -// for k, v := range r { -// dataMap[String(k)] = v -// } -// case map[any]int: -// for k, v := range r { -// dataMap[String(k)] = v -// } -// case map[any]uint: -// for k, v := range r { -// dataMap[String(k)] = v -// } -// case map[any]float32: -// for k, v := range r { -// dataMap[String(k)] = v -// } -// case map[any]float64: -// for k, v := range r { -// dataMap[String(k)] = v -// } -// case map[string]bool: -// for k, v := range r { -// dataMap[k] = v -// } -// case map[string]int: -// for k, v := range r { -// dataMap[k] = v -// } -// case map[string]uint: -// for k, v := range r { -// dataMap[k] = v -// } -// case map[string]float32: -// for k, v := range r { -// dataMap[k] = v -// } -// case map[string]float64: -// for k, v := range r { -// dataMap[k] = v -// } -// case map[string]string: -// for k, v := range r { -// dataMap[k] = v -// } -// case map[string]any: -// if option.Deep { -// recursiveOption := option -// recursiveOption.Tags = newTags -// // A copy of current map. -// for k, v := range r { -// dataMap[k] = c.doMapConvertForMapOrStructValue( -// doMapConvertForMapOrStructValueInput{ -// IsRoot: false, -// Value: v, -// Recursive: option.Deep, -// Option: recursiveOption, -// }, -// ) -// } -// } else { -// // It returns the map directly without any changing. -// return r, nil -// } -// case map[int]any: -// recursiveOption := option -// recursiveOption.Tags = newTags -// for k, v := range r { -// dataMap[String(k)] = c.doMapConvertForMapOrStructValue( -// doMapConvertForMapOrStructValueInput{ -// IsRoot: false, -// Value: v, -// Recursive: option.Deep, -// Option: recursiveOption, -// }, -// ) -// } -// case map[int]string: -// for k, v := range r { -// dataMap[String(k)] = v -// } -// case map[uint]string: -// for k, v := range r { -// dataMap[String(k)] = v -// } -// -// default: -// // Not a common type, it then uses reflection for conversion. -// var reflectValue reflect.Value -// if v, ok := value.(reflect.Value); ok { -// reflectValue = v -// } else { -// reflectValue = reflect.ValueOf(value) -// } -// reflectKind := reflectValue.Kind() -// // If it is a pointer, we should find its real data type. -// for reflectKind == reflect.Ptr { -// reflectValue = reflectValue.Elem() -// reflectKind = reflectValue.Kind() -// } -// switch reflectKind { -// // If `value` is type of array, it converts the value of even number index as its key and -// // the value of odd number index as its corresponding value, for example: -// // []string{"k1","v1","k2","v2"} => map[string]any{"k1":"v1", "k2":"v2"} -// // []string{"k1","v1","k2"} => map[string]any{"k1":"v1", "k2":nil} -// case reflect.Slice, reflect.Array: -// length := reflectValue.Len() -// for i := 0; i < length; i += 2 { -// if i+1 < length { -// dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface() -// } else { -// dataMap[String(reflectValue.Index(i).Interface())] = nil -// } -// } -// case reflect.Map, reflect.Struct, reflect.Interface: -// recursiveOption := option -// recursiveOption.Tags = newTags -// convertedValue := c.doMapConvertForMapOrStructValue( -// doMapConvertForMapOrStructValueInput{ -// IsRoot: true, -// Value: value, -// Recursive: option.Deep, -// Option: recursiveOption, -// MustMapReturn: option.EmptyEvenNil, -// }, -// ) -// if m, ok := convertedValue.(map[string]any); ok { -// return m, nil -// } -// return nil, nil -// default: -// return nil, nil -// } -// } -// return dataMap, nil -//} -// -//func getUsedMapOption(option ...MapOption) MapOption { -// var usedOption MapOption -// if len(option) > 0 { -// usedOption = option[0] -// } -// return usedOption -//} -// -//type doMapConvertForMapOrStructValueInput struct { -// IsRoot bool // It returns directly if it is not root and with no recursive converting. -// Value any // Current operation value. -// Recursive bool // Whether convert recursively for `current` operation. -// Option MapOption // Map converting option. -// MustMapReturn bool // Must return map instead of Value when empty. -//} -// -//func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) any { -// if !in.IsRoot && !in.Recursive { -// return in.Value -// } -// -// var reflectValue reflect.Value -// if v, ok := in.Value.(reflect.Value); ok { -// reflectValue = v -// in.Value = v.Interface() -// } else { -// reflectValue = reflect.ValueOf(in.Value) -// } -// reflectKind := reflectValue.Kind() -// // If it is a pointer, we should find its real data type. -// for reflectKind == reflect.Ptr { -// reflectValue = reflectValue.Elem() -// reflectKind = reflectValue.Kind() -// } -// switch reflectKind { -// case reflect.Map: -// var ( -// mapIter = reflectValue.MapRange() -// dataMap = make(map[string]any) -// ) -// for mapIter.Next() { -// var ( -// mapKeyValue = mapIter.Value() -// mapValue any -// ) -// switch { -// case mapKeyValue.IsZero(): -// if utils.CanCallIsNil(mapKeyValue) && mapKeyValue.IsNil() { -// // quick check for nil value. -// mapValue = nil -// } else { -// // in case of: -// // exception recovered: reflect: call of reflect.Value.Interface on zero Value -// mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface() -// } -// default: -// mapValue = mapKeyValue.Interface() -// } -// dataMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( -// doMapConvertForMapOrStructValueInput{ -// IsRoot: false, -// Value: mapValue, -// Recursive: in.Recursive, -// Option: in.Option, -// }, -// ) -// } -// return dataMap -// -// case reflect.Struct: -// var dataMap = make(map[string]any) -// // Map converting interface check. -// if v, ok := in.Value.(localinterface.IMapStrAny); ok { -// // Value copy, in case of concurrent safety. -// for mapK, mapV := range v.MapStrAny() { -// if in.Recursive { -// dataMap[mapK] = c.doMapConvertForMapOrStructValue( -// doMapConvertForMapOrStructValueInput{ -// IsRoot: false, -// Value: mapV, -// Recursive: in.Recursive, -// Option: in.Option, -// }, -// ) -// } else { -// dataMap[mapK] = mapV -// } -// } -// if len(dataMap) > 0 { -// return dataMap -// } -// } -// // Using reflect for converting. -// var ( -// rtField reflect.StructField -// rvField reflect.Value -// reflectType = reflectValue.Type() // attribute value type. -// mapKey = "" // mapKey may be the tag name or the struct attribute name. -// ) -// for i := 0; i < reflectValue.NumField(); i++ { -// rtField = reflectType.Field(i) -// rvField = reflectValue.Field(i) -// // Only convert the public attributes. -// fieldName := rtField.Name -// if !utils.IsLetterUpper(fieldName[0]) { -// continue -// } -// mapKey = "" -// fieldTag := rtField.Tag -// for _, tag := range in.Option.Tags { -// if mapKey = fieldTag.Get(tag); mapKey != "" { -// break -// } -// } -// if mapKey == "" { -// mapKey = fieldName -// } else { -// // Support json tag feature: -, omitempty -// mapKey = strings.TrimSpace(mapKey) -// if mapKey == "-" { -// continue -// } -// array := strings.Split(mapKey, ",") -// if len(array) > 1 { -// switch strings.TrimSpace(array[1]) { -// case "omitempty": -// if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) { -// continue -// } else { -// mapKey = strings.TrimSpace(array[0]) -// } -// default: -// mapKey = strings.TrimSpace(array[0]) -// } -// } -// if mapKey == "" { -// mapKey = fieldName -// } -// } -// if in.Recursive || rtField.Anonymous { -// // Do map converting recursively. -// var ( -// rvAttrField = rvField -// rvAttrKind = rvField.Kind() -// ) -// if rvAttrKind == reflect.Ptr { -// rvAttrField = rvField.Elem() -// rvAttrKind = rvAttrField.Kind() -// } -// switch rvAttrKind { -// case reflect.Struct: -// // Embedded struct and has no fields, just ignores it. -// // Eg: gmeta.Meta -// if rvAttrField.Type().NumField() == 0 { -// continue -// } -// var ( -// hasNoTag = mapKey == fieldName -// // DO NOT use rvAttrField.Interface() here, -// // as it might be changed from pointer to struct. -// rvInterface = rvField.Interface() -// ) -// switch { -// case hasNoTag && rtField.Anonymous: -// // It means this attribute field has no tag. -// // Overwrite the attribute with sub-struct attribute fields. -// anonymousValue := c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ -// IsRoot: false, -// Value: rvInterface, -// Recursive: true, -// Option: in.Option, -// }) -// if m, ok := anonymousValue.(map[string]any); ok { -// for k, v := range m { -// dataMap[k] = v -// } -// } else { -// dataMap[mapKey] = rvInterface -// } -// -// // It means this attribute field has desired tag. -// case !hasNoTag && rtField.Anonymous: -// dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ -// IsRoot: false, -// Value: rvInterface, -// Recursive: true, -// Option: in.Option, -// }) -// -// default: -// dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ -// IsRoot: false, -// Value: rvInterface, -// Recursive: in.Recursive, -// Option: in.Option, -// }) -// } -// -// // The struct attribute is type of slice. -// case reflect.Array, reflect.Slice: -// length := rvAttrField.Len() -// if length == 0 { -// dataMap[mapKey] = rvAttrField.Interface() -// break -// } -// array := make([]any, length) -// for arrayIndex := 0; arrayIndex < length; arrayIndex++ { -// array[arrayIndex] = c.doMapConvertForMapOrStructValue( -// doMapConvertForMapOrStructValueInput{ -// IsRoot: false, -// Value: rvAttrField.Index(arrayIndex).Interface(), -// Recursive: in.Recursive, -// Option: in.Option, -// }, -// ) -// } -// dataMap[mapKey] = array -// case reflect.Map: -// var ( -// mapIter = rvAttrField.MapRange() -// nestedMap = make(map[string]any) -// ) -// for mapIter.Next() { -// nestedMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( -// doMapConvertForMapOrStructValueInput{ -// IsRoot: false, -// Value: mapIter.Value().Interface(), -// Recursive: in.Recursive, -// Option: in.Option, -// }, -// ) -// } -// dataMap[mapKey] = nestedMap -// default: -// if rvField.IsValid() { -// dataMap[mapKey] = reflectValue.Field(i).Interface() -// } else { -// dataMap[mapKey] = nil -// } -// } -// } else { -// // No recursive map value converting -// if rvField.IsValid() { -// dataMap[mapKey] = reflectValue.Field(i).Interface() -// } else { -// dataMap[mapKey] = nil -// } -// } -// } -// if !in.MustMapReturn && len(dataMap) == 0 { -// return in.Value -// } -// return dataMap +import ( + "reflect" + "strings" + + "github.com/gogf/gf/v2/internal/empty" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/internal/utils" + "github.com/gogf/gf/v2/util/gconv/internal/localinterface" + "github.com/gogf/gf/v2/util/gtag" +) + +// MapOption specifies the option for map converting. +type MapOption struct { + // Deep marks doing Map function recursively, which means if the attribute of given converting value + // is also a struct/*struct, it automatically calls Map function on this attribute converting it to + // a map[string]any type variable. + Deep bool + + // OmitEmpty ignores the attributes that has json `omitempty` tag. + OmitEmpty bool + + // Tags specifies the converted map key name by struct tag name. + Tags []string + + // FailBreak specifies whether to break converting the next element + // if one element conversion fails in map. + FailBreak bool +} + +// Map converts any variable `value` to map[string]any. If the parameter `value` is not a +// map/struct/*struct type, then the conversion will fail and returns nil. // -// // The given value is type of slice. -// case reflect.Array, reflect.Slice: -// length := reflectValue.Len() -// if length == 0 { -// break -// } -// array := make([]any, reflectValue.Len()) -// for i := 0; i < length; i++ { -// array[i] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ -// IsRoot: false, -// Value: reflectValue.Index(i).Interface(), -// Recursive: in.Recursive, -// Option: in.Option, -// }) -// } -// return array +// If `value` is a struct/*struct object, the second parameter `priorityTagAndFieldName` specifies the most priority +// priorityTagAndFieldName that will be detected, otherwise it detects the priorityTagAndFieldName in order of: +// gconv, json, field name. +func (c *impConverter) Map(value any, option MapOption) (map[string]any, error) { + return c.doMapConvert(value, recursiveTypeAuto, false, option) +} + +// MapStrStr converts `value` to map[string]string. +// Note that there might be data copy for this map type converting. +func (c *impConverter) MapStrStr(value any, option MapOption) (map[string]string, error) { + if r, ok := value.(map[string]string); ok { + return r, nil + } + m, err := c.Map(value, option) + if err != nil && option.FailBreak { + return nil, err + } + if len(m) > 0 { + var ( + s string + vMap = make(map[string]string, len(m)) + ) + for k, v := range m { + s, err = c.String(v) + if err != nil && option.FailBreak { + return nil, err + } + vMap[k] = s + } + return vMap, nil + } + return nil, nil +} + +// MapConvert implements the map converting. +// It automatically checks and converts json string to map if `value` is string/[]byte. // -// default: -// } -// return in.Value -//} +// TODO completely implement the recursive converting for all types, especially the map. +func (c *impConverter) doMapConvert( + value any, recursive recursiveType, mustMapReturn bool, option MapOption, +) (map[string]any, error) { + if value == nil { + return nil, nil + } + // It redirects to its underlying value if it has implemented interface iVal. + if v, ok := value.(localinterface.IVal); ok { + value = v.Val() + } + var ( + newTags = gtag.StructTagPriority + ) + if option.Deep { + recursive = recursiveTypeTrue + } + switch len(option.Tags) { + case 0: + // No need handling. + case 1: + newTags = append(strings.Split(option.Tags[0], ","), gtag.StructTagPriority...) + default: + newTags = append(option.Tags, gtag.StructTagPriority...) + } + // Assert the common combination of types, and finally it uses reflection. + dataMap := make(map[string]interface{}) + switch r := value.(type) { + case string: + // If it is a JSON string, automatically unmarshal it! + if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { + if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil { + return nil, err + } + } else { + return nil, nil + } + case []byte: + // If it is a JSON string, automatically unmarshal it! + if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { + if err := json.UnmarshalUseNumber(r, &dataMap); err != nil { + return nil, err + } + } else { + return nil, nil + } + case map[interface{}]interface{}: + recursiveOption := option + recursiveOption.Tags = newTags + for k, v := range r { + dataMap[String(k)] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: v, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + }, + ) + } + case map[interface{}]string: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]int: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]uint: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]float32: + for k, v := range r { + dataMap[String(k)] = v + } + case map[interface{}]float64: + for k, v := range r { + dataMap[String(k)] = v + } + case map[string]bool: + for k, v := range r { + dataMap[k] = v + } + case map[string]int: + for k, v := range r { + dataMap[k] = v + } + case map[string]uint: + for k, v := range r { + dataMap[k] = v + } + case map[string]float32: + for k, v := range r { + dataMap[k] = v + } + case map[string]float64: + for k, v := range r { + dataMap[k] = v + } + case map[string]string: + for k, v := range r { + dataMap[k] = v + } + case map[string]interface{}: + if recursive == recursiveTypeTrue { + recursiveOption := option + recursiveOption.Tags = newTags + // A copy of current map. + for k, v := range r { + dataMap[k] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: v, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + }, + ) + } + } else { + // It returns the map directly without any changing. + return r, nil + } + case map[int]interface{}: + recursiveOption := option + recursiveOption.Tags = newTags + for k, v := range r { + dataMap[String(k)] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: v, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + }, + ) + } + case map[int]string: + for k, v := range r { + dataMap[String(k)] = v + } + case map[uint]string: + for k, v := range r { + dataMap[String(k)] = v + } + + default: + // Not a common type, it then uses reflection for conversion. + var reflectValue reflect.Value + if v, ok := value.(reflect.Value); ok { + reflectValue = v + } else { + reflectValue = reflect.ValueOf(value) + } + reflectKind := reflectValue.Kind() + // If it is a pointer, we should find its real data type. + for reflectKind == reflect.Ptr { + reflectValue = reflectValue.Elem() + reflectKind = reflectValue.Kind() + } + switch reflectKind { + // If `value` is type of array, it converts the value of even number index as its key and + // the value of odd number index as its corresponding value, for example: + // []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"} + // []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil} + case reflect.Slice, reflect.Array: + length := reflectValue.Len() + for i := 0; i < length; i += 2 { + if i+1 < length { + dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface() + } else { + dataMap[String(reflectValue.Index(i).Interface())] = nil + } + } + case reflect.Map, reflect.Struct, reflect.Interface: + recursiveOption := option + recursiveOption.Tags = newTags + convertedValue := c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: true, + Value: value, + RecursiveType: recursive, + RecursiveOption: recursive == recursiveTypeTrue, + Option: recursiveOption, + MustMapReturn: mustMapReturn, + }, + ) + if m, ok := convertedValue.(map[string]interface{}); ok { + return m, nil + } + return nil, nil + default: + return nil, nil + } + } + return dataMap, nil +} + +func getUsedMapOption(option ...MapOption) MapOption { + var usedOption MapOption + if len(option) > 0 { + usedOption = option[0] + } + return usedOption +} + +type doMapConvertForMapOrStructValueInput struct { + IsRoot bool // It returns directly if it is not root and with no recursive converting. + Value interface{} // Current operation value. + RecursiveType recursiveType // The type from top function entry. + RecursiveOption bool // Whether convert recursively for `current` operation. + Option MapOption // Map converting option. + MustMapReturn bool // Must return map instead of Value when empty. +} + +func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} { + if !in.IsRoot && !in.RecursiveOption { + return in.Value + } + + var reflectValue reflect.Value + if v, ok := in.Value.(reflect.Value); ok { + reflectValue = v + in.Value = v.Interface() + } else { + reflectValue = reflect.ValueOf(in.Value) + } + reflectKind := reflectValue.Kind() + // If it is a pointer, we should find its real data type. + for reflectKind == reflect.Ptr { + reflectValue = reflectValue.Elem() + reflectKind = reflectValue.Kind() + } + switch reflectKind { + case reflect.Map: + var ( + mapIter = reflectValue.MapRange() + dataMap = make(map[string]interface{}) + ) + for mapIter.Next() { + var ( + mapKeyValue = mapIter.Value() + mapValue interface{} + ) + switch { + case mapKeyValue.IsZero(): + if utils.CanCallIsNil(mapKeyValue) && mapKeyValue.IsNil() { + // quick check for nil value. + mapValue = nil + } else { + // in case of: + // exception recovered: reflect: call of reflect.Value.Interface on zero Value + mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface() + } + default: + mapValue = mapKeyValue.Interface() + } + dataMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: mapValue, + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } + return dataMap + + case reflect.Struct: + var dataMap = make(map[string]interface{}) + // Map converting interface check. + if v, ok := in.Value.(localinterface.IMapStrAny); ok { + // Value copy, in case of concurrent safety. + for mapK, mapV := range v.MapStrAny() { + if in.RecursiveOption { + dataMap[mapK] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: mapV, + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } else { + dataMap[mapK] = mapV + } + } + if len(dataMap) > 0 { + return dataMap + } + } + // Using reflect for converting. + var ( + rtField reflect.StructField + rvField reflect.Value + reflectType = reflectValue.Type() // attribute value type. + mapKey = "" // mapKey may be the tag name or the struct attribute name. + ) + for i := 0; i < reflectValue.NumField(); i++ { + rtField = reflectType.Field(i) + rvField = reflectValue.Field(i) + // Only convert the public attributes. + fieldName := rtField.Name + if !utils.IsLetterUpper(fieldName[0]) { + continue + } + mapKey = "" + fieldTag := rtField.Tag + for _, tag := range in.Option.Tags { + if mapKey = fieldTag.Get(tag); mapKey != "" { + break + } + } + if mapKey == "" { + mapKey = fieldName + } else { + // Support json tag feature: -, omitempty + mapKey = strings.TrimSpace(mapKey) + if mapKey == "-" { + continue + } + array := strings.Split(mapKey, ",") + if len(array) > 1 { + switch strings.TrimSpace(array[1]) { + case "omitempty": + if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) { + continue + } else { + mapKey = strings.TrimSpace(array[0]) + } + default: + mapKey = strings.TrimSpace(array[0]) + } + } + if mapKey == "" { + mapKey = fieldName + } + } + if in.RecursiveOption || rtField.Anonymous { + // Do map converting recursively. + var ( + rvAttrField = rvField + rvAttrKind = rvField.Kind() + ) + if rvAttrKind == reflect.Ptr { + rvAttrField = rvField.Elem() + rvAttrKind = rvAttrField.Kind() + } + switch rvAttrKind { + case reflect.Struct: + // Embedded struct and has no fields, just ignores it. + // Eg: gmeta.Meta + if rvAttrField.Type().NumField() == 0 { + continue + } + var ( + hasNoTag = mapKey == fieldName + // DO NOT use rvAttrField.Interface() here, + // as it might be changed from pointer to struct. + rvInterface = rvField.Interface() + ) + switch { + case hasNoTag && rtField.Anonymous: + // It means this attribute field has no tag. + // Overwrite the attribute with sub-struct attribute fields. + anonymousValue := c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvInterface, + RecursiveType: in.RecursiveType, + RecursiveOption: true, + Option: in.Option, + }) + if m, ok := anonymousValue.(map[string]interface{}); ok { + for k, v := range m { + dataMap[k] = v + } + } else { + dataMap[mapKey] = rvInterface + } + + // It means this attribute field has desired tag. + case !hasNoTag && rtField.Anonymous: + dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvInterface, + RecursiveType: in.RecursiveType, + RecursiveOption: true, + Option: in.Option, + }) + + default: + dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvInterface, + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }) + } + + // The struct attribute is type of slice. + case reflect.Array, reflect.Slice: + length := rvAttrField.Len() + if length == 0 { + dataMap[mapKey] = rvAttrField.Interface() + break + } + array := make([]interface{}, length) + for arrayIndex := 0; arrayIndex < length; arrayIndex++ { + array[arrayIndex] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvAttrField.Index(arrayIndex).Interface(), + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } + dataMap[mapKey] = array + case reflect.Map: + var ( + mapIter = rvAttrField.MapRange() + nestedMap = make(map[string]interface{}) + ) + for mapIter.Next() { + nestedMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: mapIter.Value().Interface(), + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + } + dataMap[mapKey] = nestedMap + default: + if rvField.IsValid() { + dataMap[mapKey] = reflectValue.Field(i).Interface() + } else { + dataMap[mapKey] = nil + } + } + } else { + // No recursive map value converting + if rvField.IsValid() { + dataMap[mapKey] = reflectValue.Field(i).Interface() + } else { + dataMap[mapKey] = nil + } + } + } + if !in.MustMapReturn && len(dataMap) == 0 { + return in.Value + } + return dataMap + + // The given value is type of slice. + case reflect.Array, reflect.Slice: + length := reflectValue.Len() + if length == 0 { + break + } + array := make([]interface{}, reflectValue.Len()) + for i := 0; i < length; i++ { + array[i] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: reflectValue.Index(i).Interface(), + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }) + } + return array + + default: + } + return in.Value +} diff --git a/util/gconv/gconv_converter_scan.go b/util/gconv/gconv_converter_scan.go index ccd012e7800..344e18f25eb 100644 --- a/util/gconv/gconv_converter_scan.go +++ b/util/gconv/gconv_converter_scan.go @@ -188,7 +188,7 @@ func (c *impConverter) doScanForComplicatedTypes( paramKeyToAttrMap ...map[string]string, ) error { // Try JSON conversion first - ok, err := doConvertWithJsonCheck(srcValue, dstPointer) + ok, err := c.doConvertWithJsonCheck(srcValue, dstPointer) if err != nil { return err } @@ -292,7 +292,7 @@ func doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem ref // Returns: // - bool: true if JSON conversion was successful // - error: any error that occurred during conversion -func doConvertWithJsonCheck(srcValue any, dstPointer any) (ok bool, err error) { +func (c *impConverter) doConvertWithJsonCheck(srcValue any, dstPointer any) (ok bool, err error) { switch valueResult := srcValue.(type) { case []byte: if json.Valid(valueResult) { @@ -329,7 +329,7 @@ func doConvertWithJsonCheck(srcValue any, dstPointer any) (ok bool, err error) { default: // The `params` might be struct that implements interface function Interface, eg: gvar.Var. if v, ok := srcValue.(localinterface.IInterface); ok { - return doConvertWithJsonCheck(v.Interface(), dstPointer) + return c.doConvertWithJsonCheck(v.Interface(), dstPointer) } } return false, nil diff --git a/util/gconv/gconv_converter_struct.go b/util/gconv/gconv_converter_struct.go index ab254be3121..bd38209d895 100644 --- a/util/gconv/gconv_converter_struct.go +++ b/util/gconv/gconv_converter_struct.go @@ -35,7 +35,7 @@ func (c *impConverter) Struct( } // JSON content converting. - ok, err := doConvertWithJsonCheck(params, pointer) + ok, err := c.doConvertWithJsonCheck(params, pointer) if err != nil { return err } @@ -133,7 +133,10 @@ func (c *impConverter) Struct( if !ok { // paramsMap is the map[string]any type variable for params. // DO NOT use MapDeep here. - paramsMap = c.doMapConvert(paramsInterface, recursiveTypeAuto, true) + paramsMap, err = c.doMapConvert(paramsInterface, recursiveTypeAuto, true, MapOption{}) + if err != nil { + return err + } if paramsMap == nil { return gerror.NewCodef( gcode.CodeInvalidParameter, @@ -443,7 +446,7 @@ func (c *impConverter) bindVarToReflectValue( structFieldValue reflect.Value, value any, paramKeyToAttrMap map[string]string, ) (err error) { // JSON content converting. - ok, err := doConvertWithJsonCheck(value, structFieldValue) + ok, err := c.doConvertWithJsonCheck(value, structFieldValue) if err != nil { return err } diff --git a/util/gconv/gconv_map.go b/util/gconv/gconv_map.go index 8523c3a423a..246129527a0 100644 --- a/util/gconv/gconv_map.go +++ b/util/gconv/gconv_map.go @@ -13,20 +13,6 @@ const ( recursiveTypeTrue recursiveType = "true" ) -// MapOption specifies the option for map converting. -type MapOption struct { - // Deep marks doing Map function recursively, which means if the attribute of given converting value - // is also a struct/*struct, it automatically calls Map function on this attribute converting it to - // a map[string]any type variable. - Deep bool - - // OmitEmpty ignores the attributes that has json `omitempty` tag. - OmitEmpty bool - - // Tags specifies the converted map key name by struct tag name. - Tags []string -} - // Map converts any variable `value` to map[string]any. If the parameter `value` is not a // map/struct/*struct type, then the conversion will fail and returns nil. // @@ -34,7 +20,8 @@ type MapOption struct { // priorityTagAndFieldName that will be detected, otherwise it detects the priorityTagAndFieldName in order of: // gconv, json, field name. func Map(value any, option ...MapOption) map[string]any { - return defaultConverter.doMapConvert(value, recursiveTypeAuto, false, option...) + result, _ := defaultConverter.Map(value, getUsedMapOption(option...)) + return result } // MapDeep does Map function recursively, which means if the attribute of `value` @@ -42,27 +29,20 @@ func Map(value any, option ...MapOption) map[string]any { // a map[string]any type variable. // Deprecated: used Map instead. func MapDeep(value any, tags ...string) map[string]any { - return defaultConverter.doMapConvert(value, recursiveTypeTrue, false, MapOption{ - Deep: true, - Tags: tags, + result, _ := defaultConverter.Map(value, MapOption{ + Deep: true, + OmitEmpty: false, + Tags: tags, + FailBreak: false, }) + return result } // MapStrStr converts `value` to map[string]string. // Note that there might be data copy for this map type converting. func MapStrStr(value any, option ...MapOption) map[string]string { - if r, ok := value.(map[string]string); ok { - return r - } - m := Map(value, option...) - if len(m) > 0 { - vMap := make(map[string]string, len(m)) - for k, v := range m { - vMap[k] = String(v) - } - return vMap - } - return nil + result, _ := defaultConverter.MapStrStr(value, getUsedMapOption(option...)) + return result } // MapStrStrDeep converts `value` to map[string]string recursively. From 33a8d32748cfc79e4bc86ed8c9283573a3a49536 Mon Sep 17 00:00:00 2001 From: John Guo Date: Sun, 2 Mar 2025 22:37:49 +0800 Subject: [PATCH 26/48] up --- util/gconv/gconv_converter_map.go | 194 ++++++++++++++++++++++-------- 1 file changed, 144 insertions(+), 50 deletions(-) diff --git a/util/gconv/gconv_converter_map.go b/util/gconv/gconv_converter_map.go index 83b980c1521..c79a802bdba 100644 --- a/util/gconv/gconv_converter_map.go +++ b/util/gconv/gconv_converter_map.go @@ -87,6 +87,7 @@ func (c *impConverter) doMapConvert( value = v.Val() } var ( + err error newTags = gtag.StructTagPriority ) if option.Deep { @@ -106,7 +107,7 @@ func (c *impConverter) doMapConvert( case string: // If it is a JSON string, automatically unmarshal it! if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { - if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil { + if err = json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil { return nil, err } } else { @@ -115,7 +116,7 @@ func (c *impConverter) doMapConvert( case []byte: // If it is a JSON string, automatically unmarshal it! if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' { - if err := json.UnmarshalUseNumber(r, &dataMap); err != nil { + if err = json.UnmarshalUseNumber(r, &dataMap); err != nil { return nil, err } } else { @@ -125,7 +126,11 @@ func (c *impConverter) doMapConvert( recursiveOption := option recursiveOption.Tags = newTags for k, v := range r { - dataMap[String(k)] = c.doMapConvertForMapOrStructValue( + s, err := c.String(k) + if err != nil && option.FailBreak { + return nil, err + } + dataMap[s], err = c.doMapConvertForMapOrStructValue( doMapConvertForMapOrStructValueInput{ IsRoot: false, Value: v, @@ -134,26 +139,49 @@ func (c *impConverter) doMapConvert( Option: recursiveOption, }, ) + if err != nil && option.FailBreak { + return nil, err + } } case map[interface{}]string: for k, v := range r { - dataMap[String(k)] = v + s, err := c.String(k) + if err != nil && option.FailBreak { + return nil, err + } + dataMap[s] = v } case map[interface{}]int: for k, v := range r { - dataMap[String(k)] = v + s, err := c.String(k) + if err != nil && option.FailBreak { + return nil, err + } + dataMap[s] = v } case map[interface{}]uint: for k, v := range r { - dataMap[String(k)] = v + s, err := c.String(k) + if err != nil && option.FailBreak { + return nil, err + } + dataMap[s] = v } case map[interface{}]float32: for k, v := range r { - dataMap[String(k)] = v + s, err := c.String(k) + if err != nil && option.FailBreak { + return nil, err + } + dataMap[s] = v } case map[interface{}]float64: for k, v := range r { - dataMap[String(k)] = v + s, err := c.String(k) + if err != nil && option.FailBreak { + return nil, err + } + dataMap[s] = v } case map[string]bool: for k, v := range r { @@ -185,7 +213,7 @@ func (c *impConverter) doMapConvert( recursiveOption.Tags = newTags // A copy of current map. for k, v := range r { - dataMap[k] = c.doMapConvertForMapOrStructValue( + dataMap[k], err = c.doMapConvertForMapOrStructValue( doMapConvertForMapOrStructValueInput{ IsRoot: false, Value: v, @@ -194,6 +222,9 @@ func (c *impConverter) doMapConvert( Option: recursiveOption, }, ) + if err != nil && option.FailBreak { + return nil, err + } } } else { // It returns the map directly without any changing. @@ -203,7 +234,11 @@ func (c *impConverter) doMapConvert( recursiveOption := option recursiveOption.Tags = newTags for k, v := range r { - dataMap[String(k)] = c.doMapConvertForMapOrStructValue( + s, err := c.String(k) + if err != nil && option.FailBreak { + return nil, err + } + dataMap[s], err = c.doMapConvertForMapOrStructValue( doMapConvertForMapOrStructValueInput{ IsRoot: false, Value: v, @@ -212,14 +247,25 @@ func (c *impConverter) doMapConvert( Option: recursiveOption, }, ) + if err != nil && option.FailBreak { + return nil, err + } } case map[int]string: for k, v := range r { - dataMap[String(k)] = v + s, err := c.String(k) + if err != nil && option.FailBreak { + return nil, err + } + dataMap[s] = v } case map[uint]string: for k, v := range r { - dataMap[String(k)] = v + s, err := c.String(k) + if err != nil && option.FailBreak { + return nil, err + } + dataMap[s] = v } default: @@ -244,16 +290,20 @@ func (c *impConverter) doMapConvert( case reflect.Slice, reflect.Array: length := reflectValue.Len() for i := 0; i < length; i += 2 { + s, err := c.String(String(reflectValue.Index(i).Interface())) + if err != nil && option.FailBreak { + return nil, err + } if i+1 < length { - dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface() + dataMap[s] = reflectValue.Index(i + 1).Interface() } else { - dataMap[String(reflectValue.Index(i).Interface())] = nil + dataMap[s] = nil } } case reflect.Map, reflect.Struct, reflect.Interface: recursiveOption := option recursiveOption.Tags = newTags - convertedValue := c.doMapConvertForMapOrStructValue( + convertedValue, err := c.doMapConvertForMapOrStructValue( doMapConvertForMapOrStructValueInput{ IsRoot: true, Value: value, @@ -263,6 +313,9 @@ func (c *impConverter) doMapConvert( MustMapReturn: mustMapReturn, }, ) + if err != nil && option.FailBreak { + return nil, err + } if m, ok := convertedValue.(map[string]interface{}); ok { return m, nil } @@ -291,12 +344,15 @@ type doMapConvertForMapOrStructValueInput struct { MustMapReturn bool // Must return map instead of Value when empty. } -func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} { +func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) (any, error) { if !in.IsRoot && !in.RecursiveOption { - return in.Value + return in.Value, nil } - var reflectValue reflect.Value + var ( + err error + reflectValue reflect.Value + ) if v, ok := in.Value.(reflect.Value); ok { reflectValue = v in.Value = v.Interface() @@ -333,7 +389,11 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt default: mapValue = mapKeyValue.Interface() } - dataMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( + s, err := c.String(mapIter.Key().Interface()) + if err != nil && in.Option.FailBreak { + return nil, err + } + dataMap[s], err = c.doMapConvertForMapOrStructValue( doMapConvertForMapOrStructValueInput{ IsRoot: false, Value: mapValue, @@ -342,8 +402,11 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt Option: in.Option, }, ) + if err != nil && in.Option.FailBreak { + return nil, err + } } - return dataMap + return dataMap, nil case reflect.Struct: var dataMap = make(map[string]interface{}) @@ -352,7 +415,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt // Value copy, in case of concurrent safety. for mapK, mapV := range v.MapStrAny() { if in.RecursiveOption { - dataMap[mapK] = c.doMapConvertForMapOrStructValue( + dataMap[mapK], err = c.doMapConvertForMapOrStructValue( doMapConvertForMapOrStructValueInput{ IsRoot: false, Value: mapV, @@ -361,12 +424,15 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt Option: in.Option, }, ) + if err != nil && in.Option.FailBreak { + return nil, err + } } else { dataMap[mapK] = mapV } } if len(dataMap) > 0 { - return dataMap + return dataMap, nil } } // Using reflect for converting. @@ -443,13 +509,18 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt case hasNoTag && rtField.Anonymous: // It means this attribute field has no tag. // Overwrite the attribute with sub-struct attribute fields. - anonymousValue := c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvInterface, - RecursiveType: in.RecursiveType, - RecursiveOption: true, - Option: in.Option, - }) + anonymousValue, err := c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvInterface, + RecursiveType: in.RecursiveType, + RecursiveOption: true, + Option: in.Option, + }, + ) + if err != nil && in.Option.FailBreak { + return nil, err + } if m, ok := anonymousValue.(map[string]interface{}); ok { for k, v := range m { dataMap[k] = v @@ -460,22 +531,32 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt // It means this attribute field has desired tag. case !hasNoTag && rtField.Anonymous: - dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvInterface, - RecursiveType: in.RecursiveType, - RecursiveOption: true, - Option: in.Option, - }) + dataMap[mapKey], err = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvInterface, + RecursiveType: in.RecursiveType, + RecursiveOption: true, + Option: in.Option, + }, + ) + if err != nil && in.Option.FailBreak { + return nil, err + } default: - dataMap[mapKey] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ - IsRoot: false, - Value: rvInterface, - RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, - Option: in.Option, - }) + dataMap[mapKey], err = c.doMapConvertForMapOrStructValue( + doMapConvertForMapOrStructValueInput{ + IsRoot: false, + Value: rvInterface, + RecursiveType: in.RecursiveType, + RecursiveOption: in.RecursiveType == recursiveTypeTrue, + Option: in.Option, + }, + ) + if err != nil && in.Option.FailBreak { + return nil, err + } } // The struct attribute is type of slice. @@ -487,7 +568,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt } array := make([]interface{}, length) for arrayIndex := 0; arrayIndex < length; arrayIndex++ { - array[arrayIndex] = c.doMapConvertForMapOrStructValue( + array[arrayIndex], err = c.doMapConvertForMapOrStructValue( doMapConvertForMapOrStructValueInput{ IsRoot: false, Value: rvAttrField.Index(arrayIndex).Interface(), @@ -496,6 +577,9 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt Option: in.Option, }, ) + if err != nil && in.Option.FailBreak { + return nil, err + } } dataMap[mapKey] = array case reflect.Map: @@ -504,7 +588,11 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt nestedMap = make(map[string]interface{}) ) for mapIter.Next() { - nestedMap[String(mapIter.Key().Interface())] = c.doMapConvertForMapOrStructValue( + s, err := c.String(mapIter.Key().Interface()) + if err != nil && in.Option.FailBreak { + return nil, err + } + nestedMap[s], err = c.doMapConvertForMapOrStructValue( doMapConvertForMapOrStructValueInput{ IsRoot: false, Value: mapIter.Value().Interface(), @@ -513,6 +601,9 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt Option: in.Option, }, ) + if err != nil && in.Option.FailBreak { + return nil, err + } } dataMap[mapKey] = nestedMap default: @@ -532,9 +623,9 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt } } if !in.MustMapReturn && len(dataMap) == 0 { - return in.Value + return in.Value, nil } - return dataMap + return dataMap, nil // The given value is type of slice. case reflect.Array, reflect.Slice: @@ -544,17 +635,20 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt } array := make([]interface{}, reflectValue.Len()) for i := 0; i < length; i++ { - array[i] = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ + array[i], err = c.doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{ IsRoot: false, Value: reflectValue.Index(i).Interface(), RecursiveType: in.RecursiveType, RecursiveOption: in.RecursiveType == recursiveTypeTrue, Option: in.Option, }) + if err != nil && in.Option.FailBreak { + return nil, err + } } - return array + return array, nil default: } - return in.Value + return in.Value, nil } From b52ba15e43ec4064bd53eb8f23c9268b3710444d Mon Sep 17 00:00:00 2001 From: John Guo Date: Sun, 2 Mar 2025 22:39:21 +0800 Subject: [PATCH 27/48] up --- util/gconv/gconv_converter_map.go | 56 +++++++++---------- util/gconv/gconv_converter_slice_any.go | 4 +- util/gconv/gconv_converter_slice_float.go | 68 +++++++++++------------ util/gconv/gconv_converter_slice_int.go | 48 ++++++++-------- util/gconv/gconv_converter_slice_str.go | 32 +++++------ util/gconv/gconv_converter_slice_uint.go | 48 ++++++++-------- util/gconv/gconv_map.go | 8 +-- 7 files changed, 132 insertions(+), 132 deletions(-) diff --git a/util/gconv/gconv_converter_map.go b/util/gconv/gconv_converter_map.go index c79a802bdba..02a08380e3b 100644 --- a/util/gconv/gconv_converter_map.go +++ b/util/gconv/gconv_converter_map.go @@ -30,9 +30,9 @@ type MapOption struct { // Tags specifies the converted map key name by struct tag name. Tags []string - // FailBreak specifies whether to break converting the next element + // BreakOnError specifies whether to break converting the next element // if one element conversion fails in map. - FailBreak bool + BreakOnError bool } // Map converts any variable `value` to map[string]any. If the parameter `value` is not a @@ -52,7 +52,7 @@ func (c *impConverter) MapStrStr(value any, option MapOption) (map[string]string return r, nil } m, err := c.Map(value, option) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } if len(m) > 0 { @@ -62,7 +62,7 @@ func (c *impConverter) MapStrStr(value any, option MapOption) (map[string]string ) for k, v := range m { s, err = c.String(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } vMap[k] = s @@ -127,7 +127,7 @@ func (c *impConverter) doMapConvert( recursiveOption.Tags = newTags for k, v := range r { s, err := c.String(k) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } dataMap[s], err = c.doMapConvertForMapOrStructValue( @@ -139,14 +139,14 @@ func (c *impConverter) doMapConvert( Option: recursiveOption, }, ) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } } case map[interface{}]string: for k, v := range r { s, err := c.String(k) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } dataMap[s] = v @@ -154,7 +154,7 @@ func (c *impConverter) doMapConvert( case map[interface{}]int: for k, v := range r { s, err := c.String(k) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } dataMap[s] = v @@ -162,7 +162,7 @@ func (c *impConverter) doMapConvert( case map[interface{}]uint: for k, v := range r { s, err := c.String(k) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } dataMap[s] = v @@ -170,7 +170,7 @@ func (c *impConverter) doMapConvert( case map[interface{}]float32: for k, v := range r { s, err := c.String(k) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } dataMap[s] = v @@ -178,7 +178,7 @@ func (c *impConverter) doMapConvert( case map[interface{}]float64: for k, v := range r { s, err := c.String(k) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } dataMap[s] = v @@ -222,7 +222,7 @@ func (c *impConverter) doMapConvert( Option: recursiveOption, }, ) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } } @@ -235,7 +235,7 @@ func (c *impConverter) doMapConvert( recursiveOption.Tags = newTags for k, v := range r { s, err := c.String(k) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } dataMap[s], err = c.doMapConvertForMapOrStructValue( @@ -247,14 +247,14 @@ func (c *impConverter) doMapConvert( Option: recursiveOption, }, ) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } } case map[int]string: for k, v := range r { s, err := c.String(k) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } dataMap[s] = v @@ -262,7 +262,7 @@ func (c *impConverter) doMapConvert( case map[uint]string: for k, v := range r { s, err := c.String(k) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } dataMap[s] = v @@ -291,7 +291,7 @@ func (c *impConverter) doMapConvert( length := reflectValue.Len() for i := 0; i < length; i += 2 { s, err := c.String(String(reflectValue.Index(i).Interface())) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } if i+1 < length { @@ -313,7 +313,7 @@ func (c *impConverter) doMapConvert( MustMapReturn: mustMapReturn, }, ) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } if m, ok := convertedValue.(map[string]interface{}); ok { @@ -390,7 +390,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt mapValue = mapKeyValue.Interface() } s, err := c.String(mapIter.Key().Interface()) - if err != nil && in.Option.FailBreak { + if err != nil && in.Option.BreakOnError { return nil, err } dataMap[s], err = c.doMapConvertForMapOrStructValue( @@ -402,7 +402,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt Option: in.Option, }, ) - if err != nil && in.Option.FailBreak { + if err != nil && in.Option.BreakOnError { return nil, err } } @@ -424,7 +424,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt Option: in.Option, }, ) - if err != nil && in.Option.FailBreak { + if err != nil && in.Option.BreakOnError { return nil, err } } else { @@ -518,7 +518,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt Option: in.Option, }, ) - if err != nil && in.Option.FailBreak { + if err != nil && in.Option.BreakOnError { return nil, err } if m, ok := anonymousValue.(map[string]interface{}); ok { @@ -540,7 +540,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt Option: in.Option, }, ) - if err != nil && in.Option.FailBreak { + if err != nil && in.Option.BreakOnError { return nil, err } @@ -554,7 +554,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt Option: in.Option, }, ) - if err != nil && in.Option.FailBreak { + if err != nil && in.Option.BreakOnError { return nil, err } } @@ -577,7 +577,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt Option: in.Option, }, ) - if err != nil && in.Option.FailBreak { + if err != nil && in.Option.BreakOnError { return nil, err } } @@ -589,7 +589,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt ) for mapIter.Next() { s, err := c.String(mapIter.Key().Interface()) - if err != nil && in.Option.FailBreak { + if err != nil && in.Option.BreakOnError { return nil, err } nestedMap[s], err = c.doMapConvertForMapOrStructValue( @@ -601,7 +601,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt Option: in.Option, }, ) - if err != nil && in.Option.FailBreak { + if err != nil && in.Option.BreakOnError { return nil, err } } @@ -642,7 +642,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt RecursiveOption: in.RecursiveType == recursiveTypeTrue, Option: in.Option, }) - if err != nil && in.Option.FailBreak { + if err != nil && in.Option.BreakOnError { return nil, err } } diff --git a/util/gconv/gconv_converter_slice_any.go b/util/gconv/gconv_converter_slice_any.go index d9d0c2a6246..45ede7cffa8 100644 --- a/util/gconv/gconv_converter_slice_any.go +++ b/util/gconv/gconv_converter_slice_any.go @@ -16,9 +16,9 @@ import ( ) type SliceOption struct { - // FailBreak specifies whether to break converting the next element + // BreakOnError specifies whether to break converting the next element // if one element conversion fails in slice. - FailBreak bool + BreakOnError bool } // SliceAny converts `any` to []any. diff --git a/util/gconv/gconv_converter_slice_float.go b/util/gconv/gconv_converter_slice_float.go index 201e927f76e..0bb93fd11b9 100644 --- a/util/gconv/gconv_converter_slice_float.go +++ b/util/gconv/gconv_converter_slice_float.go @@ -31,7 +31,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -40,7 +40,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -49,7 +49,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -58,7 +58,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -67,7 +67,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -76,7 +76,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -85,7 +85,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -99,7 +99,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -116,7 +116,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa } if utils.IsNumeric(value) { f, err = c.Float32(value) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []float32{f}, err @@ -125,7 +125,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -134,7 +134,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -143,7 +143,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -152,7 +152,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -163,7 +163,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -172,7 +172,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -197,7 +197,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa ) for i := 0; i < length; i++ { f, err = c.Float32(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } slice[i] = f @@ -209,7 +209,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa return []float32{}, err } f, err = c.Float32(any) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []float32{f}, err @@ -231,7 +231,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -240,7 +240,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -249,7 +249,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -258,7 +258,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -267,7 +267,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -276,7 +276,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -285,7 +285,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -299,7 +299,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -316,7 +316,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa } if utils.IsNumeric(value) { f, err = c.Float64(value) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []float64{f}, err @@ -325,7 +325,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -334,7 +334,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -343,7 +343,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -352,7 +352,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -361,7 +361,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -372,7 +372,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = f @@ -397,7 +397,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa ) for i := 0; i < length; i++ { f, err = c.Float64(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } slice[i] = f @@ -409,7 +409,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa return []float64{}, err } f, err = c.Float64(any) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []float64{f}, err diff --git a/util/gconv/gconv_converter_slice_int.go b/util/gconv/gconv_converter_slice_int.go index 4dcc6cc8d7d..437e36b5527 100644 --- a/util/gconv/gconv_converter_slice_int.go +++ b/util/gconv/gconv_converter_slice_int.go @@ -31,7 +31,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) { array = make([]int, len(value)) for k, v := range value { ii, err = c.Int(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ii @@ -85,7 +85,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) { } if utils.IsNumeric(value) { ii, err = c.Int(value) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []int{ii}, err @@ -118,7 +118,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) { array = make([]int, len(value)) for k, v := range value { ii, err = c.Int(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ii @@ -127,7 +127,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) { array = make([]int, len(value)) for k, v := range value { ii, err = c.Int(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ii @@ -136,7 +136,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) { array = make([]int, len(value)) for k, v := range value { ii, err = c.Int(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ii @@ -145,7 +145,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) { array = make([]int, len(value)) for k, v := range value { ii, err = c.Int(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ii @@ -170,7 +170,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) { ) for i := 0; i < length; i++ { ii, err = c.Int(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } slice[i] = ii @@ -182,7 +182,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) { return []int{}, err } ii, err = c.Int(any) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []int{ii}, err @@ -204,7 +204,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error) array = make([]int32, len(value)) for k, v := range value { ii, err = c.Int32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ii @@ -258,7 +258,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error) } if utils.IsNumeric(value) { ii, err = c.Int32(value) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []int32{ii}, err @@ -291,7 +291,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error) array = make([]int32, len(value)) for k, v := range value { ii, err = c.Int32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ii @@ -300,7 +300,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error) array = make([]int32, len(value)) for k, v := range value { ii, err = c.Int32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ii @@ -309,7 +309,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error) array = make([]int32, len(value)) for k, v := range value { ii, err = c.Int32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ii @@ -318,7 +318,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error) array = make([]int32, len(value)) for k, v := range value { ii, err = c.Int32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ii @@ -343,7 +343,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error) ) for i := 0; i < length; i++ { ii, err = c.Int32(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } slice[i] = ii @@ -355,7 +355,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error) return []int32{}, err } ii, err = c.Int32(any) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []int32{ii}, err @@ -377,7 +377,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error) array = make([]int64, len(value)) for k, v := range value { ii, err = c.Int64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ii @@ -431,7 +431,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error) } if utils.IsNumeric(value) { ii, err = c.Int64(value) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []int64{ii}, err @@ -464,7 +464,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error) array = make([]int64, len(value)) for k, v := range value { ii, err = c.Int64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ii @@ -473,7 +473,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error) array = make([]int64, len(value)) for k, v := range value { ii, err = c.Int64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ii @@ -482,7 +482,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error) array = make([]int64, len(value)) for k, v := range value { ii, err = c.Int64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ii @@ -491,7 +491,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error) array = make([]int64, len(value)) for k, v := range value { ii, err = c.Int64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ii @@ -516,7 +516,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error) ) for i := 0; i < length; i++ { ii, err = c.Int64(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } slice[i] = ii @@ -528,7 +528,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error) return []int64{}, err } ii, err = c.Int64(any) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []int64{ii}, err diff --git a/util/gconv/gconv_converter_slice_str.go b/util/gconv/gconv_converter_slice_str.go index 5f454b0eb18..ff8734e7da2 100644 --- a/util/gconv/gconv_converter_slice_str.go +++ b/util/gconv/gconv_converter_slice_str.go @@ -30,7 +30,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = s @@ -44,7 +44,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = s @@ -53,7 +53,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = s @@ -62,7 +62,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = s @@ -71,7 +71,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = s @@ -85,7 +85,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = s @@ -106,7 +106,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = s @@ -115,7 +115,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = s @@ -124,7 +124,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = s @@ -133,7 +133,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = s @@ -142,7 +142,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = s @@ -151,7 +151,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = s @@ -160,7 +160,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = s @@ -171,7 +171,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = s @@ -196,7 +196,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, ) for i := 0; i < length; i++ { s, err = c.String(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } slice[i] = s @@ -208,7 +208,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, return []string{}, err } s, err = c.String(any) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []string{s}, err diff --git a/util/gconv/gconv_converter_slice_uint.go b/util/gconv/gconv_converter_slice_uint.go index 925c163a615..b66e0aca2e7 100644 --- a/util/gconv/gconv_converter_slice_uint.go +++ b/util/gconv/gconv_converter_slice_uint.go @@ -31,7 +31,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e array = make([]uint, len(value)) for k, v := range value { ui, err = c.Uint(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ui @@ -80,7 +80,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e } if utils.IsNumeric(value) { ui, err = c.Uint(value) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []uint{ui}, err @@ -113,7 +113,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e array = make([]uint, len(value)) for k, v := range value { ui, err = c.Uint(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ui @@ -122,7 +122,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e array = make([]uint, len(value)) for k, v := range value { ui, err = c.Uint(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ui @@ -131,7 +131,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e array = make([]uint, len(value)) for k, v := range value { ui, err = c.Uint(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ui @@ -140,7 +140,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e array = make([]uint, len(value)) for k, v := range value { ui, err = c.Uint(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ui @@ -168,7 +168,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e ) for i := 0; i < length; i++ { ui, err = c.Uint(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } slice[i] = ui @@ -180,7 +180,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e return []uint{}, err } ui, err = c.Uint(any) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []uint{ui}, err @@ -202,7 +202,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3 array = make([]uint32, len(value)) for k, v := range value { ui, err = c.Uint32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ui @@ -254,7 +254,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3 } if utils.IsNumeric(value) { ui, err = c.Uint32(value) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []uint32{ui}, err @@ -284,7 +284,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3 array = make([]uint32, len(value)) for k, v := range value { ui, err = c.Uint32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ui @@ -293,7 +293,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3 array = make([]uint32, len(value)) for k, v := range value { ui, err = c.Uint32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ui @@ -302,7 +302,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3 array = make([]uint32, len(value)) for k, v := range value { ui, err = c.Uint32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ui @@ -311,7 +311,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3 array = make([]uint32, len(value)) for k, v := range value { ui, err = c.Uint32(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ui @@ -338,7 +338,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3 ) for i := 0; i < length; i++ { ui, err = c.Uint32(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } slice[i] = ui @@ -350,7 +350,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3 return []uint32{}, err } ui, err = c.Uint32(any) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []uint32{ui}, err @@ -372,7 +372,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6 array = make([]uint64, len(value)) for k, v := range value { ui, err = c.Uint64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ui @@ -424,7 +424,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6 } if utils.IsNumeric(value) { ui, err = c.Uint64(value) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []uint64{ui}, err @@ -454,7 +454,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6 array = make([]uint64, len(value)) for k, v := range value { ui, err = c.Uint64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ui @@ -463,7 +463,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6 array = make([]uint64, len(value)) for k, v := range value { ui, err = c.Uint64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ui @@ -472,7 +472,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6 array = make([]uint64, len(value)) for k, v := range value { ui, err = c.Uint64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ui @@ -481,7 +481,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6 array = make([]uint64, len(value)) for k, v := range value { ui, err = c.Uint64(v) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } array[k] = ui @@ -507,7 +507,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6 ) for i := 0; i < length; i++ { ui, err = c.Uint64(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } slice[i] = ui @@ -519,7 +519,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6 return []uint64{}, err } ui, err = c.Uint64(any) - if err != nil && option.FailBreak { + if err != nil && option.BreakOnError { return nil, err } return []uint64{ui}, err diff --git a/util/gconv/gconv_map.go b/util/gconv/gconv_map.go index 246129527a0..9c49f9e3139 100644 --- a/util/gconv/gconv_map.go +++ b/util/gconv/gconv_map.go @@ -30,10 +30,10 @@ func Map(value any, option ...MapOption) map[string]any { // Deprecated: used Map instead. func MapDeep(value any, tags ...string) map[string]any { result, _ := defaultConverter.Map(value, MapOption{ - Deep: true, - OmitEmpty: false, - Tags: tags, - FailBreak: false, + Deep: true, + OmitEmpty: false, + Tags: tags, + BreakOnError: false, }) return result } From d7a246c4c79a1f11d95dba67b785dfdbac9ae5ea Mon Sep 17 00:00:00 2001 From: John Guo Date: Sun, 2 Mar 2025 22:46:27 +0800 Subject: [PATCH 28/48] up --- util/gconv/gconv_converter.go | 3 --- util/gconv/gconv_converter_convert.go | 4 ++-- util/gconv/gconv_converter_maptomaps.go | 4 ++-- util/gconv/gconv_converter_slice_any.go | 1 + util/gconv/gconv_converter_slice_map.go | 8 ++++---- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/util/gconv/gconv_converter.go b/util/gconv/gconv_converter.go index 68fe71a14f8..86157c9c041 100644 --- a/util/gconv/gconv_converter.go +++ b/util/gconv/gconv_converter.go @@ -33,9 +33,6 @@ type Converter interface { Float32(any any) (float32, error) Float64(any any) (float64, error) - doMapConvert( - value any, recursive recursiveType, mustMapReturn bool, option ...MapOption, - ) map[string]any MapToMap(params any, pointer any, mapping ...map[string]string) (err error) MapToMaps(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) Rune(any any) (rune, error) diff --git a/util/gconv/gconv_converter_convert.go b/util/gconv/gconv_converter_convert.go index 74ca4660ff7..f6d30ec84c5 100644 --- a/util/gconv/gconv_converter_convert.go +++ b/util/gconv/gconv_converter_convert.go @@ -310,10 +310,10 @@ func (c *impConverter) doConvert(in doConvertInput) (convertedValue any, err err return &v, nil case "map[string]string": - return MapStrStr(in.FromValue), nil + return c.MapStrStr(in.FromValue, MapOption{}) case "map[string]interface {}": - return Map(in.FromValue, MapOption{}), nil + return c.Map(in.FromValue, MapOption{}) case "[]map[string]interface {}": return c.SliceMap(in.FromValue, SliceOption{}, MapOption{}) diff --git a/util/gconv/gconv_converter_maptomaps.go b/util/gconv/gconv_converter_maptomaps.go index 9783a4e6fae..1c5c266a7d6 100644 --- a/util/gconv/gconv_converter_maptomaps.go +++ b/util/gconv/gconv_converter_maptomaps.go @@ -103,13 +103,13 @@ func (c *impConverter) MapToMaps(params any, pointer any, paramKeyToAttrMap ...m var item reflect.Value if pointerElemType.Kind() == reflect.Ptr { item = reflect.New(pointerElemType.Elem()) - if err = MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap...); err != nil { + if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap...); err != nil { return err } pointerSlice.Index(i).Set(item) } else { item = reflect.New(pointerElemType) - if err = MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap...); err != nil { + if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap...); err != nil { return err } pointerSlice.Index(i).Set(item.Elem()) diff --git a/util/gconv/gconv_converter_slice_any.go b/util/gconv/gconv_converter_slice_any.go index 45ede7cffa8..93680534068 100644 --- a/util/gconv/gconv_converter_slice_any.go +++ b/util/gconv/gconv_converter_slice_any.go @@ -15,6 +15,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) +// SliceOption is the option for Slice type converting. type SliceOption struct { // BreakOnError specifies whether to break converting the next element // if one element conversion fails in slice. diff --git a/util/gconv/gconv_converter_slice_map.go b/util/gconv/gconv_converter_slice_map.go index 813833196f7..0bd5ecdfd5e 100644 --- a/util/gconv/gconv_converter_slice_map.go +++ b/util/gconv/gconv_converter_slice_map.go @@ -48,10 +48,10 @@ func (c *impConverter) SliceMap(value any, sliceOption SliceOption, mapOption Ma } list := make([]map[string]any, len(array)) for k, v := range array { - m := Map(v, mapOption) - //if err != nil { - // return nil, err - //} + m, err := c.Map(v, mapOption) + if err != nil && sliceOption.BreakOnError { + return nil, err + } list[k] = m } return list, nil From 1c1558b1f71aa04626252295d2e581be895c4331 Mon Sep 17 00:00:00 2001 From: John Guo Date: Sun, 2 Mar 2025 23:21:59 +0800 Subject: [PATCH 29/48] up --- util/gconv/gconv.go | 19 ++-- util/gconv/gconv_convert.go | 26 +---- util/gconv/gconv_map.go | 15 +-- util/gconv/gconv_scan.go | 6 +- .../converter/converter.go} | 20 +++- .../converter/converter_bool.go} | 2 +- .../converter/converter_builtin.go} | 2 +- .../converter/converter_bytes.go} | 2 +- .../converter/converter_convert.go} | 38 ++++++- .../converter/converter_float.go} | 2 +- .../converter/converter_int.go} | 4 +- .../converter/converter_map.go} | 42 +++----- .../converter/converter_maptomap.go} | 22 ++-- .../converter/converter_maptomaps.go} | 8 +- .../converter/converter_rune.go} | 2 +- .../converter/converter_scan.go} | 100 ++++++++++++------ .../converter/converter_slice_any.go} | 2 +- .../converter/converter_slice_float.go} | 2 +- .../converter/converter_slice_int.go} | 2 +- .../converter/converter_slice_map.go} | 2 +- .../converter/converter_slice_str.go} | 8 +- .../converter/converter_slice_uint.go} | 2 +- .../converter/converter_string.go} | 2 +- .../converter/converter_struct.go} | 16 ++- .../converter/converter_structs.go} | 7 +- .../converter/converter_time.go} | 2 +- .../converter/converter_uint.go} | 2 +- 27 files changed, 215 insertions(+), 142 deletions(-) rename util/gconv/{gconv_converter.go => internal/converter/converter.go} (94%) rename util/gconv/{gconv_converter_bool.go => internal/converter/converter_bool.go} (99%) rename util/gconv/{gconv_converter_builtin.go => internal/converter/converter_builtin.go} (99%) rename util/gconv/{gconv_converter_bytes.go => internal/converter/converter_bytes.go} (98%) rename util/gconv/{gconv_converter_convert.go => internal/converter/converter_convert.go} (90%) rename util/gconv/{gconv_converter_float.go => internal/converter/converter_float.go} (99%) rename util/gconv/{gconv_converter_int.go => internal/converter/converter_int.go} (98%) rename util/gconv/{gconv_converter_map.go => internal/converter/converter_map.go} (94%) rename util/gconv/{gconv_converter_maptomap.go => internal/converter/converter_maptomap.go} (88%) rename util/gconv/{gconv_converter_maptomaps.go => internal/converter/converter_maptomaps.go} (95%) rename util/gconv/{gconv_converter_rune.go => internal/converter/converter_rune.go} (97%) rename util/gconv/{gconv_converter_scan.go => internal/converter/converter_scan.go} (82%) rename util/gconv/{gconv_converter_slice_any.go => internal/converter/converter_slice_any.go} (99%) rename util/gconv/{gconv_converter_slice_float.go => internal/converter/converter_slice_float.go} (99%) rename util/gconv/{gconv_converter_slice_int.go => internal/converter/converter_slice_int.go} (99%) rename util/gconv/{gconv_converter_slice_map.go => internal/converter/converter_slice_map.go} (98%) rename util/gconv/{gconv_converter_slice_str.go => internal/converter/converter_slice_str.go} (97%) rename util/gconv/{gconv_converter_slice_uint.go => internal/converter/converter_slice_uint.go} (99%) rename util/gconv/{gconv_converter_string.go => internal/converter/converter_string.go} (99%) rename util/gconv/{gconv_converter_struct.go => internal/converter/converter_struct.go} (98%) rename util/gconv/{gconv_converter_structs.go => internal/converter/converter_structs.go} (96%) rename util/gconv/{gconv_converter_time.go => internal/converter/converter_time.go} (99%) rename util/gconv/{gconv_converter_uint.go => internal/converter/converter_uint.go} (99%) diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index be49d479a4a..5ec146f2a70 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -10,21 +10,16 @@ package gconv import ( + "github.com/gogf/gf/v2/util/gconv/internal/converter" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" "github.com/gogf/gf/v2/util/gconv/internal/structcache" ) -type AnyConvertFunc = structcache.AnyConvertFunc - -var ( - // Empty strings. - emptyStringMap = map[string]struct{}{ - "": {}, - "0": {}, - "no": {}, - "off": {}, - "false": {}, - } +type ( + AnyConvertFunc = structcache.AnyConvertFunc + MapOption = converter.MapOption + ScanOption = converter.ScanOption + SliceOption = converter.SliceOption ) // IUnmarshalValue is the interface for custom defined types customizing value assignment. @@ -33,7 +28,7 @@ type IUnmarshalValue = localinterface.IUnmarshalValue var ( // defaultConverter is the default management object converting. - defaultConverter = NewConverter() + defaultConverter = converter.NewConverter() ) // RegisterConverter registers custom converter. diff --git a/util/gconv/gconv_convert.go b/util/gconv/gconv_convert.go index 53db02f1cd9..134651aca0e 100644 --- a/util/gconv/gconv_convert.go +++ b/util/gconv/gconv_convert.go @@ -6,23 +6,12 @@ package gconv -import ( - "reflect" -) - // Convert converts the variable `fromValue` to the type `toTypeName`, the type `toTypeName` is specified by string. // // The optional parameter `extraParams` is used for additional necessary parameter for this conversion. // It supports common basic types conversion as its conversion based on type name string. func Convert(fromValue any, toTypeName string, extraParams ...any) any { - result, _ := defaultConverter.doConvert( - doConvertInput{ - FromValue: fromValue, - ToTypeName: toTypeName, - ReferValue: nil, - Extra: extraParams, - }, - ) + result, _ := defaultConverter.ConvertWithTypeName(fromValue, toTypeName, extraParams...) return result } @@ -31,17 +20,6 @@ func Convert(fromValue any, toTypeName string, extraParams ...any) any { // The optional parameter `extraParams` is used for additional necessary parameter for this conversion. // It supports common basic types conversion as its conversion based on type name string. func ConvertWithRefer(fromValue any, referValue any, extraParams ...any) any { - var referValueRf reflect.Value - if v, ok := referValue.(reflect.Value); ok { - referValueRf = v - } else { - referValueRf = reflect.ValueOf(referValue) - } - result, _ := defaultConverter.doConvert(doConvertInput{ - FromValue: fromValue, - ToTypeName: referValueRf.Type().String(), - ReferValue: referValue, - Extra: extraParams, - }) + result, _ := defaultConverter.ConvertWithRefer(fromValue, referValue, extraParams...) return result } diff --git a/util/gconv/gconv_map.go b/util/gconv/gconv_map.go index 9c49f9e3139..1aede25b5e8 100644 --- a/util/gconv/gconv_map.go +++ b/util/gconv/gconv_map.go @@ -6,13 +6,6 @@ package gconv -type recursiveType string - -const ( - recursiveTypeAuto recursiveType = "auto" - recursiveTypeTrue recursiveType = "true" -) - // Map converts any variable `value` to map[string]any. If the parameter `value` is not a // map/struct/*struct type, then the conversion will fail and returns nil. // @@ -62,3 +55,11 @@ func MapStrStrDeep(value any, tags ...string) map[string]string { } return nil } + +func getUsedMapOption(option ...MapOption) MapOption { + var usedOption MapOption + if len(option) > 0 { + usedOption = option[0] + } + return usedOption +} diff --git a/util/gconv/gconv_scan.go b/util/gconv/gconv_scan.go index 806438668af..8edbc0aca46 100644 --- a/util/gconv/gconv_scan.go +++ b/util/gconv/gconv_scan.go @@ -17,5 +17,9 @@ package gconv // The `paramKeyToAttrMap` parameter is used for mapping between attribute names and parameter keys. // TODO: change `paramKeyToAttrMap` to `ScanOption` to be more scalable; add `DeepCopy` option for `ScanOption`. func Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) { - return defaultConverter.Scan(srcValue, dstPointer, paramKeyToAttrMap...) + option := ScanOption{} + if len(paramKeyToAttrMap) > 0 { + option.ParamKeyToAttrMap = paramKeyToAttrMap[0] + } + return defaultConverter.Scan(srcValue, dstPointer, option) } diff --git a/util/gconv/gconv_converter.go b/util/gconv/internal/converter/converter.go similarity index 94% rename from util/gconv/gconv_converter.go rename to util/gconv/internal/converter/converter.go index 86157c9c041..a9e7269521c 100644 --- a/util/gconv/gconv_converter.go +++ b/util/gconv/internal/converter/converter.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" @@ -16,6 +16,15 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/structcache" ) +type AnyConvertFunc = structcache.AnyConvertFunc + +type RecursiveType string + +const ( + RecursiveTypeAuto RecursiveType = "auto" + RecursiveTypeTrue RecursiveType = "true" +) + type ( converterInType = reflect.Type converterOutType = reflect.Type @@ -66,6 +75,15 @@ type impConverter struct { } var ( + // Empty strings. + emptyStringMap = map[string]struct{}{ + "": {}, + "0": {}, + "no": {}, + "off": {}, + "false": {}, + } + intType = reflect.TypeOf(0) int8Type = reflect.TypeOf(int8(0)) int16Type = reflect.TypeOf(int16(0)) diff --git a/util/gconv/gconv_converter_bool.go b/util/gconv/internal/converter/converter_bool.go similarity index 99% rename from util/gconv/gconv_converter_bool.go rename to util/gconv/internal/converter/converter_bool.go index 5b080d9df92..d9e88c41ecd 100644 --- a/util/gconv/gconv_converter_bool.go +++ b/util/gconv/internal/converter/converter_bool.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" diff --git a/util/gconv/gconv_converter_builtin.go b/util/gconv/internal/converter/converter_builtin.go similarity index 99% rename from util/gconv/gconv_converter_builtin.go rename to util/gconv/internal/converter/converter_builtin.go index 2d8a3aee101..b8a8e0e4746 100644 --- a/util/gconv/gconv_converter_builtin.go +++ b/util/gconv/internal/converter/converter_builtin.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" diff --git a/util/gconv/gconv_converter_bytes.go b/util/gconv/internal/converter/converter_bytes.go similarity index 98% rename from util/gconv/gconv_converter_bytes.go rename to util/gconv/internal/converter/converter_bytes.go index 437f9078021..dfec4eef0c4 100644 --- a/util/gconv/gconv_converter_bytes.go +++ b/util/gconv/internal/converter/converter_bytes.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "math" diff --git a/util/gconv/gconv_converter_convert.go b/util/gconv/internal/converter/converter_convert.go similarity index 90% rename from util/gconv/gconv_converter_convert.go rename to util/gconv/internal/converter/converter_convert.go index f6d30ec84c5..68195d0f689 100644 --- a/util/gconv/gconv_converter_convert.go +++ b/util/gconv/internal/converter/converter_convert.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" @@ -14,6 +14,40 @@ import ( "github.com/gogf/gf/v2/os/gtime" ) +// ConvertWithTypeName converts the variable `fromValue` to the type `toTypeName`, the type `toTypeName` is specified by string. +// +// The optional parameter `extraParams` is used for additional necessary parameter for this conversion. +// It supports common basic types conversion as its conversion based on type name string. +func (c *impConverter) ConvertWithTypeName(fromValue any, toTypeName string, extraParams ...any) (any, error) { + return c.doConvert( + doConvertInput{ + FromValue: fromValue, + ToTypeName: toTypeName, + ReferValue: nil, + Extra: extraParams, + }, + ) +} + +// ConvertWithRefer converts the variable `fromValue` to the type referred by value `referValue`. +// +// The optional parameter `extraParams` is used for additional necessary parameter for this conversion. +// It supports common basic types conversion as its conversion based on type name string. +func (c *impConverter) ConvertWithRefer(fromValue, referValue any, extraParams ...any) (any, error) { + var referValueRf reflect.Value + if v, ok := referValue.(reflect.Value); ok { + referValueRf = v + } else { + referValueRf = reflect.ValueOf(referValue) + } + return c.doConvert(doConvertInput{ + FromValue: fromValue, + ToTypeName: referValueRf.Type().String(), + ReferValue: referValue, + Extra: extraParams, + }) +} + type doConvertInput struct { FromValue any // Value that is converted from. ToTypeName string // Target value type name in string. @@ -389,7 +423,7 @@ func (c *impConverter) doConvert(in doConvertInput) (convertedValue any, err err case reflect.Map: var targetValue = reflect.New(referReflectValue.Type()).Elem() - if err = c.MapToMap(in.FromValue, targetValue); err == nil { + if err = c.MapToMap(in.FromValue, targetValue, nil, MapOption{}); err == nil { in.alreadySetToReferValue = true } return targetValue.Interface(), nil diff --git a/util/gconv/gconv_converter_float.go b/util/gconv/internal/converter/converter_float.go similarity index 99% rename from util/gconv/gconv_converter_float.go rename to util/gconv/internal/converter/converter_float.go index d9e5520d6c0..2e9968120b7 100644 --- a/util/gconv/gconv_converter_float.go +++ b/util/gconv/internal/converter/converter_float.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" diff --git a/util/gconv/gconv_converter_int.go b/util/gconv/internal/converter/converter_int.go similarity index 98% rename from util/gconv/gconv_converter_int.go rename to util/gconv/internal/converter/converter_int.go index fb742471c57..b3999734a52 100644 --- a/util/gconv/gconv_converter_int.go +++ b/util/gconv/internal/converter/converter_int.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "math" @@ -44,7 +44,7 @@ func (c *impConverter) Int16(any any) (int16, error) { if v, ok := any.(int16); ok { return v, nil } - v, err := defaultConverter.Int64(any) + v, err := c.Int64(any) if err != nil { return 0, err } diff --git a/util/gconv/gconv_converter_map.go b/util/gconv/internal/converter/converter_map.go similarity index 94% rename from util/gconv/gconv_converter_map.go rename to util/gconv/internal/converter/converter_map.go index 02a08380e3b..e0dfe0cc3c3 100644 --- a/util/gconv/gconv_converter_map.go +++ b/util/gconv/internal/converter/converter_map.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" @@ -42,7 +42,7 @@ type MapOption struct { // priorityTagAndFieldName that will be detected, otherwise it detects the priorityTagAndFieldName in order of: // gconv, json, field name. func (c *impConverter) Map(value any, option MapOption) (map[string]any, error) { - return c.doMapConvert(value, recursiveTypeAuto, false, option) + return c.doMapConvert(value, RecursiveTypeAuto, false, option) } // MapStrStr converts `value` to map[string]string. @@ -77,7 +77,7 @@ func (c *impConverter) MapStrStr(value any, option MapOption) (map[string]string // // TODO completely implement the recursive converting for all types, especially the map. func (c *impConverter) doMapConvert( - value any, recursive recursiveType, mustMapReturn bool, option MapOption, + value any, recursive RecursiveType, mustMapReturn bool, option MapOption, ) (map[string]any, error) { if value == nil { return nil, nil @@ -91,7 +91,7 @@ func (c *impConverter) doMapConvert( newTags = gtag.StructTagPriority ) if option.Deep { - recursive = recursiveTypeTrue + recursive = RecursiveTypeTrue } switch len(option.Tags) { case 0: @@ -135,7 +135,7 @@ func (c *impConverter) doMapConvert( IsRoot: false, Value: v, RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, + RecursiveOption: recursive == RecursiveTypeTrue, Option: recursiveOption, }, ) @@ -208,7 +208,7 @@ func (c *impConverter) doMapConvert( dataMap[k] = v } case map[string]interface{}: - if recursive == recursiveTypeTrue { + if recursive == RecursiveTypeTrue { recursiveOption := option recursiveOption.Tags = newTags // A copy of current map. @@ -218,7 +218,7 @@ func (c *impConverter) doMapConvert( IsRoot: false, Value: v, RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, + RecursiveOption: recursive == RecursiveTypeTrue, Option: recursiveOption, }, ) @@ -243,7 +243,7 @@ func (c *impConverter) doMapConvert( IsRoot: false, Value: v, RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, + RecursiveOption: recursive == RecursiveTypeTrue, Option: recursiveOption, }, ) @@ -290,7 +290,7 @@ func (c *impConverter) doMapConvert( case reflect.Slice, reflect.Array: length := reflectValue.Len() for i := 0; i < length; i += 2 { - s, err := c.String(String(reflectValue.Index(i).Interface())) + s, err := c.String(reflectValue.Index(i).Interface()) if err != nil && option.BreakOnError { return nil, err } @@ -308,7 +308,7 @@ func (c *impConverter) doMapConvert( IsRoot: true, Value: value, RecursiveType: recursive, - RecursiveOption: recursive == recursiveTypeTrue, + RecursiveOption: recursive == RecursiveTypeTrue, Option: recursiveOption, MustMapReturn: mustMapReturn, }, @@ -327,18 +327,10 @@ func (c *impConverter) doMapConvert( return dataMap, nil } -func getUsedMapOption(option ...MapOption) MapOption { - var usedOption MapOption - if len(option) > 0 { - usedOption = option[0] - } - return usedOption -} - type doMapConvertForMapOrStructValueInput struct { IsRoot bool // It returns directly if it is not root and with no recursive converting. Value interface{} // Current operation value. - RecursiveType recursiveType // The type from top function entry. + RecursiveType RecursiveType // The type from top function entry. RecursiveOption bool // Whether convert recursively for `current` operation. Option MapOption // Map converting option. MustMapReturn bool // Must return map instead of Value when empty. @@ -398,7 +390,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt IsRoot: false, Value: mapValue, RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, + RecursiveOption: in.RecursiveType == RecursiveTypeTrue, Option: in.Option, }, ) @@ -420,7 +412,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt IsRoot: false, Value: mapV, RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, + RecursiveOption: in.RecursiveType == RecursiveTypeTrue, Option: in.Option, }, ) @@ -550,7 +542,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt IsRoot: false, Value: rvInterface, RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, + RecursiveOption: in.RecursiveType == RecursiveTypeTrue, Option: in.Option, }, ) @@ -573,7 +565,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt IsRoot: false, Value: rvAttrField.Index(arrayIndex).Interface(), RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, + RecursiveOption: in.RecursiveType == RecursiveTypeTrue, Option: in.Option, }, ) @@ -597,7 +589,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt IsRoot: false, Value: mapIter.Value().Interface(), RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, + RecursiveOption: in.RecursiveType == RecursiveTypeTrue, Option: in.Option, }, ) @@ -639,7 +631,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt IsRoot: false, Value: reflectValue.Index(i).Interface(), RecursiveType: in.RecursiveType, - RecursiveOption: in.RecursiveType == recursiveTypeTrue, + RecursiveOption: in.RecursiveType == RecursiveTypeTrue, Option: in.Option, }) if err != nil && in.Option.BreakOnError { diff --git a/util/gconv/gconv_converter_maptomap.go b/util/gconv/internal/converter/converter_maptomap.go similarity index 88% rename from util/gconv/gconv_converter_maptomap.go rename to util/gconv/internal/converter/converter_maptomap.go index 5026ce2239c..51a8be2cf21 100644 --- a/util/gconv/gconv_converter_maptomap.go +++ b/util/gconv/internal/converter/converter_maptomap.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" @@ -23,15 +23,13 @@ import ( // // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes // sense only if the items of original map `params` is type struct. -func (c *impConverter) MapToMap(params any, pointer any, mapping ...map[string]string) (err error) { +func (c *impConverter) MapToMap( + params, pointer any, mapping map[string]string, option MapOption, +) (err error) { var ( - paramsRv reflect.Value - paramsKind reflect.Kind - keyToAttributeNameMapping map[string]string + paramsRv reflect.Value + paramsKind reflect.Kind ) - if len(mapping) > 0 { - keyToAttributeNameMapping = mapping[0] - } if v, ok := params.(reflect.Value); ok { paramsRv = v } else { @@ -43,7 +41,11 @@ func (c *impConverter) MapToMap(params any, pointer any, mapping ...map[string]s paramsKind = paramsRv.Kind() } if paramsKind != reflect.Map { - return c.MapToMap(Map(params), pointer, mapping...) + m, err := c.Map(params, option) + if err != nil { + return err + } + return c.MapToMap(m, pointer, mapping, option) } // Empty params map, no need continue. if paramsRv.Len() == 0 { @@ -93,7 +95,7 @@ func (c *impConverter) MapToMap(params any, pointer any, mapping ...map[string]s switch pointerValueKind { case reflect.Map, reflect.Struct: if err = c.Struct( - paramsRv.MapIndex(key).Interface(), mapValue, keyToAttributeNameMapping, "", + paramsRv.MapIndex(key).Interface(), mapValue, mapping, "", ); err != nil { return err } diff --git a/util/gconv/gconv_converter_maptomaps.go b/util/gconv/internal/converter/converter_maptomaps.go similarity index 95% rename from util/gconv/gconv_converter_maptomaps.go rename to util/gconv/internal/converter/converter_maptomaps.go index 1c5c266a7d6..3a842585f74 100644 --- a/util/gconv/gconv_converter_maptomaps.go +++ b/util/gconv/internal/converter/converter_maptomaps.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" @@ -21,7 +21,7 @@ import ( // // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes // sense only if the item of `params` is type struct. -func (c *impConverter) MapToMaps(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) { +func (c *impConverter) MapToMaps(params any, pointer any, paramKeyToAttrMap map[string]string) (err error) { // Params and its element type check. var ( paramsRv reflect.Value @@ -103,13 +103,13 @@ func (c *impConverter) MapToMaps(params any, pointer any, paramKeyToAttrMap ...m var item reflect.Value if pointerElemType.Kind() == reflect.Ptr { item = reflect.New(pointerElemType.Elem()) - if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap...); err != nil { + if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, MapOption{}); err != nil { return err } pointerSlice.Index(i).Set(item) } else { item = reflect.New(pointerElemType) - if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap...); err != nil { + if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, MapOption{}); err != nil { return err } pointerSlice.Index(i).Set(item.Elem()) diff --git a/util/gconv/gconv_converter_rune.go b/util/gconv/internal/converter/converter_rune.go similarity index 97% rename from util/gconv/gconv_converter_rune.go rename to util/gconv/internal/converter/converter_rune.go index 0a6c5fdcaad..301687d02d6 100644 --- a/util/gconv/gconv_converter_rune.go +++ b/util/gconv/internal/converter/converter_rune.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter func (c *impConverter) Rune(any any) (rune, error) { if v, ok := any.(rune); ok { diff --git a/util/gconv/gconv_converter_scan.go b/util/gconv/internal/converter/converter_scan.go similarity index 82% rename from util/gconv/gconv_converter_scan.go rename to util/gconv/internal/converter/converter_scan.go index 344e18f25eb..15b207f0372 100644 --- a/util/gconv/gconv_converter_scan.go +++ b/util/gconv/internal/converter/converter_scan.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" @@ -15,7 +15,12 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *impConverter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) { +type ScanOption struct { + ParamKeyToAttrMap map[string]string + BreakOnError bool +} + +func (c *impConverter) Scan(srcValue any, dstPointer any, option ScanOption) (err error) { // Check if srcValue is nil, in which case no conversion is needed if srcValue == nil { return nil @@ -79,12 +84,12 @@ func (c *impConverter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...m // Create a new value for the pointer dereference nextLevelPtr := reflect.New(dstPointerReflectValueElem.Type().Elem()) // Recursively scan into the dereferenced pointer - if err = Scan(srcValueReflectValue, nextLevelPtr, paramKeyToAttrMap...); err == nil { + if err = c.Scan(srcValueReflectValue, nextLevelPtr, option); err == nil { dstPointerReflectValueElem.Set(nextLevelPtr) } return } - return Scan(srcValueReflectValue, dstPointerReflectValueElem, paramKeyToAttrMap...) + return c.Scan(srcValueReflectValue, dstPointerReflectValueElem, option) } // Check if srcValue and dstPointer are the same type, in which case direct assignment can be performed @@ -95,28 +100,43 @@ func (c *impConverter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...m // Handle different destination types switch dstPointerReflectValueElemKind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - // Convert to int type - dstPointerReflectValueElem.SetInt(Int64(srcValue)) + v, err := c.Int64(srcValue) + if err != nil && option.BreakOnError { + return err + } + dstPointerReflectValueElem.SetInt(v) return nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - // Convert to uint type - dstPointerReflectValueElem.SetUint(Uint64(srcValue)) + v, err := c.Uint64(srcValue) + if err != nil && option.BreakOnError { + return err + } + dstPointerReflectValueElem.SetUint(v) return nil case reflect.Float32, reflect.Float64: - // Convert to float type - dstPointerReflectValueElem.SetFloat(Float64(srcValue)) + v, err := c.Float64(srcValue) + if err != nil && option.BreakOnError { + return err + } + dstPointerReflectValueElem.SetFloat(v) return nil case reflect.String: - // Convert to string type - dstPointerReflectValueElem.SetString(String(srcValue)) + v, err := c.String(srcValue) + if err != nil && option.BreakOnError { + return err + } + dstPointerReflectValueElem.SetString(v) return nil case reflect.Bool: - // Convert to bool type - dstPointerReflectValueElem.SetBool(Bool(srcValue)) + v, err := c.Bool(srcValue) + if err != nil && option.BreakOnError { + return err + } + dstPointerReflectValueElem.SetBool(v) return nil case reflect.Slice: @@ -132,7 +152,7 @@ func (c *impConverter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...m } // Special handling for struct or map slice elements if dstElemKind == reflect.Struct || dstElemKind == reflect.Map { - return c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...) + return c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, option) } // Handle basic type slice conversions var srcValueReflectValueKind = srcValueReflectValue.Kind() @@ -145,29 +165,49 @@ func (c *impConverter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...m srcElem := srcValueReflectValue.Index(i).Interface() switch dstElemType.Kind() { case reflect.String: - newSlice.Index(i).SetString(String(srcElem)) + v, err := c.String(srcElem) + if err != nil && option.BreakOnError { + return err + } + newSlice.Index(i).SetString(v) case reflect.Int: - newSlice.Index(i).SetInt(Int64(srcElem)) + v, err := c.Int64(srcElem) + if err != nil && option.BreakOnError { + return err + } + newSlice.Index(i).SetInt(v) case reflect.Int64: - newSlice.Index(i).SetInt(Int64(srcElem)) + v, err := c.Int64(srcElem) + if err != nil && option.BreakOnError { + return err + } + newSlice.Index(i).SetInt(v) case reflect.Float64: - newSlice.Index(i).SetFloat(Float64(srcElem)) + v, err := c.Float64(srcElem) + if err != nil && option.BreakOnError { + return err + } + newSlice.Index(i).SetFloat(v) case reflect.Bool: - newSlice.Index(i).SetBool(Bool(srcElem)) + v, err := c.Bool(srcElem) + if err != nil && option.BreakOnError { + return err + } + newSlice.Index(i).SetBool(v) default: - return Scan( - srcElem, newSlice.Index(i).Addr().Interface(), paramKeyToAttrMap..., + return c.Scan( + srcElem, newSlice.Index(i).Addr().Interface(), option, ) } } dstPointerReflectValueElem.Set(newSlice) return nil } - return c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...) + return c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, option) default: // Handle complex types (structs, maps, etc.) - return c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, paramKeyToAttrMap...) + return c.doScanForComplicatedTypes(srcValue, dstPointer, dstPointerReflectType, option) } } @@ -185,7 +225,7 @@ func (c *impConverter) Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...m func (c *impConverter) doScanForComplicatedTypes( srcValue, dstPointer any, dstPointerReflectType reflect.Type, - paramKeyToAttrMap ...map[string]string, + option ScanOption, ) error { // Try JSON conversion first ok, err := c.doConvertWithJsonCheck(srcValue, dstPointer) @@ -200,17 +240,13 @@ func (c *impConverter) doScanForComplicatedTypes( var ( dstPointerReflectTypeElem = dstPointerReflectType.Elem() dstPointerReflectTypeElemKind = dstPointerReflectTypeElem.Kind() - keyToAttributeNameMapping map[string]string + keyToAttributeNameMapping = option.ParamKeyToAttrMap ) - if len(paramKeyToAttrMap) > 0 { - keyToAttributeNameMapping = paramKeyToAttrMap[0] - } - // Handle different destination types switch dstPointerReflectTypeElemKind { case reflect.Map: // Convert map to map - return c.MapToMap(srcValue, dstPointer, paramKeyToAttrMap...) + return c.MapToMap(srcValue, dstPointer, keyToAttributeNameMapping, MapOption{}) case reflect.Array, reflect.Slice: var ( @@ -224,7 +260,7 @@ func (c *impConverter) doScanForComplicatedTypes( } if sliceElemKind == reflect.Map { // Convert to slice of maps - return c.MapToMaps(srcValue, dstPointer, paramKeyToAttrMap...) + return c.MapToMaps(srcValue, dstPointer, keyToAttributeNameMapping) } // Convert to slice of structs return c.Structs(srcValue, dstPointer, keyToAttributeNameMapping, "") diff --git a/util/gconv/gconv_converter_slice_any.go b/util/gconv/internal/converter/converter_slice_any.go similarity index 99% rename from util/gconv/gconv_converter_slice_any.go rename to util/gconv/internal/converter/converter_slice_any.go index 93680534068..c020d5ad63b 100644 --- a/util/gconv/gconv_converter_slice_any.go +++ b/util/gconv/internal/converter/converter_slice_any.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" diff --git a/util/gconv/gconv_converter_slice_float.go b/util/gconv/internal/converter/converter_slice_float.go similarity index 99% rename from util/gconv/gconv_converter_slice_float.go rename to util/gconv/internal/converter/converter_slice_float.go index 0bb93fd11b9..85f1e0071c0 100644 --- a/util/gconv/gconv_converter_slice_float.go +++ b/util/gconv/internal/converter/converter_slice_float.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" diff --git a/util/gconv/gconv_converter_slice_int.go b/util/gconv/internal/converter/converter_slice_int.go similarity index 99% rename from util/gconv/gconv_converter_slice_int.go rename to util/gconv/internal/converter/converter_slice_int.go index 437e36b5527..1c05a532769 100644 --- a/util/gconv/gconv_converter_slice_int.go +++ b/util/gconv/internal/converter/converter_slice_int.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" diff --git a/util/gconv/gconv_converter_slice_map.go b/util/gconv/internal/converter/converter_slice_map.go similarity index 98% rename from util/gconv/gconv_converter_slice_map.go rename to util/gconv/internal/converter/converter_slice_map.go index 0bd5ecdfd5e..6e040ea0644 100644 --- a/util/gconv/gconv_converter_slice_map.go +++ b/util/gconv/internal/converter/converter_slice_map.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import "github.com/gogf/gf/v2/internal/json" diff --git a/util/gconv/gconv_converter_slice_str.go b/util/gconv/internal/converter/converter_slice_str.go similarity index 97% rename from util/gconv/gconv_converter_slice_str.go rename to util/gconv/internal/converter/converter_slice_str.go index ff8734e7da2..a62658ddada 100644 --- a/util/gconv/gconv_converter_slice_str.go +++ b/util/gconv/internal/converter/converter_slice_str.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" @@ -38,7 +38,11 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, case []int8: array = make([]string, len(value)) for k, v := range value { - array[k] = String(v) + s, err = c.String(v) + if err != nil && option.BreakOnError { + return nil, err + } + array[k] = s } case []int16: array = make([]string, len(value)) diff --git a/util/gconv/gconv_converter_slice_uint.go b/util/gconv/internal/converter/converter_slice_uint.go similarity index 99% rename from util/gconv/gconv_converter_slice_uint.go rename to util/gconv/internal/converter/converter_slice_uint.go index b66e0aca2e7..9e44b7428a5 100644 --- a/util/gconv/gconv_converter_slice_uint.go +++ b/util/gconv/internal/converter/converter_slice_uint.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" diff --git a/util/gconv/gconv_converter_string.go b/util/gconv/internal/converter/converter_string.go similarity index 99% rename from util/gconv/gconv_converter_string.go rename to util/gconv/internal/converter/converter_string.go index dd38ac11904..e3415abd765 100644 --- a/util/gconv/gconv_converter_string.go +++ b/util/gconv/internal/converter/converter_string.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "fmt" diff --git a/util/gconv/gconv_converter_struct.go b/util/gconv/internal/converter/converter_struct.go similarity index 98% rename from util/gconv/gconv_converter_struct.go rename to util/gconv/internal/converter/converter_struct.go index bd38209d895..5b6fdb94e77 100644 --- a/util/gconv/gconv_converter_struct.go +++ b/util/gconv/internal/converter/converter_struct.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" @@ -133,7 +133,7 @@ func (c *impConverter) Struct( if !ok { // paramsMap is the map[string]any type variable for params. // DO NOT use MapDeep here. - paramsMap, err = c.doMapConvert(paramsInterface, recursiveTypeAuto, true, MapOption{}) + paramsMap, err = c.doMapConvert(paramsInterface, RecursiveTypeAuto, true, MapOption{}) if err != nil { return err } @@ -470,7 +470,7 @@ func (c *impConverter) bindVarToReflectValue( // Converting using reflection by kind. switch kind { case reflect.Map: - return c.MapToMap(value, structFieldValue, paramKeyToAttrMap) + return c.MapToMap(value, structFieldValue, paramKeyToAttrMap, MapOption{}) case reflect.Struct: // Recursively converting for struct attribute. @@ -512,13 +512,16 @@ func (c *impConverter) bindVarToReflectValue( } } if !converted { - c.doConvertWithReflectValueSet( + err = c.doConvertWithReflectValueSet( elem, doConvertInput{ FromValue: reflectValue.Index(i).Interface(), ToTypeName: elemTypeName, ReferValue: elem, }, ) + if err != nil { + return err + } } if elemType.Kind() == reflect.Ptr { // Before it sets the `elem` to array, do pointer converting if necessary. @@ -566,13 +569,16 @@ func (c *impConverter) bindVarToReflectValue( } } if !converted { - c.doConvertWithReflectValueSet( + err = c.doConvertWithReflectValueSet( elem, doConvertInput{ FromValue: value, ToTypeName: elemTypeName, ReferValue: elem, }, ) + if err != nil { + return err + } } if elemType.Kind() == reflect.Ptr { // Before it sets the `elem` to array, do pointer converting if necessary. diff --git a/util/gconv/gconv_converter_structs.go b/util/gconv/internal/converter/converter_structs.go similarity index 96% rename from util/gconv/gconv_converter_structs.go rename to util/gconv/internal/converter/converter_structs.go index dc722385dce..5f003d7ef31 100644 --- a/util/gconv/gconv_converter_structs.go +++ b/util/gconv/internal/converter/converter_structs.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "reflect" @@ -62,7 +62,10 @@ func (c *impConverter) Structs( paramsList[i] = paramsRv.Index(i).Interface() } default: - var paramsMaps = Maps(params) + paramsMaps, err := c.SliceMap(params, SliceOption{}, MapOption{}) + if err != nil { + return err + } paramsList = make([]any, len(paramsMaps)) for i := 0; i < len(paramsMaps); i++ { paramsList[i] = paramsMaps[i] diff --git a/util/gconv/gconv_converter_time.go b/util/gconv/internal/converter/converter_time.go similarity index 99% rename from util/gconv/gconv_converter_time.go rename to util/gconv/internal/converter/converter_time.go index 974daf45158..4f5b416ba1b 100644 --- a/util/gconv/gconv_converter_time.go +++ b/util/gconv/internal/converter/converter_time.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "time" diff --git a/util/gconv/gconv_converter_uint.go b/util/gconv/internal/converter/converter_uint.go similarity index 99% rename from util/gconv/gconv_converter_uint.go rename to util/gconv/internal/converter/converter_uint.go index 90691feedb9..eb1b912412b 100644 --- a/util/gconv/gconv_converter_uint.go +++ b/util/gconv/internal/converter/converter_uint.go @@ -4,7 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -package gconv +package converter import ( "math" From 996b141900f6f60d55850043c953f2579027d90e Mon Sep 17 00:00:00 2001 From: John Guo Date: Sun, 2 Mar 2025 23:44:23 +0800 Subject: [PATCH 30/48] up --- util/gconv/gconv.go | 1 + util/gconv/gconv_maps.go | 66 +++++-------------- util/gconv/gconv_scan_list.go | 10 +-- util/gconv/gconv_struct.go | 5 +- util/gconv/gconv_z_bench_struct_test.go | 2 +- util/gconv/internal/converter/converter.go | 1 + .../internal/converter/converter_maptomap.go | 8 ++- .../internal/converter/converter_scan.go | 15 ++++- .../internal/converter/converter_struct.go | 33 +++++----- .../internal/converter/converter_structs.go | 8 ++- 10 files changed, 69 insertions(+), 80 deletions(-) diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index 5ec146f2a70..fe6a0ce20e2 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -20,6 +20,7 @@ type ( MapOption = converter.MapOption ScanOption = converter.ScanOption SliceOption = converter.SliceOption + StructOption = converter.StructOption ) // IUnmarshalValue is the interface for custom defined types customizing value assignment. diff --git a/util/gconv/gconv_maps.go b/util/gconv/gconv_maps.go index a68bb4e1046..618ac85de25 100644 --- a/util/gconv/gconv_maps.go +++ b/util/gconv/gconv_maps.go @@ -9,72 +9,38 @@ package gconv import "github.com/gogf/gf/v2/internal/json" // SliceMap is alias of Maps. -func SliceMap(any interface{}, option ...MapOption) []map[string]interface{} { +func SliceMap(any any, option ...MapOption) []map[string]any { return Maps(any, option...) } // SliceMapDeep is alias of MapsDeep. // Deprecated: used SliceMap instead. -func SliceMapDeep(any interface{}) []map[string]interface{} { +func SliceMapDeep(any any) []map[string]any { return MapsDeep(any) } -// Maps converts `value` to []map[string]interface{}. +// Maps converts `value` to []map[string]any. // Note that it automatically checks and converts json string to []map if `value` is string/[]byte. -func Maps(value interface{}, option ...MapOption) []map[string]interface{} { - if value == nil { - return nil - } - switch r := value.(type) { - case string: - list := make([]map[string]interface{}, 0) - if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' { - if err := json.UnmarshalUseNumber([]byte(r), &list); err != nil { - return nil - } - return list - } else { - return nil - } - - case []byte: - list := make([]map[string]interface{}, 0) - if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' { - if err := json.UnmarshalUseNumber(r, &list); err != nil { - return nil - } - return list - } else { - return nil - } - - case []map[string]interface{}: - return r - - default: - array := Interfaces(value) - if len(array) == 0 { - return nil - } - list := make([]map[string]interface{}, len(array)) - for k, v := range array { - list[k] = Map(v, option...) - } - return list +func Maps(value any, option ...MapOption) []map[string]any { + mapOption := MapOption{} + if len(option) > 0 { + mapOption = option[0] } + result, _ := defaultConverter.SliceMap(value, SliceOption{}, mapOption) + return result } -// MapsDeep converts `value` to []map[string]interface{} recursively. +// MapsDeep converts `value` to []map[string]any recursively. // // TODO completely implement the recursive converting for all types. // Deprecated: used Maps instead. -func MapsDeep(value interface{}, tags ...string) []map[string]interface{} { +func MapsDeep(value any, tags ...string) []map[string]any { if value == nil { return nil } switch r := value.(type) { case string: - list := make([]map[string]interface{}, 0) + list := make([]map[string]any, 0) if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' { if err := json.UnmarshalUseNumber([]byte(r), &list); err != nil { return nil @@ -85,7 +51,7 @@ func MapsDeep(value interface{}, tags ...string) []map[string]interface{} { } case []byte: - list := make([]map[string]interface{}, 0) + list := make([]map[string]any, 0) if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' { if err := json.UnmarshalUseNumber(r, &list); err != nil { return nil @@ -95,8 +61,8 @@ func MapsDeep(value interface{}, tags ...string) []map[string]interface{} { return nil } - case []map[string]interface{}: - list := make([]map[string]interface{}, len(r)) + case []map[string]any: + list := make([]map[string]any, len(r)) for k, v := range r { list[k] = MapDeep(v, tags...) } @@ -107,7 +73,7 @@ func MapsDeep(value interface{}, tags ...string) []map[string]interface{} { if len(array) == 0 { return nil } - list := make([]map[string]interface{}, len(array)) + list := make([]map[string]any, len(array)) for k, v := range array { list[k] = MapDeep(v, tags...) } diff --git a/util/gconv/gconv_scan_list.go b/util/gconv/gconv_scan_list.go index 8fae2265ce1..78cc98335b5 100644 --- a/util/gconv/gconv_scan_list.go +++ b/util/gconv/gconv_scan_list.go @@ -93,7 +93,9 @@ import ( // given `relation` parameter. // // See the example or unit testing cases for clear understanding for this function. -func ScanList(structSlice interface{}, structSlicePointer interface{}, bindToAttrName string, relationAttrNameAndFields ...string) (err error) { +func ScanList( + structSlice any, structSlicePointer any, bindToAttrName string, relationAttrNameAndFields ...string, +) (err error) { var ( relationAttrName string relationFields string @@ -111,7 +113,7 @@ func ScanList(structSlice interface{}, structSlicePointer interface{}, bindToAtt // doScanList converts `structSlice` to struct slice which contains other complex struct attributes recursively. // Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct. func doScanList( - structSlice interface{}, structSlicePointer interface{}, bindToAttrName, relationAttrName, relationFields string, + structSlice any, structSlicePointer any, bindToAttrName, relationAttrName, relationFields string, ) (err error) { var ( maps = Maps(structSlice) @@ -169,7 +171,7 @@ func doScanList( // Relation variables. var ( - relationDataMap map[string]interface{} + relationDataMap map[string]any relationFromFieldName string // Eg: relationKV: id:uid -> id relationBindToFieldName string // Eg: relationKV: id:uid -> uid ) @@ -315,7 +317,7 @@ func doScanList( relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName) if relationFromAttrField.IsValid() { // results := make(Result, 0) - results := make([]interface{}, 0) + results := make([]any, 0) for _, v := range SliceAny(relationDataMap[String(relationFromAttrField.Interface())]) { item := v results = append(results, item) diff --git a/util/gconv/gconv_struct.go b/util/gconv/gconv_struct.go index d3fe9570cc6..370f6c83aa7 100644 --- a/util/gconv/gconv_struct.go +++ b/util/gconv/gconv_struct.go @@ -27,5 +27,8 @@ func Struct(params any, pointer any, paramKeyToAttrMap ...map[string]string) (er // specified priorityTagAndFieldName for `params` key-value items to struct attribute names mapping. // The parameter `priorityTag` supports multiple priorityTagAndFieldName that can be joined with char ','. func StructTag(params any, pointer any, priorityTag string) (err error) { - return defaultConverter.Struct(params, pointer, nil, priorityTag) + option := StructOption{ + PriorityTag: priorityTag, + } + return defaultConverter.Struct(params, pointer, option) } diff --git a/util/gconv/gconv_z_bench_struct_test.go b/util/gconv/gconv_z_bench_struct_test.go index a447181b3de..d091a7dfb3d 100644 --- a/util/gconv/gconv_z_bench_struct_test.go +++ b/util/gconv/gconv_z_bench_struct_test.go @@ -92,7 +92,7 @@ func Benchmark_Struct_Basic(b *testing.B) { func Benchmark_doStruct_Fields8_Basic_MapToStruct(b *testing.B) { for i := 0; i < b.N; i++ { - defaultConverter.Struct(structMapFields8, structPointer8, map[string]string{}, "") + defaultConverter.Struct(structMapFields8, structPointer8, StructOption{}) } } diff --git a/util/gconv/internal/converter/converter.go b/util/gconv/internal/converter/converter.go index a9e7269521c..543199d8129 100644 --- a/util/gconv/internal/converter/converter.go +++ b/util/gconv/internal/converter/converter.go @@ -4,6 +4,7 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. +// Package converter provides converting utilities for any types of variables. package converter import ( diff --git a/util/gconv/internal/converter/converter_maptomap.go b/util/gconv/internal/converter/converter_maptomap.go index 51a8be2cf21..ecf10a18408 100644 --- a/util/gconv/internal/converter/converter_maptomap.go +++ b/util/gconv/internal/converter/converter_maptomap.go @@ -94,9 +94,11 @@ func (c *impConverter) MapToMap( mapValue := reflect.New(pointerValueType).Elem() switch pointerValueKind { case reflect.Map, reflect.Struct: - if err = c.Struct( - paramsRv.MapIndex(key).Interface(), mapValue, mapping, "", - ); err != nil { + structOption := StructOption{ + ParamKeyToAttrMap: mapping, + PriorityTag: "", + } + if err = c.Struct(paramsRv.MapIndex(key).Interface(), mapValue, structOption); err != nil { return err } default: diff --git a/util/gconv/internal/converter/converter_scan.go b/util/gconv/internal/converter/converter_scan.go index 15b207f0372..2fade54c83b 100644 --- a/util/gconv/internal/converter/converter_scan.go +++ b/util/gconv/internal/converter/converter_scan.go @@ -15,11 +15,17 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) +// ScanOption is the option for the Scan function. type ScanOption struct { + // ParamKeyToAttrMap specifies the mapping between parameter keys and struct attribute names. ParamKeyToAttrMap map[string]string - BreakOnError bool + + // BreakOnError specifies whether to break converting the next element + // if one element conversion fails. + BreakOnError bool } +// Scan automatically checks the type of `pointer` and converts `params` to `pointer`. func (c *impConverter) Scan(srcValue any, dstPointer any, option ScanOption) (err error) { // Check if srcValue is nil, in which case no conversion is needed if srcValue == nil { @@ -266,8 +272,11 @@ func (c *impConverter) doScanForComplicatedTypes( return c.Structs(srcValue, dstPointer, keyToAttributeNameMapping, "") default: - // Convert to single struct - return c.Struct(srcValue, dstPointer, keyToAttributeNameMapping, "") + structOption := StructOption{ + ParamKeyToAttrMap: keyToAttributeNameMapping, + PriorityTag: "", + } + return c.Struct(srcValue, dstPointer, structOption) } } diff --git a/util/gconv/internal/converter/converter_struct.go b/util/gconv/internal/converter/converter_struct.go index 5b6fdb94e77..42cb206d8c6 100644 --- a/util/gconv/internal/converter/converter_struct.go +++ b/util/gconv/internal/converter/converter_struct.go @@ -19,13 +19,13 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/structcache" ) +type StructOption struct { + ParamKeyToAttrMap map[string]string + PriorityTag string +} + // Struct is the core internal converting function for any data to struct. -func (c *impConverter) Struct( - params any, - pointer any, - paramKeyToAttrMap map[string]string, - priorityTag string, -) (err error) { +func (c *impConverter) Struct(params, pointer any, option StructOption) (err error) { if params == nil { // If `params` is nil, no conversion. return nil @@ -151,7 +151,7 @@ func (c *impConverter) Struct( } // Get struct info from cache or parse struct and cache the struct info. cachedStructInfo := c.internalConverter.GetCachedStructInfo( - pointerElemReflectValue.Type(), priorityTag, + pointerElemReflectValue.Type(), option.PriorityTag, ) // Nothing to be converted. if cachedStructInfo == nil { @@ -172,7 +172,7 @@ func (c *impConverter) Struct( // Firstly, search according to custom mapping rules. // If a possible direct assignment is found, reduce the number of subsequent map searches. - for paramKey, fieldName := range paramKeyToAttrMap { + for paramKey, fieldName := range option.ParamKeyToAttrMap { paramsValue, ok = paramsMap[paramKey] if !ok { continue @@ -184,13 +184,13 @@ func (c *impConverter) Struct( cachedFieldInfo, fieldValue, paramsValue, - paramKeyToAttrMap, + option.ParamKeyToAttrMap, ); err != nil { return err } if len(cachedFieldInfo.OtherSameNameField) > 0 { if err = c.setOtherSameNameField( - cachedFieldInfo, paramsValue, pointerReflectValue, paramKeyToAttrMap, + cachedFieldInfo, paramsValue, pointerReflectValue, option.ParamKeyToAttrMap, ); err != nil { return err } @@ -203,7 +203,8 @@ func (c *impConverter) Struct( return nil } return c.bindStructWithLoopFieldInfos( - paramsMap, pointerElemReflectValue, paramKeyToAttrMap, usedParamsKeyOrTagNameMap, cachedStructInfo, + paramsMap, pointerElemReflectValue, option.ParamKeyToAttrMap, + usedParamsKeyOrTagNameMap, cachedStructInfo, ) } @@ -367,14 +368,14 @@ func (c *impConverter) bindVarToStructField( if cachedFieldInfo.ConvertFunc != nil { return cachedFieldInfo.ConvertFunc(srcValue, fieldValue) } - c.doConvertWithReflectValueSet( + err = c.doConvertWithReflectValueSet( fieldValue, doConvertInput{ FromValue: srcValue, ToTypeName: cachedFieldInfo.StructField.Type.String(), ReferValue: fieldValue, }, ) - return nil + return err } // bindVarToReflectValueWithInterfaceCheck does bind using common interfaces checks. @@ -474,7 +475,7 @@ func (c *impConverter) bindVarToReflectValue( case reflect.Struct: // Recursively converting for struct attribute. - if err = c.Struct(value, structFieldValue, nil, ""); err != nil { + if err = c.Struct(value, structFieldValue, StructOption{}); err != nil { // Note there's reflect conversion mechanism here. structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type())) } @@ -507,7 +508,7 @@ func (c *impConverter) bindVarToReflectValue( elem = reflect.New(elemType).Elem() } if elem.Kind() == reflect.Struct { - if err = c.Struct(reflectValue.Index(i).Interface(), elem, nil, ""); err == nil { + if err = c.Struct(reflectValue.Index(i).Interface(), elem, StructOption{}); err == nil { converted = true } } @@ -564,7 +565,7 @@ func (c *impConverter) bindVarToReflectValue( elem = reflect.New(elemType).Elem() } if elem.Kind() == reflect.Struct { - if err = c.Struct(value, elem, nil, ""); err == nil { + if err = c.Struct(value, elem, StructOption{}); err == nil { converted = true } } diff --git a/util/gconv/internal/converter/converter_structs.go b/util/gconv/internal/converter/converter_structs.go index 5f003d7ef31..00d0641c619 100644 --- a/util/gconv/internal/converter/converter_structs.go +++ b/util/gconv/internal/converter/converter_structs.go @@ -81,6 +81,10 @@ func (c *impConverter) Structs( itemTypeKind = itemType.Kind() pointerRvElem = pointerRv.Elem() pointerRvLength = pointerRvElem.Len() + structOption = StructOption{ + ParamKeyToAttrMap: paramKeyToAttrMap, + PriorityTag: priorityTag, + } ) if itemTypeKind == reflect.Ptr { // Pointer element. @@ -93,7 +97,7 @@ func (c *impConverter) Structs( if !tempReflectValue.IsValid() { tempReflectValue = reflect.New(itemType.Elem()).Elem() } - if err = c.Struct(paramsList[i], tempReflectValue, paramKeyToAttrMap, priorityTag); err != nil { + if err = c.Struct(paramsList[i], tempReflectValue, structOption); err != nil { return err } reflectElemArray.Index(i).Set(tempReflectValue.Addr()) @@ -107,7 +111,7 @@ func (c *impConverter) Structs( } else { tempReflectValue = reflect.New(itemType).Elem() } - if err = c.Struct(paramsList[i], tempReflectValue, paramKeyToAttrMap, priorityTag); err != nil { + if err = c.Struct(paramsList[i], tempReflectValue, structOption); err != nil { return err } reflectElemArray.Index(i).Set(tempReflectValue) From 355ef48941c4dcf00bd46e16e0ef0539f484f617 Mon Sep 17 00:00:00 2001 From: John Guo Date: Sun, 2 Mar 2025 23:47:32 +0800 Subject: [PATCH 31/48] up --- util/gconv/gconv_structs.go | 4 +++- util/gconv/internal/converter/converter_scan.go | 4 +++- util/gconv/internal/converter/converter_structs.go | 8 ++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/util/gconv/gconv_structs.go b/util/gconv/gconv_structs.go index 238b801e2db..b4c43f1c4cb 100644 --- a/util/gconv/gconv_structs.go +++ b/util/gconv/gconv_structs.go @@ -21,5 +21,7 @@ func SliceStruct(params any, pointer any, mapping ...map[string]string) (err err // specified priorityTagAndFieldName for `params` key-value items to struct attribute names mapping. // The parameter `priorityTag` supports multiple priorityTagAndFieldName that can be joined with char ','. func StructsTag(params any, pointer any, priorityTag string) (err error) { - return defaultConverter.Structs(params, pointer, nil, priorityTag) + return defaultConverter.Structs(params, pointer, SliceOption{}, StructOption{ + PriorityTag: priorityTag, + }) } diff --git a/util/gconv/internal/converter/converter_scan.go b/util/gconv/internal/converter/converter_scan.go index 2fade54c83b..2c67a974b0c 100644 --- a/util/gconv/internal/converter/converter_scan.go +++ b/util/gconv/internal/converter/converter_scan.go @@ -269,7 +269,9 @@ func (c *impConverter) doScanForComplicatedTypes( return c.MapToMaps(srcValue, dstPointer, keyToAttributeNameMapping) } // Convert to slice of structs - return c.Structs(srcValue, dstPointer, keyToAttributeNameMapping, "") + return c.Structs(srcValue, dstPointer, SliceOption{}, StructOption{ + ParamKeyToAttrMap: keyToAttributeNameMapping, + }) default: structOption := StructOption{ diff --git a/util/gconv/internal/converter/converter_structs.go b/util/gconv/internal/converter/converter_structs.go index 00d0641c619..0f0f5703f35 100644 --- a/util/gconv/internal/converter/converter_structs.go +++ b/util/gconv/internal/converter/converter_structs.go @@ -21,7 +21,7 @@ import ( // Note that if `pointer` is a pointer to another pointer of type of slice of struct, // it will create the struct/pointer internally. func (c *impConverter) Structs( - params any, pointer any, paramKeyToAttrMap map[string]string, priorityTag string, + params any, pointer any, sliceOption SliceOption, structOption StructOption, ) (err error) { defer func() { // Catch the panic, especially the reflection operation panics. @@ -62,7 +62,7 @@ func (c *impConverter) Structs( paramsList[i] = paramsRv.Index(i).Interface() } default: - paramsMaps, err := c.SliceMap(params, SliceOption{}, MapOption{}) + paramsMaps, err := c.SliceMap(params, sliceOption, MapOption{}) if err != nil { return err } @@ -81,10 +81,6 @@ func (c *impConverter) Structs( itemTypeKind = itemType.Kind() pointerRvElem = pointerRv.Elem() pointerRvLength = pointerRvElem.Len() - structOption = StructOption{ - ParamKeyToAttrMap: paramKeyToAttrMap, - PriorityTag: priorityTag, - } ) if itemTypeKind == reflect.Ptr { // Pointer element. From d42d2c2344120db478d3cb13e8d34f5c82172c78 Mon Sep 17 00:00:00 2001 From: John Guo Date: Mon, 3 Mar 2025 00:05:57 +0800 Subject: [PATCH 32/48] up --- util/gconv/gconv.go | 117 +++++++++++++++++- util/gconv/internal/converter/converter.go | 51 ++------ .../internal/converter/converter_bool.go | 2 +- .../internal/converter/converter_builtin.go | 16 +-- .../internal/converter/converter_bytes.go | 2 +- .../internal/converter/converter_convert.go | 16 +-- .../internal/converter/converter_float.go | 4 +- .../gconv/internal/converter/converter_int.go | 10 +- .../gconv/internal/converter/converter_map.go | 8 +- .../internal/converter/converter_maptomap.go | 2 +- .../internal/converter/converter_maptomaps.go | 2 +- .../internal/converter/converter_rune.go | 4 +- .../internal/converter/converter_scan.go | 6 +- .../internal/converter/converter_slice_any.go | 2 +- .../converter/converter_slice_float.go | 4 +- .../internal/converter/converter_slice_int.go | 6 +- .../internal/converter/converter_slice_map.go | 2 +- .../internal/converter/converter_slice_str.go | 2 +- .../converter/converter_slice_uint.go | 6 +- .../internal/converter/converter_string.go | 2 +- .../internal/converter/converter_struct.go | 16 ++- .../internal/converter/converter_structs.go | 2 +- .../internal/converter/converter_time.go | 6 +- .../internal/converter/converter_uint.go | 10 +- 24 files changed, 187 insertions(+), 111 deletions(-) diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index fe6a0ce20e2..fa7279e6efb 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -10,17 +10,121 @@ package gconv import ( + "time" + + "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/gconv/internal/converter" "github.com/gogf/gf/v2/util/gconv/internal/localinterface" "github.com/gogf/gf/v2/util/gconv/internal/structcache" ) +// Converter is the manager for type converting. +type Converter interface { + ConverterForConvert + ConverterForRegister + ConverterForInt + ConverterForUint + ConverterForTime + ConverterForFloat + ConverterForMap + ConverterForSlice + ConverterForStruct + ConverterForBasic +} + +// ConverterForBasic is the basic converting interface. +type ConverterForBasic interface { + Scan(srcValue, dstPointer any, option ScanOption) (err error) + String(any any) (string, error) + Bool(any any) (bool, error) + Rune(any any) (rune, error) +} + +// ConverterForTime is the converting interface for time. +type ConverterForTime interface { + Time(v any, format ...string) (time.Time, error) + Duration(v any) (time.Duration, error) + GTime(v any, format ...string) (*gtime.Time, error) +} + +// ConverterForInt is the converting interface for integer. +type ConverterForInt interface { + Int(v any) (int, error) + Int8(v any) (int8, error) + Int16(v any) (int16, error) + Int32(v any) (int32, error) + Int64(v any) (int64, error) +} + +// ConverterForUint is the converting interface for unsigned integer. +type ConverterForUint interface { + Uint(v any) (uint, error) + Uint8(v any) (uint8, error) + Uint16(v any) (uint16, error) + Uint32(v any) (uint32, error) + Uint64(v any) (uint64, error) +} + +// ConverterForFloat is the converting interface for float. +type ConverterForFloat interface { + Float32(v any) (float32, error) + Float64(v any) (float64, error) +} + +// ConverterForMap is the converting interface for map. +type ConverterForMap interface { + Map(v any, option MapOption) (map[string]any, error) + MapStrStr(v any, option MapOption) (map[string]string, error) +} + +// ConverterForSlice is the converting interface for slice. +type ConverterForSlice interface { + Bytes(v any) ([]byte, error) + Runes(v any) ([]rune, error) + SliceAny(v any, option SliceOption) ([]any, error) + SliceFloat32(v any, option SliceOption) ([]float32, error) + SliceFloat64(v any, option SliceOption) ([]float64, error) + SliceInt(v any, option SliceOption) ([]int, error) + SliceInt32(v any, option SliceOption) ([]int32, error) + SliceInt64(v any, option SliceOption) ([]int64, error) + SliceUint(v any, option SliceOption) ([]uint, error) + SliceUint32(v any, option SliceOption) ([]uint32, error) + SliceUint64(v any, option SliceOption) ([]uint64, error) + SliceStr(v any, option SliceOption) ([]string, error) + SliceMap(v any, sliceOption SliceOption, mapOption MapOption) ([]map[string]any, error) +} + +// ConverterForStruct is the converting interface for struct. +type ConverterForStruct interface { + Struct(params, pointer any, option StructOption) (err error) + Structs(params, pointer any, sliceOption SliceOption, structOption StructOption) (err error) +} + +// ConverterForConvert is the converting interface for custom converting. +type ConverterForConvert interface { + ConvertWithRefer(fromValue, referValue any, extraParams ...any) (any, error) +} + +// ConverterForRegister is the converting interface for custom converter registration. +type ConverterForRegister interface { + RegisterTypeConverterFunc(fn any) (err error) +} + type ( + // AnyConvertFunc is the function type for converting any to specified type. AnyConvertFunc = structcache.AnyConvertFunc - MapOption = converter.MapOption - ScanOption = converter.ScanOption - SliceOption = converter.SliceOption - StructOption = converter.StructOption + + // MapOption specifies the option for map converting. + MapOption = converter.MapOption + + // SliceOption is the option for Slice type converting. + SliceOption = converter.SliceOption + + // ScanOption is the option for the Scan function. + ScanOption = converter.ScanOption + + // StructOption is the option for Struct converting. + StructOption = converter.StructOption ) // IUnmarshalValue is the interface for custom defined types customizing value assignment. @@ -32,6 +136,11 @@ var ( defaultConverter = converter.NewConverter() ) +// NewConverter creates and returns management object for type converting. +func NewConverter() Converter { + return converter.NewConverter() +} + // RegisterConverter registers custom converter. // Deprecated: use RegisterTypeConverterFunc instead for clear func RegisterConverter(fn any) (err error) { diff --git a/util/gconv/internal/converter/converter.go b/util/gconv/internal/converter/converter.go index 543199d8129..00f0481e19a 100644 --- a/util/gconv/internal/converter/converter.go +++ b/util/gconv/internal/converter/converter.go @@ -32,45 +32,8 @@ type ( converterFunc = reflect.Value ) -// Converter is the manager for type converting. -type Converter interface { - RegisterTypeConverterFunc(fn any) (err error) - ConverterForInt - ConverterForUint - String(any any) (string, error) - Bool(any any) (bool, error) - Bytes(any any) ([]byte, error) - Float32(any any) (float32, error) - Float64(any any) (float64, error) - - MapToMap(params any, pointer any, mapping ...map[string]string) (err error) - MapToMaps(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error) - Rune(any any) (rune, error) - Runes(any any) ([]rune, error) - Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) - Time(any interface{}, format ...string) (time.Time, error) - Duration(any interface{}) (time.Duration, error) - GTime(any interface{}, format ...string) (*gtime.Time, error) -} - -type ConverterForInt interface { - Int(any any) (int, error) - Int8(any any) (int8, error) - Int16(any any) (int16, error) - Int32(any any) (int32, error) - Int64(any any) (int64, error) -} - -type ConverterForUint interface { - Uint(any any) (uint, error) - Uint8(any any) (uint8, error) - Uin16(any any) (uint16, error) - Uint32(any any) (uint32, error) - Uint64(any any) (uint64, error) -} - -// impConverter implements the interface Converter. -type impConverter struct { +// Converter implements the interface Converter. +type Converter struct { internalConverter *structcache.Converter typeConverterFuncMap map[converterInType]map[converterOutType]converterFunc } @@ -110,8 +73,8 @@ var ( ) // NewConverter creates and returns management object for type converting. -func NewConverter() *impConverter { - cf := &impConverter{ +func NewConverter() *Converter { + cf := &Converter{ internalConverter: structcache.NewConverter(), typeConverterFuncMap: make(map[converterInType]map[converterOutType]converterFunc), } @@ -127,7 +90,7 @@ func NewConverter() *impConverter { // 1. The parameter `fn` must be defined as pattern `func(T1) (T2, error)`. // It will convert type `T1` to type `T2`. // 2. The `T1` should not be type of pointer, but the `T2` should be type of pointer. -func (c *impConverter) RegisterTypeConverterFunc(fn any) (err error) { +func (c *Converter) RegisterTypeConverterFunc(fn any) (err error) { var ( fnReflectType = reflect.TypeOf(fn) errType = reflect.TypeOf((*error)(nil)).Elem() @@ -184,7 +147,7 @@ func (c *impConverter) RegisterTypeConverterFunc(fn any) (err error) { return } -func (c *impConverter) registerBuiltInConverter() { +func (c *Converter) registerBuiltInConverter() { c.registerAnyConvertFuncForTypes( c.builtInAnyConvertFuncForInt64, intType, int8Type, int16Type, int32Type, int64Type, ) @@ -211,7 +174,7 @@ func (c *impConverter) registerBuiltInConverter() { ) } -func (c *impConverter) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, types ...reflect.Type) { +func (c *Converter) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, types ...reflect.Type) { for _, t := range types { c.internalConverter.RegisterAnyConvertFunc(t, convertFunc) } diff --git a/util/gconv/internal/converter/converter_bool.go b/util/gconv/internal/converter/converter_bool.go index d9e88c41ecd..f8d9ce7c953 100644 --- a/util/gconv/internal/converter/converter_bool.go +++ b/util/gconv/internal/converter/converter_bool.go @@ -15,7 +15,7 @@ import ( ) // Bool converts `any` to bool. -func (c *impConverter) Bool(any any) (bool, error) { +func (c *Converter) Bool(any any) (bool, error) { if empty.IsNil(any) { return false, nil } diff --git a/util/gconv/internal/converter/converter_builtin.go b/util/gconv/internal/converter/converter_builtin.go index b8a8e0e4746..f7ac1cf0e37 100644 --- a/util/gconv/internal/converter/converter_builtin.go +++ b/util/gconv/internal/converter/converter_builtin.go @@ -13,7 +13,7 @@ import ( "github.com/gogf/gf/v2/os/gtime" ) -func (c *impConverter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) error { +func (c *Converter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) error { v, err := c.Int64(from) if err != nil { return err @@ -22,7 +22,7 @@ func (c *impConverter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) return nil } -func (c *impConverter) builtInAnyConvertFuncForUint64(from any, to reflect.Value) error { +func (c *Converter) builtInAnyConvertFuncForUint64(from any, to reflect.Value) error { v, err := c.Uint64(from) if err != nil { return err @@ -31,7 +31,7 @@ func (c *impConverter) builtInAnyConvertFuncForUint64(from any, to reflect.Value return nil } -func (c *impConverter) builtInAnyConvertFuncForString(from any, to reflect.Value) error { +func (c *Converter) builtInAnyConvertFuncForString(from any, to reflect.Value) error { v, err := c.String(from) if err != nil { return err @@ -40,7 +40,7 @@ func (c *impConverter) builtInAnyConvertFuncForString(from any, to reflect.Value return nil } -func (c *impConverter) builtInAnyConvertFuncForFloat64(from any, to reflect.Value) error { +func (c *Converter) builtInAnyConvertFuncForFloat64(from any, to reflect.Value) error { v, err := c.Float64(from) if err != nil { return err @@ -49,7 +49,7 @@ func (c *impConverter) builtInAnyConvertFuncForFloat64(from any, to reflect.Valu return nil } -func (c *impConverter) builtInAnyConvertFuncForBool(from any, to reflect.Value) error { +func (c *Converter) builtInAnyConvertFuncForBool(from any, to reflect.Value) error { v, err := c.Bool(from) if err != nil { return err @@ -58,7 +58,7 @@ func (c *impConverter) builtInAnyConvertFuncForBool(from any, to reflect.Value) return nil } -func (c *impConverter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) error { +func (c *Converter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) error { v, err := c.Bytes(from) if err != nil { return err @@ -67,7 +67,7 @@ func (c *impConverter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) return nil } -func (c *impConverter) builtInAnyConvertFuncForTime(from any, to reflect.Value) error { +func (c *Converter) builtInAnyConvertFuncForTime(from any, to reflect.Value) error { t, err := c.Time(from) if err != nil { return err @@ -76,7 +76,7 @@ func (c *impConverter) builtInAnyConvertFuncForTime(from any, to reflect.Value) return nil } -func (c *impConverter) builtInAnyConvertFuncForGTime(from any, to reflect.Value) error { +func (c *Converter) builtInAnyConvertFuncForGTime(from any, to reflect.Value) error { v, err := c.GTime(from) if err != nil { return err diff --git a/util/gconv/internal/converter/converter_bytes.go b/util/gconv/internal/converter/converter_bytes.go index dfec4eef0c4..43cfa771bf4 100644 --- a/util/gconv/internal/converter/converter_bytes.go +++ b/util/gconv/internal/converter/converter_bytes.go @@ -17,7 +17,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *impConverter) Bytes(any any) ([]byte, error) { +func (c *Converter) Bytes(any any) ([]byte, error) { if empty.IsNil(any) { return nil, nil } diff --git a/util/gconv/internal/converter/converter_convert.go b/util/gconv/internal/converter/converter_convert.go index 68195d0f689..5668a6b349a 100644 --- a/util/gconv/internal/converter/converter_convert.go +++ b/util/gconv/internal/converter/converter_convert.go @@ -18,7 +18,7 @@ import ( // // The optional parameter `extraParams` is used for additional necessary parameter for this conversion. // It supports common basic types conversion as its conversion based on type name string. -func (c *impConverter) ConvertWithTypeName(fromValue any, toTypeName string, extraParams ...any) (any, error) { +func (c *Converter) ConvertWithTypeName(fromValue any, toTypeName string, extraParams ...any) (any, error) { return c.doConvert( doConvertInput{ FromValue: fromValue, @@ -33,7 +33,7 @@ func (c *impConverter) ConvertWithTypeName(fromValue any, toTypeName string, ext // // The optional parameter `extraParams` is used for additional necessary parameter for this conversion. // It supports common basic types conversion as its conversion based on type name string. -func (c *impConverter) ConvertWithRefer(fromValue, referValue any, extraParams ...any) (any, error) { +func (c *Converter) ConvertWithRefer(fromValue, referValue any, extraParams ...any) (any, error) { var referValueRf reflect.Value if v, ok := referValue.(reflect.Value); ok { referValueRf = v @@ -60,7 +60,7 @@ type doConvertInput struct { } // doConvert does commonly use types converting. -func (c *impConverter) doConvert(in doConvertInput) (convertedValue any, err error) { +func (c *Converter) doConvert(in doConvertInput) (convertedValue any, err error) { switch in.ToTypeName { case "int": return c.Int(in.FromValue) @@ -445,7 +445,7 @@ func (c *impConverter) doConvert(in doConvertInput) (convertedValue any, err err } } -func (c *impConverter) doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput) error { +func (c *Converter) doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput) error { convertedValue, err := c.doConvert(in) if err != nil { return err @@ -456,7 +456,7 @@ func (c *impConverter) doConvertWithReflectValueSet(reflectValue reflect.Value, return err } -func (c *impConverter) getRegisteredConverterFuncAndSrcType( +func (c *Converter) getRegisteredConverterFuncAndSrcType( srcReflectValue, dstReflectValueForRefer reflect.Value, ) (f converterFunc, srcType reflect.Type, ok bool) { if len(c.typeConverterFuncMap) == 0 { @@ -492,7 +492,7 @@ func (c *impConverter) getRegisteredConverterFuncAndSrcType( return } -func (c *impConverter) callCustomConverterWithRefer( +func (c *Converter) callCustomConverterWithRefer( srcReflectValue, referReflectValue reflect.Value, ) (dstReflectValue reflect.Value, converted bool, err error) { registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, referReflectValue) @@ -505,7 +505,7 @@ func (c *impConverter) callCustomConverterWithRefer( } // callCustomConverter call the custom converter. It will try some possible type. -func (c *impConverter) callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) { +func (c *Converter) callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) { registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, dstReflectValue) if !ok { return false, nil @@ -513,7 +513,7 @@ func (c *impConverter) callCustomConverter(srcReflectValue, dstReflectValue refl return c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType) } -func (c *impConverter) doCallCustomConverter( +func (c *Converter) doCallCustomConverter( srcReflectValue reflect.Value, dstReflectValue reflect.Value, registeredConverterFunc converterFunc, diff --git a/util/gconv/internal/converter/converter_float.go b/util/gconv/internal/converter/converter_float.go index 2e9968120b7..49f5ce44490 100644 --- a/util/gconv/internal/converter/converter_float.go +++ b/util/gconv/internal/converter/converter_float.go @@ -17,7 +17,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *impConverter) Float32(any any) (float32, error) { +func (c *Converter) Float32(any any) (float32, error) { if empty.IsNil(any) { return 0, nil } @@ -78,7 +78,7 @@ func (c *impConverter) Float32(any any) (float32, error) { } } -func (c *impConverter) Float64(any any) (float64, error) { +func (c *Converter) Float64(any any) (float64, error) { if empty.IsNil(any) { return 0, nil } diff --git a/util/gconv/internal/converter/converter_int.go b/util/gconv/internal/converter/converter_int.go index b3999734a52..c2d4b421f52 100644 --- a/util/gconv/internal/converter/converter_int.go +++ b/util/gconv/internal/converter/converter_int.go @@ -18,7 +18,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *impConverter) Int(any any) (int, error) { +func (c *Converter) Int(any any) (int, error) { if v, ok := any.(int); ok { return v, nil } @@ -29,7 +29,7 @@ func (c *impConverter) Int(any any) (int, error) { return int(v), nil } -func (c *impConverter) Int8(any any) (int8, error) { +func (c *Converter) Int8(any any) (int8, error) { if v, ok := any.(int8); ok { return v, nil } @@ -40,7 +40,7 @@ func (c *impConverter) Int8(any any) (int8, error) { return int8(v), nil } -func (c *impConverter) Int16(any any) (int16, error) { +func (c *Converter) Int16(any any) (int16, error) { if v, ok := any.(int16); ok { return v, nil } @@ -51,7 +51,7 @@ func (c *impConverter) Int16(any any) (int16, error) { return int16(v), nil } -func (c *impConverter) Int32(any any) (int32, error) { +func (c *Converter) Int32(any any) (int32, error) { if v, ok := any.(int32); ok { return v, nil } @@ -62,7 +62,7 @@ func (c *impConverter) Int32(any any) (int32, error) { return int32(v), nil } -func (c *impConverter) Int64(any any) (int64, error) { +func (c *Converter) Int64(any any) (int64, error) { if empty.IsNil(any) { return 0, nil } diff --git a/util/gconv/internal/converter/converter_map.go b/util/gconv/internal/converter/converter_map.go index e0dfe0cc3c3..46e9f27fb7a 100644 --- a/util/gconv/internal/converter/converter_map.go +++ b/util/gconv/internal/converter/converter_map.go @@ -41,13 +41,13 @@ type MapOption struct { // If `value` is a struct/*struct object, the second parameter `priorityTagAndFieldName` specifies the most priority // priorityTagAndFieldName that will be detected, otherwise it detects the priorityTagAndFieldName in order of: // gconv, json, field name. -func (c *impConverter) Map(value any, option MapOption) (map[string]any, error) { +func (c *Converter) Map(value any, option MapOption) (map[string]any, error) { return c.doMapConvert(value, RecursiveTypeAuto, false, option) } // MapStrStr converts `value` to map[string]string. // Note that there might be data copy for this map type converting. -func (c *impConverter) MapStrStr(value any, option MapOption) (map[string]string, error) { +func (c *Converter) MapStrStr(value any, option MapOption) (map[string]string, error) { if r, ok := value.(map[string]string); ok { return r, nil } @@ -76,7 +76,7 @@ func (c *impConverter) MapStrStr(value any, option MapOption) (map[string]string // It automatically checks and converts json string to map if `value` is string/[]byte. // // TODO completely implement the recursive converting for all types, especially the map. -func (c *impConverter) doMapConvert( +func (c *Converter) doMapConvert( value any, recursive RecursiveType, mustMapReturn bool, option MapOption, ) (map[string]any, error) { if value == nil { @@ -336,7 +336,7 @@ type doMapConvertForMapOrStructValueInput struct { MustMapReturn bool // Must return map instead of Value when empty. } -func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) (any, error) { +func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) (any, error) { if !in.IsRoot && !in.RecursiveOption { return in.Value, nil } diff --git a/util/gconv/internal/converter/converter_maptomap.go b/util/gconv/internal/converter/converter_maptomap.go index ecf10a18408..d1d4cb1cf05 100644 --- a/util/gconv/internal/converter/converter_maptomap.go +++ b/util/gconv/internal/converter/converter_maptomap.go @@ -23,7 +23,7 @@ import ( // // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes // sense only if the items of original map `params` is type struct. -func (c *impConverter) MapToMap( +func (c *Converter) MapToMap( params, pointer any, mapping map[string]string, option MapOption, ) (err error) { var ( diff --git a/util/gconv/internal/converter/converter_maptomaps.go b/util/gconv/internal/converter/converter_maptomaps.go index 3a842585f74..0b9fd21074a 100644 --- a/util/gconv/internal/converter/converter_maptomaps.go +++ b/util/gconv/internal/converter/converter_maptomaps.go @@ -21,7 +21,7 @@ import ( // // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes // sense only if the item of `params` is type struct. -func (c *impConverter) MapToMaps(params any, pointer any, paramKeyToAttrMap map[string]string) (err error) { +func (c *Converter) MapToMaps(params any, pointer any, paramKeyToAttrMap map[string]string) (err error) { // Params and its element type check. var ( paramsRv reflect.Value diff --git a/util/gconv/internal/converter/converter_rune.go b/util/gconv/internal/converter/converter_rune.go index 301687d02d6..1e95807cb3e 100644 --- a/util/gconv/internal/converter/converter_rune.go +++ b/util/gconv/internal/converter/converter_rune.go @@ -6,7 +6,7 @@ package converter -func (c *impConverter) Rune(any any) (rune, error) { +func (c *Converter) Rune(any any) (rune, error) { if v, ok := any.(rune); ok { return v, nil } @@ -17,7 +17,7 @@ func (c *impConverter) Rune(any any) (rune, error) { return v, nil } -func (c *impConverter) Runes(any any) ([]rune, error) { +func (c *Converter) Runes(any any) ([]rune, error) { if v, ok := any.([]rune); ok { return v, nil } diff --git a/util/gconv/internal/converter/converter_scan.go b/util/gconv/internal/converter/converter_scan.go index 2c67a974b0c..2e6a5178b7f 100644 --- a/util/gconv/internal/converter/converter_scan.go +++ b/util/gconv/internal/converter/converter_scan.go @@ -26,7 +26,7 @@ type ScanOption struct { } // Scan automatically checks the type of `pointer` and converts `params` to `pointer`. -func (c *impConverter) Scan(srcValue any, dstPointer any, option ScanOption) (err error) { +func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err error) { // Check if srcValue is nil, in which case no conversion is needed if srcValue == nil { return nil @@ -228,7 +228,7 @@ func (c *impConverter) Scan(srcValue any, dstPointer any, option ScanOption) (er // - dstPointer: The destination pointer to convert to // - dstPointerReflectType: The reflection type of the destination pointer // - paramKeyToAttrMap: Optional mapping between parameter keys and struct attribute names -func (c *impConverter) doScanForComplicatedTypes( +func (c *Converter) doScanForComplicatedTypes( srcValue, dstPointer any, dstPointerReflectType reflect.Type, option ScanOption, @@ -339,7 +339,7 @@ func doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem ref // Returns: // - bool: true if JSON conversion was successful // - error: any error that occurred during conversion -func (c *impConverter) doConvertWithJsonCheck(srcValue any, dstPointer any) (ok bool, err error) { +func (c *Converter) doConvertWithJsonCheck(srcValue any, dstPointer any) (ok bool, err error) { switch valueResult := srcValue.(type) { case []byte: if json.Valid(valueResult) { diff --git a/util/gconv/internal/converter/converter_slice_any.go b/util/gconv/internal/converter/converter_slice_any.go index c020d5ad63b..fbbde71b1c3 100644 --- a/util/gconv/internal/converter/converter_slice_any.go +++ b/util/gconv/internal/converter/converter_slice_any.go @@ -23,7 +23,7 @@ type SliceOption struct { } // SliceAny converts `any` to []any. -func (c *impConverter) SliceAny(any interface{}, option SliceOption) ([]any, error) { +func (c *Converter) SliceAny(any interface{}, option SliceOption) ([]any, error) { if empty.IsNil(any) { return nil, nil } diff --git a/util/gconv/internal/converter/converter_slice_float.go b/util/gconv/internal/converter/converter_slice_float.go index 85f1e0071c0..0019e790c71 100644 --- a/util/gconv/internal/converter/converter_slice_float.go +++ b/util/gconv/internal/converter/converter_slice_float.go @@ -17,7 +17,7 @@ import ( ) // SliceFloat32 converts `any` to []float32. -func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]float32, error) { +func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32, error) { if empty.IsNil(any) { return nil, nil } @@ -217,7 +217,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa } // SliceFloat64 converts `any` to []float64. -func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]float64, error) { +func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64, error) { if empty.IsNil(any) { return nil, nil } diff --git a/util/gconv/internal/converter/converter_slice_int.go b/util/gconv/internal/converter/converter_slice_int.go index 1c05a532769..653f3701470 100644 --- a/util/gconv/internal/converter/converter_slice_int.go +++ b/util/gconv/internal/converter/converter_slice_int.go @@ -17,7 +17,7 @@ import ( ) // SliceInt converts `any` to []int. -func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) { +func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) { if empty.IsNil(any) { return nil, nil } @@ -190,7 +190,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) { } // SliceInt32 converts `any` to []int32. -func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error) { +func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) { if empty.IsNil(any) { return nil, nil } @@ -363,7 +363,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error) } // SliceInt64 converts `any` to []int64. -func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error) { +func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) { if empty.IsNil(any) { return nil, nil } diff --git a/util/gconv/internal/converter/converter_slice_map.go b/util/gconv/internal/converter/converter_slice_map.go index 6e040ea0644..c14f48157c8 100644 --- a/util/gconv/internal/converter/converter_slice_map.go +++ b/util/gconv/internal/converter/converter_slice_map.go @@ -10,7 +10,7 @@ import "github.com/gogf/gf/v2/internal/json" // SliceMap converts `value` to []map[string]any. // Note that it automatically checks and converts json string to []map if `value` is string/[]byte. -func (c *impConverter) SliceMap(value any, sliceOption SliceOption, mapOption MapOption) ([]map[string]any, error) { +func (c *Converter) SliceMap(value any, sliceOption SliceOption, mapOption MapOption) ([]map[string]any, error) { if value == nil { return nil, nil } diff --git a/util/gconv/internal/converter/converter_slice_str.go b/util/gconv/internal/converter/converter_slice_str.go index a62658ddada..850c68382f2 100644 --- a/util/gconv/internal/converter/converter_slice_str.go +++ b/util/gconv/internal/converter/converter_slice_str.go @@ -16,7 +16,7 @@ import ( ) // SliceStr converts `any` to []string. -func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, error) { +func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, error) { if empty.IsNil(any) { return nil, nil } diff --git a/util/gconv/internal/converter/converter_slice_uint.go b/util/gconv/internal/converter/converter_slice_uint.go index 9e44b7428a5..22b749ce82b 100644 --- a/util/gconv/internal/converter/converter_slice_uint.go +++ b/util/gconv/internal/converter/converter_slice_uint.go @@ -17,7 +17,7 @@ import ( ) // SliceUint converts `any` to []uint. -func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, error) { +func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, error) { if empty.IsNil(any) { return nil, nil } @@ -188,7 +188,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e } // SliceUint32 converts `any` to []uint32. -func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint32, error) { +func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32, error) { if empty.IsNil(any) { return nil, nil } @@ -358,7 +358,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3 } // SliceUint64 converts `any` to []uint64. -func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint64, error) { +func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64, error) { if empty.IsNil(any) { return nil, nil } diff --git a/util/gconv/internal/converter/converter_string.go b/util/gconv/internal/converter/converter_string.go index e3415abd765..cd9434faaf6 100644 --- a/util/gconv/internal/converter/converter_string.go +++ b/util/gconv/internal/converter/converter_string.go @@ -20,7 +20,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *impConverter) String(any any) (string, error) { +func (c *Converter) String(any any) (string, error) { if empty.IsNil(any) { return "", nil } diff --git a/util/gconv/internal/converter/converter_struct.go b/util/gconv/internal/converter/converter_struct.go index 42cb206d8c6..bfdba5ec48f 100644 --- a/util/gconv/internal/converter/converter_struct.go +++ b/util/gconv/internal/converter/converter_struct.go @@ -19,13 +19,17 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/structcache" ) +// StructOption is the option for Struct converting. type StructOption struct { + // ParamKeyToAttrMap is the map for custom parameter key to attribute name mapping. ParamKeyToAttrMap map[string]string - PriorityTag string + + // PriorityTag is the priority tag for struct converting. + PriorityTag string } // Struct is the core internal converting function for any data to struct. -func (c *impConverter) Struct(params, pointer any, option StructOption) (err error) { +func (c *Converter) Struct(params, pointer any, option StructOption) (err error) { if params == nil { // If `params` is nil, no conversion. return nil @@ -208,7 +212,7 @@ func (c *impConverter) Struct(params, pointer any, option StructOption) (err err ) } -func (c *impConverter) setOtherSameNameField( +func (c *Converter) setOtherSameNameField( cachedFieldInfo *structcache.CachedFieldInfo, srcValue any, structValue reflect.Value, @@ -224,7 +228,7 @@ func (c *impConverter) setOtherSameNameField( return nil } -func (c *impConverter) bindStructWithLoopFieldInfos( +func (c *Converter) bindStructWithLoopFieldInfos( paramsMap map[string]any, structValue reflect.Value, paramKeyToAttrMap map[string]string, @@ -320,7 +324,7 @@ func fuzzyMatchingFieldName( // bindVarToStructField sets value to struct object attribute by name. // each value to attribute converting comes into in this function. -func (c *impConverter) bindVarToStructField( +func (c *Converter) bindVarToStructField( cachedFieldInfo *structcache.CachedFieldInfo, fieldValue reflect.Value, srcValue any, @@ -443,7 +447,7 @@ func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value a } // bindVarToReflectValue sets `value` to reflect value object `structFieldValue`. -func (c *impConverter) bindVarToReflectValue( +func (c *Converter) bindVarToReflectValue( structFieldValue reflect.Value, value any, paramKeyToAttrMap map[string]string, ) (err error) { // JSON content converting. diff --git a/util/gconv/internal/converter/converter_structs.go b/util/gconv/internal/converter/converter_structs.go index 0f0f5703f35..ceaa385443e 100644 --- a/util/gconv/internal/converter/converter_structs.go +++ b/util/gconv/internal/converter/converter_structs.go @@ -20,7 +20,7 @@ import ( // The parameter `pointer` should be type of pointer to slice of struct. // Note that if `pointer` is a pointer to another pointer of type of slice of struct, // it will create the struct/pointer internally. -func (c *impConverter) Structs( +func (c *Converter) Structs( params any, pointer any, sliceOption SliceOption, structOption StructOption, ) (err error) { defer func() { diff --git a/util/gconv/internal/converter/converter_time.go b/util/gconv/internal/converter/converter_time.go index 4f5b416ba1b..05eae209faa 100644 --- a/util/gconv/internal/converter/converter_time.go +++ b/util/gconv/internal/converter/converter_time.go @@ -16,7 +16,7 @@ import ( ) // Time converts `any` to time.Time. -func (c *impConverter) Time(any interface{}, format ...string) (time.Time, error) { +func (c *Converter) Time(any interface{}, format ...string) (time.Time, error) { // It's already this type. if len(format) == 0 { if v, ok := any.(time.Time); ok { @@ -36,7 +36,7 @@ func (c *impConverter) Time(any interface{}, format ...string) (time.Time, error // Duration converts `any` to time.Duration. // If `any` is string, then it uses time.ParseDuration to convert it. // If `any` is numeric, then it converts `any` as nanoseconds. -func (c *impConverter) Duration(any interface{}) (time.Duration, error) { +func (c *Converter) Duration(any interface{}) (time.Duration, error) { // It's already this type. if v, ok := any.(time.Duration); ok { return v, nil @@ -60,7 +60,7 @@ func (c *impConverter) Duration(any interface{}) (time.Duration, error) { // It returns the converted value that matched the first format of the formats slice. // If no `format` given, it converts `any` using gtime.NewFromTimeStamp if `any` is numeric, // or using gtime.StrToTime if `any` is string. -func (c *impConverter) GTime(any interface{}, format ...string) (*gtime.Time, error) { +func (c *Converter) GTime(any interface{}, format ...string) (*gtime.Time, error) { if empty.IsNil(any) { return nil, nil } diff --git a/util/gconv/internal/converter/converter_uint.go b/util/gconv/internal/converter/converter_uint.go index eb1b912412b..74cf7c55069 100644 --- a/util/gconv/internal/converter/converter_uint.go +++ b/util/gconv/internal/converter/converter_uint.go @@ -18,7 +18,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) -func (c *impConverter) Uint(any any) (uint, error) { +func (c *Converter) Uint(any any) (uint, error) { if empty.IsNil(any) { return 0, nil } @@ -29,7 +29,7 @@ func (c *impConverter) Uint(any any) (uint, error) { return uint(v), err } -func (c *impConverter) Uint8(any any) (uint8, error) { +func (c *Converter) Uint8(any any) (uint8, error) { if empty.IsNil(any) { return 0, nil } @@ -40,7 +40,7 @@ func (c *impConverter) Uint8(any any) (uint8, error) { return uint8(v), err } -func (c *impConverter) Uint16(any any) (uint16, error) { +func (c *Converter) Uint16(any any) (uint16, error) { if empty.IsNil(any) { return 0, nil } @@ -51,7 +51,7 @@ func (c *impConverter) Uint16(any any) (uint16, error) { return uint16(v), err } -func (c *impConverter) Uint32(any any) (uint32, error) { +func (c *Converter) Uint32(any any) (uint32, error) { if empty.IsNil(any) { return 0, nil } @@ -62,7 +62,7 @@ func (c *impConverter) Uint32(any any) (uint32, error) { return uint32(v), err } -func (c *impConverter) Uint64(any any) (uint64, error) { +func (c *Converter) Uint64(any any) (uint64, error) { if empty.IsNil(any) { return 0, nil } From cb7ae2e03f0ba3a8a3d33cc3dd4ae8fa4f52923c Mon Sep 17 00:00:00 2001 From: John Guo Date: Mon, 3 Mar 2025 11:19:17 +0800 Subject: [PATCH 33/48] up --- container/gvar/gvar_basic.go | 4 +- .../drivers/mysql/mysql_z_unit_issue_test.go | 2 +- database/gdb/gdb_converter.go | 72 +++++++++++++++++++ database/gdb/gdb_type_record.go | 4 +- database/gdb/gdb_type_result.go | 4 +- util/gconv/gconv.go | 5 +- util/gconv/internal/converter/converter.go | 57 +++++++-------- .../internal/localinterface/localinterface.go | 14 ++-- 8 files changed, 121 insertions(+), 41 deletions(-) create mode 100644 database/gdb/gdb_converter.go diff --git a/container/gvar/gvar_basic.go b/container/gvar/gvar_basic.go index a7613afb9f9..b57b235578d 100644 --- a/container/gvar/gvar_basic.go +++ b/container/gvar/gvar_basic.go @@ -12,7 +12,7 @@ import ( ) // Val returns the current value of `v`. -func (v *Var) Val() interface{} { +func (v *Var) Val() any { if v == nil { return nil } @@ -25,7 +25,7 @@ func (v *Var) Val() interface{} { } // Interface is alias of Val. -func (v *Var) Interface() interface{} { +func (v *Var) Interface() any { return v.Val() } diff --git a/contrib/drivers/mysql/mysql_z_unit_issue_test.go b/contrib/drivers/mysql/mysql_z_unit_issue_test.go index 019d6042ed6..7f7f0a85401 100644 --- a/contrib/drivers/mysql/mysql_z_unit_issue_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_issue_test.go @@ -1741,7 +1741,7 @@ func Test_Issue4086(t *testing.T) { }, }) }) - return + gtest.C(t, func(t *gtest.T) { type ProxyParam struct { ProxyId int64 `json:"proxyId" orm:"proxy_id"` diff --git a/database/gdb/gdb_converter.go b/database/gdb/gdb_converter.go new file mode 100644 index 00000000000..e20fe0e127f --- /dev/null +++ b/database/gdb/gdb_converter.go @@ -0,0 +1,72 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gdb + +import ( + "reflect" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/util/gconv" +) + +// iVal is used for type assert api for Val(). +type iVal interface { + Val() any +} + +var ( + // converter is the internal type converter for gdb. + converter = gconv.NewConverter() +) + +func init() { + converter.RegisterAnyConverterFunc( + sliceTypeConverterFunc, + reflect.TypeOf([]string{}), + reflect.TypeOf([]float32{}), + reflect.TypeOf([]float64{}), + reflect.TypeOf([]int{}), + reflect.TypeOf([]int32{}), + reflect.TypeOf([]int64{}), + reflect.TypeOf([]uint{}), + reflect.TypeOf([]uint32{}), + reflect.TypeOf([]uint64{}), + ) +} + +func sliceTypeConverterFunc(from any, to reflect.Value) (err error) { + v, ok := from.(iVal) + if !ok { + return nil + } + fromVal := v.Val() + switch x := fromVal.(type) { + case []byte: + dst := to.Addr().Interface() + err = json.Unmarshal(x, dst) + case string: + dst := to.Addr().Interface() + err = json.Unmarshal([]byte(x), dst) + default: + fromType := reflect.TypeOf(fromVal) + switch fromType.Kind() { + case reflect.Slice: + dv, err := converter.ConvertWithTypeName(fromVal, to.Type().String()) + if err != nil { + return err + } + to.Set(reflect.ValueOf(dv)) + default: + err = gerror.Newf( + `unsupported type converting from "%v(%T)" to "%v(%T)"`, + fromVal, fromVal, to, to, + ) + } + } + return err +} diff --git a/database/gdb/gdb_type_record.go b/database/gdb/gdb_type_record.go index 2b14c537573..a32807dcfc9 100644 --- a/database/gdb/gdb_type_record.go +++ b/database/gdb/gdb_type_record.go @@ -53,7 +53,9 @@ func (r Record) Struct(pointer interface{}) error { } return nil } - return gconv.StructTag(r, pointer, OrmTagForStruct) + return converter.Struct(r, pointer, gconv.StructOption{ + PriorityTag: OrmTagForStruct, + }) } // IsEmpty checks and returns whether `r` is empty. diff --git a/database/gdb/gdb_type_result.go b/database/gdb/gdb_type_result.go index 03e7051d3a9..60976d30e96 100644 --- a/database/gdb/gdb_type_result.go +++ b/database/gdb/gdb_type_result.go @@ -200,5 +200,7 @@ func (r Result) Structs(pointer interface{}) (err error) { } return nil } - return gconv.StructsTag(r, pointer, OrmTagForStruct) + return converter.Structs(r, pointer, gconv.SliceOption{}, gconv.StructOption{ + PriorityTag: OrmTagForStruct, + }) } diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index fa7279e6efb..478a796a0cd 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -10,6 +10,7 @@ package gconv import ( + "reflect" "time" "github.com/gogf/gf/v2/os/gtime" @@ -103,11 +104,13 @@ type ConverterForStruct interface { // ConverterForConvert is the converting interface for custom converting. type ConverterForConvert interface { ConvertWithRefer(fromValue, referValue any, extraParams ...any) (any, error) + ConvertWithTypeName(fromValue any, toTypeName string, extraParams ...any) (any, error) } // ConverterForRegister is the converting interface for custom converter registration. type ConverterForRegister interface { - RegisterTypeConverterFunc(fn any) (err error) + RegisterTypeConverterFunc(f any) error + RegisterAnyConverterFunc(f AnyConvertFunc, types ...reflect.Type) } type ( diff --git a/util/gconv/internal/converter/converter.go b/util/gconv/internal/converter/converter.go index 00f0481e19a..5261e022970 100644 --- a/util/gconv/internal/converter/converter.go +++ b/util/gconv/internal/converter/converter.go @@ -78,7 +78,7 @@ func NewConverter() *Converter { internalConverter: structcache.NewConverter(), typeConverterFuncMap: make(map[converterInType]map[converterOutType]converterFunc), } - cf.registerBuiltInConverter() + cf.registerBuiltInAnyConvertFunc() return cf } @@ -90,33 +90,33 @@ func NewConverter() *Converter { // 1. The parameter `fn` must be defined as pattern `func(T1) (T2, error)`. // It will convert type `T1` to type `T2`. // 2. The `T1` should not be type of pointer, but the `T2` should be type of pointer. -func (c *Converter) RegisterTypeConverterFunc(fn any) (err error) { +func (c *Converter) RegisterTypeConverterFunc(f any) (err error) { var ( - fnReflectType = reflect.TypeOf(fn) - errType = reflect.TypeOf((*error)(nil)).Elem() + fReflectType = reflect.TypeOf(f) + errType = reflect.TypeOf((*error)(nil)).Elem() ) - if fnReflectType.Kind() != reflect.Func || - fnReflectType.NumIn() != 1 || fnReflectType.NumOut() != 2 || - !fnReflectType.Out(1).Implements(errType) { + if fReflectType.Kind() != reflect.Func || + fReflectType.NumIn() != 1 || fReflectType.NumOut() != 2 || + !fReflectType.Out(1).Implements(errType) { err = gerror.NewCodef( gcode.CodeInvalidParameter, "parameter must be type of converter function and defined as pattern `func(T1) (T2, error)`, "+ "but defined as `%s`", - fnReflectType.String(), + fReflectType.String(), ) return } // The Key and Value of the converter map should not be pointer. var ( - inType = fnReflectType.In(0) - outType = fnReflectType.Out(0) + inType = fReflectType.In(0) + outType = fReflectType.Out(0) ) if inType.Kind() == reflect.Pointer { err = gerror.NewCodef( gcode.CodeInvalidParameter, "invalid converter function `%s`: invalid input parameter type `%s`, should not be type of pointer", - fnReflectType.String(), inType.String(), + fReflectType.String(), inType.String(), ) return } @@ -124,7 +124,7 @@ func (c *Converter) RegisterTypeConverterFunc(fn any) (err error) { err = gerror.NewCodef( gcode.CodeInvalidParameter, "invalid converter function `%s`: invalid output parameter type `%s` should be type of pointer", - fnReflectType.String(), outType.String(), + fReflectType.String(), outType.String(), ) return } @@ -142,40 +142,41 @@ func (c *Converter) RegisterTypeConverterFunc(fn any) (err error) { ) return } - registeredOutTypeMap[outType] = reflect.ValueOf(fn) + registeredOutTypeMap[outType] = reflect.ValueOf(f) c.internalConverter.RegisterTypeConvertFunc(outType) return } -func (c *Converter) registerBuiltInConverter() { - c.registerAnyConvertFuncForTypes( +// RegisterAnyConverterFunc registers custom type converting function for specified types. +func (c *Converter) RegisterAnyConverterFunc(convertFunc AnyConvertFunc, types ...reflect.Type) { + for _, t := range types { + c.internalConverter.RegisterAnyConvertFunc(t, convertFunc) + } +} + +func (c *Converter) registerBuiltInAnyConvertFunc() { + c.RegisterAnyConverterFunc( c.builtInAnyConvertFuncForInt64, intType, int8Type, int16Type, int32Type, int64Type, ) - c.registerAnyConvertFuncForTypes( + c.RegisterAnyConverterFunc( c.builtInAnyConvertFuncForUint64, uintType, uint8Type, uint16Type, uint32Type, uint64Type, ) - c.registerAnyConvertFuncForTypes( + c.RegisterAnyConverterFunc( c.builtInAnyConvertFuncForString, stringType, ) - c.registerAnyConvertFuncForTypes( + c.RegisterAnyConverterFunc( c.builtInAnyConvertFuncForFloat64, float32Type, float64Type, ) - c.registerAnyConvertFuncForTypes( + c.RegisterAnyConverterFunc( c.builtInAnyConvertFuncForBool, boolType, ) - c.registerAnyConvertFuncForTypes( + c.RegisterAnyConverterFunc( c.builtInAnyConvertFuncForBytes, bytesType, ) - c.registerAnyConvertFuncForTypes( + c.RegisterAnyConverterFunc( c.builtInAnyConvertFuncForTime, timeType, ) - c.registerAnyConvertFuncForTypes( + c.RegisterAnyConverterFunc( c.builtInAnyConvertFuncForGTime, gtimeType, ) } - -func (c *Converter) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, types ...reflect.Type) { - for _, t := range types { - c.internalConverter.RegisterAnyConvertFunc(t, convertFunc) - } -} diff --git a/util/gconv/internal/localinterface/localinterface.go b/util/gconv/internal/localinterface/localinterface.go index 63ef7d0789d..d6821b2c48f 100644 --- a/util/gconv/internal/localinterface/localinterface.go +++ b/util/gconv/internal/localinterface/localinterface.go @@ -9,9 +9,9 @@ package localinterface import "github.com/gogf/gf/v2/os/gtime" -// IVal is used for type assert api for String(). +// IVal is used for type assert api for Val(). type IVal interface { - Val() interface{} + Val() any } // IString is used for type assert api for String(). @@ -56,12 +56,12 @@ type IBytes interface { // IInterface is used for type assert api for Interface(). type IInterface interface { - Interface() interface{} + Interface() any } // IInterfaces is used for type assert api for Interfaces(). type IInterfaces interface { - Interfaces() []interface{} + Interfaces() []any } // IFloats is used for type assert api for Floats(). @@ -86,7 +86,7 @@ type IUints interface { // IMapStrAny is the interface support for converting struct parameter to map. type IMapStrAny interface { - MapStrAny() map[string]interface{} + MapStrAny() map[string]any } // IUnmarshalText is the interface for custom defined types customizing value assignment. @@ -104,12 +104,12 @@ type IUnmarshalJSON interface { // IUnmarshalValue is the interface for custom defined types customizing value assignment. // Note that only pointer can implement interface IUnmarshalValue. type IUnmarshalValue interface { - UnmarshalValue(interface{}) error + UnmarshalValue(any) error } // ISet is the interface for custom value assignment. type ISet interface { - Set(value interface{}) (old interface{}) + Set(value any) (old any) } // IGTime is the interface for gtime.Time converting. From c031261b9918cfb2a470dcb5cb9a50e3628fcaf3 Mon Sep 17 00:00:00 2001 From: John Guo Date: Mon, 3 Mar 2025 11:31:37 +0800 Subject: [PATCH 34/48] up --- database/gdb/gdb_converter.go | 9 +++- database/gdb/gdb_z_mysql_internal_test.go | 9 ++++ util/gconv/internal/converter/converter.go | 44 +++++++++---------- .../internal/converter/converter_bytes.go | 1 + .../internal/converter/converter_float.go | 2 + .../gconv/internal/converter/converter_int.go | 5 +++ .../internal/converter/converter_maptomaps.go | 8 ++-- .../internal/converter/converter_rune.go | 2 + .../internal/converter/converter_scan.go | 8 ++-- .../internal/converter/converter_struct.go | 2 +- .../internal/converter/converter_uint.go | 5 +++ 11 files changed, 63 insertions(+), 32 deletions(-) diff --git a/database/gdb/gdb_converter.go b/database/gdb/gdb_converter.go index e20fe0e127f..f2c96bebccc 100644 --- a/database/gdb/gdb_converter.go +++ b/database/gdb/gdb_converter.go @@ -39,6 +39,11 @@ func init() { ) } +// GetConverter returns the internal type converter for gdb. +func GetConverter() gconv.Converter { + return converter +} + func sliceTypeConverterFunc(from any, to reflect.Value) (err error) { v, ok := from.(iVal) if !ok { @@ -63,8 +68,8 @@ func sliceTypeConverterFunc(from any, to reflect.Value) (err error) { to.Set(reflect.ValueOf(dv)) default: err = gerror.Newf( - `unsupported type converting from "%v(%T)" to "%v(%T)"`, - fromVal, fromVal, to, to, + `unsupported type converting from type "%T" to type "%T"`, + fromVal, to, ) } } diff --git a/database/gdb/gdb_z_mysql_internal_test.go b/database/gdb/gdb_z_mysql_internal_test.go index 8539c2c9481..5b5872eb84b 100644 --- a/database/gdb/gdb_z_mysql_internal_test.go +++ b/database/gdb/gdb_z_mysql_internal_test.go @@ -14,6 +14,15 @@ import ( "github.com/gogf/gf/v2/text/gregex" ) +func Test_GetConverter(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + c := GetConverter() + s, err := c.String(1) + t.AssertNil(err) + t.AssertEQ(s, "1") + }) +} + func Test_HookSelect_Regex(t *testing.T) { gtest.C(t, func(t *gtest.T) { var ( diff --git a/util/gconv/internal/converter/converter.go b/util/gconv/internal/converter/converter.go index 5261e022970..13845929e56 100644 --- a/util/gconv/internal/converter/converter.go +++ b/util/gconv/internal/converter/converter.go @@ -17,8 +17,10 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/structcache" ) +// AnyConvertFunc is the type for any type converting function. type AnyConvertFunc = structcache.AnyConvertFunc +// RecursiveType is the type for converting recursively. type RecursiveType string const ( @@ -47,29 +49,6 @@ var ( "off": {}, "false": {}, } - - intType = reflect.TypeOf(0) - int8Type = reflect.TypeOf(int8(0)) - int16Type = reflect.TypeOf(int16(0)) - int32Type = reflect.TypeOf(int32(0)) - int64Type = reflect.TypeOf(int64(0)) - - uintType = reflect.TypeOf(uint(0)) - uint8Type = reflect.TypeOf(uint8(0)) - uint16Type = reflect.TypeOf(uint16(0)) - uint32Type = reflect.TypeOf(uint32(0)) - uint64Type = reflect.TypeOf(uint64(0)) - - float32Type = reflect.TypeOf(float32(0)) - float64Type = reflect.TypeOf(float64(0)) - - stringType = reflect.TypeOf("") - bytesType = reflect.TypeOf([]byte{}) - - boolType = reflect.TypeOf(false) - - timeType = reflect.TypeOf((*time.Time)(nil)).Elem() - gtimeType = reflect.TypeOf((*gtime.Time)(nil)).Elem() ) // NewConverter creates and returns management object for type converting. @@ -155,6 +134,25 @@ func (c *Converter) RegisterAnyConverterFunc(convertFunc AnyConvertFunc, types . } func (c *Converter) registerBuiltInAnyConvertFunc() { + var ( + intType = reflect.TypeOf(0) + int8Type = reflect.TypeOf(int8(0)) + int16Type = reflect.TypeOf(int16(0)) + int32Type = reflect.TypeOf(int32(0)) + int64Type = reflect.TypeOf(int64(0)) + uintType = reflect.TypeOf(uint(0)) + uint8Type = reflect.TypeOf(uint8(0)) + uint16Type = reflect.TypeOf(uint16(0)) + uint32Type = reflect.TypeOf(uint32(0)) + uint64Type = reflect.TypeOf(uint64(0)) + float32Type = reflect.TypeOf(float32(0)) + float64Type = reflect.TypeOf(float64(0)) + stringType = reflect.TypeOf("") + bytesType = reflect.TypeOf([]byte{}) + boolType = reflect.TypeOf(false) + timeType = reflect.TypeOf((*time.Time)(nil)).Elem() + gtimeType = reflect.TypeOf((*gtime.Time)(nil)).Elem() + ) c.RegisterAnyConverterFunc( c.builtInAnyConvertFuncForInt64, intType, int8Type, int16Type, int32Type, int64Type, ) diff --git a/util/gconv/internal/converter/converter_bytes.go b/util/gconv/internal/converter/converter_bytes.go index 43cfa771bf4..79cd23378ec 100644 --- a/util/gconv/internal/converter/converter_bytes.go +++ b/util/gconv/internal/converter/converter_bytes.go @@ -17,6 +17,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) +// Bytes converts `any` to []byte. func (c *Converter) Bytes(any any) ([]byte, error) { if empty.IsNil(any) { return nil, nil diff --git a/util/gconv/internal/converter/converter_float.go b/util/gconv/internal/converter/converter_float.go index 49f5ce44490..21418100db6 100644 --- a/util/gconv/internal/converter/converter_float.go +++ b/util/gconv/internal/converter/converter_float.go @@ -17,6 +17,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) +// Float32 converts `any` to float32. func (c *Converter) Float32(any any) (float32, error) { if empty.IsNil(any) { return 0, nil @@ -78,6 +79,7 @@ func (c *Converter) Float32(any any) (float32, error) { } } +// Float64 converts `any` to float64. func (c *Converter) Float64(any any) (float64, error) { if empty.IsNil(any) { return 0, nil diff --git a/util/gconv/internal/converter/converter_int.go b/util/gconv/internal/converter/converter_int.go index c2d4b421f52..dc82e926cd8 100644 --- a/util/gconv/internal/converter/converter_int.go +++ b/util/gconv/internal/converter/converter_int.go @@ -18,6 +18,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) +// Int converts `any` to int. func (c *Converter) Int(any any) (int, error) { if v, ok := any.(int); ok { return v, nil @@ -29,6 +30,7 @@ func (c *Converter) Int(any any) (int, error) { return int(v), nil } +// Int8 converts `any` to int8. func (c *Converter) Int8(any any) (int8, error) { if v, ok := any.(int8); ok { return v, nil @@ -40,6 +42,7 @@ func (c *Converter) Int8(any any) (int8, error) { return int8(v), nil } +// Int16 converts `any` to int16. func (c *Converter) Int16(any any) (int16, error) { if v, ok := any.(int16); ok { return v, nil @@ -51,6 +54,7 @@ func (c *Converter) Int16(any any) (int16, error) { return int16(v), nil } +// Int32 converts `any` to int32. func (c *Converter) Int32(any any) (int32, error) { if v, ok := any.(int32); ok { return v, nil @@ -62,6 +66,7 @@ func (c *Converter) Int32(any any) (int32, error) { return int32(v), nil } +// Int64 converts `any` to int64. func (c *Converter) Int64(any any) (int64, error) { if empty.IsNil(any) { return 0, nil diff --git a/util/gconv/internal/converter/converter_maptomaps.go b/util/gconv/internal/converter/converter_maptomaps.go index 0b9fd21074a..3420934b5b9 100644 --- a/util/gconv/internal/converter/converter_maptomaps.go +++ b/util/gconv/internal/converter/converter_maptomaps.go @@ -21,7 +21,9 @@ import ( // // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes // sense only if the item of `params` is type struct. -func (c *Converter) MapToMaps(params any, pointer any, paramKeyToAttrMap map[string]string) (err error) { +func (c *Converter) MapToMaps( + params any, pointer any, paramKeyToAttrMap map[string]string, option MapOption, +) (err error) { // Params and its element type check. var ( paramsRv reflect.Value @@ -103,13 +105,13 @@ func (c *Converter) MapToMaps(params any, pointer any, paramKeyToAttrMap map[str var item reflect.Value if pointerElemType.Kind() == reflect.Ptr { item = reflect.New(pointerElemType.Elem()) - if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, MapOption{}); err != nil { + if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, option); err != nil { return err } pointerSlice.Index(i).Set(item) } else { item = reflect.New(pointerElemType) - if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, MapOption{}); err != nil { + if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, option); err != nil { return err } pointerSlice.Index(i).Set(item.Elem()) diff --git a/util/gconv/internal/converter/converter_rune.go b/util/gconv/internal/converter/converter_rune.go index 1e95807cb3e..e7ea9d5febd 100644 --- a/util/gconv/internal/converter/converter_rune.go +++ b/util/gconv/internal/converter/converter_rune.go @@ -6,6 +6,7 @@ package converter +// Rune converts `any` to rune. func (c *Converter) Rune(any any) (rune, error) { if v, ok := any.(rune); ok { return v, nil @@ -17,6 +18,7 @@ func (c *Converter) Rune(any any) (rune, error) { return v, nil } +// Runes converts `any` to []rune. func (c *Converter) Runes(any any) ([]rune, error) { if v, ok := any.([]rune); ok { return v, nil diff --git a/util/gconv/internal/converter/converter_scan.go b/util/gconv/internal/converter/converter_scan.go index 2e6a5178b7f..003082f3c5e 100644 --- a/util/gconv/internal/converter/converter_scan.go +++ b/util/gconv/internal/converter/converter_scan.go @@ -99,7 +99,7 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err e } // Check if srcValue and dstPointer are the same type, in which case direct assignment can be performed - if ok := doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem); ok { + if ok := c.doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem); ok { return nil } @@ -266,7 +266,9 @@ func (c *Converter) doScanForComplicatedTypes( } if sliceElemKind == reflect.Map { // Convert to slice of maps - return c.MapToMaps(srcValue, dstPointer, keyToAttributeNameMapping) + return c.MapToMaps(srcValue, dstPointer, keyToAttributeNameMapping, MapOption{ + BreakOnError: option.BreakOnError, + }) } // Convert to slice of structs return c.Structs(srcValue, dstPointer, SliceOption{}, StructOption{ @@ -284,7 +286,7 @@ func (c *Converter) doScanForComplicatedTypes( // doConvertWithTypeCheck supports `pointer` in type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct` // for converting. -func doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem reflect.Value) (ok bool) { +func (c *Converter) doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem reflect.Value) (ok bool) { if !dstPointerReflectValueElem.IsValid() || !srcValueReflectValue.IsValid() { return false } diff --git a/util/gconv/internal/converter/converter_struct.go b/util/gconv/internal/converter/converter_struct.go index bfdba5ec48f..0dc48063d8d 100644 --- a/util/gconv/internal/converter/converter_struct.go +++ b/util/gconv/internal/converter/converter_struct.go @@ -96,7 +96,7 @@ func (c *Converter) Struct(params, pointer any, option StructOption) (err error) // If `params` and `pointer` are the same type, the do directly assignment. // For performance enhancement purpose. - if ok = doConvertWithTypeCheck(paramsReflectValue, pointerElemReflectValue); ok { + if ok = c.doConvertWithTypeCheck(paramsReflectValue, pointerElemReflectValue); ok { return nil } diff --git a/util/gconv/internal/converter/converter_uint.go b/util/gconv/internal/converter/converter_uint.go index 74cf7c55069..2055b0c0cb2 100644 --- a/util/gconv/internal/converter/converter_uint.go +++ b/util/gconv/internal/converter/converter_uint.go @@ -18,6 +18,7 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) +// Uint converts `any` to uint. func (c *Converter) Uint(any any) (uint, error) { if empty.IsNil(any) { return 0, nil @@ -29,6 +30,7 @@ func (c *Converter) Uint(any any) (uint, error) { return uint(v), err } +// Uint8 converts `any` to uint8. func (c *Converter) Uint8(any any) (uint8, error) { if empty.IsNil(any) { return 0, nil @@ -40,6 +42,7 @@ func (c *Converter) Uint8(any any) (uint8, error) { return uint8(v), err } +// Uint16 converts `any` to uint16. func (c *Converter) Uint16(any any) (uint16, error) { if empty.IsNil(any) { return 0, nil @@ -51,6 +54,7 @@ func (c *Converter) Uint16(any any) (uint16, error) { return uint16(v), err } +// Uint32 converts `any` to uint32. func (c *Converter) Uint32(any any) (uint32, error) { if empty.IsNil(any) { return 0, nil @@ -62,6 +66,7 @@ func (c *Converter) Uint32(any any) (uint32, error) { return uint32(v), err } +// Uint64 converts `any` to uint64. func (c *Converter) Uint64(any any) (uint64, error) { if empty.IsNil(any) { return 0, nil From 4912659af256d7922b7e3191f989aeee36b18c08 Mon Sep 17 00:00:00 2001 From: John Guo Date: Mon, 3 Mar 2025 14:08:30 +0800 Subject: [PATCH 35/48] up --- net/ghttp/ghttp_z_unit_feature_config_test.go | 6 +- ...ghttp_z_unit_feature_router_strict_test.go | 2 +- util/gconv/gconv_map.go | 12 ++-- util/gconv/gconv_maps.go | 8 ++- util/gconv/gconv_scan.go | 4 +- util/gconv/gconv_slice_any.go | 4 +- util/gconv/gconv_slice_float.go | 8 ++- util/gconv/gconv_slice_int.go | 12 +++- util/gconv/gconv_slice_str.go | 4 +- util/gconv/gconv_slice_uint.go | 12 +++- util/gconv/gconv_struct.go | 3 +- util/gconv/gconv_structs.go | 7 +- .../gconv/internal/converter/converter_map.go | 58 ++++++++-------- .../internal/converter/converter_maptomap.go | 1 + .../internal/converter/converter_scan.go | 29 ++++---- .../internal/converter/converter_slice_any.go | 6 +- .../converter/converter_slice_float.go | 68 +++++++++---------- .../internal/converter/converter_slice_int.go | 48 ++++++------- .../internal/converter/converter_slice_map.go | 2 +- .../internal/converter/converter_slice_str.go | 34 +++++----- .../converter/converter_slice_uint.go | 48 ++++++------- .../internal/converter/converter_struct.go | 25 ++++--- 22 files changed, 220 insertions(+), 181 deletions(-) diff --git a/net/ghttp/ghttp_z_unit_feature_config_test.go b/net/ghttp/ghttp_z_unit_feature_config_test.go index c84cf24255e..306d61e97e4 100644 --- a/net/ghttp/ghttp_z_unit_feature_config_test.go +++ b/net/ghttp/ghttp_z_unit_feature_config_test.go @@ -30,15 +30,15 @@ func Test_ConfigFromMap(t *testing.T) { "readTimeout": "60s", "indexFiles": g.Slice{"index.php", "main.php"}, "errorLogEnabled": true, - "cookieMaxAge": "1y", + "cookieMaxAge": "1d", "cookieSameSite": "lax", "cookieSecure": true, "cookieHttpOnly": true, } config, err := ghttp.ConfigFromMap(m) t.AssertNil(err) - d1, _ := time.ParseDuration(gconv.String(m["readTimeout"])) - d2, _ := time.ParseDuration(gconv.String(m["cookieMaxAge"])) + d1, _ := gtime.ParseDuration(gconv.String(m["readTimeout"])) + d2, _ := gtime.ParseDuration(gconv.String(m["cookieMaxAge"])) t.Assert(config.Address, m["address"]) t.Assert(config.ReadTimeout, d1) t.Assert(config.CookieMaxAge, d2) diff --git a/net/ghttp/ghttp_z_unit_feature_router_strict_test.go b/net/ghttp/ghttp_z_unit_feature_router_strict_test.go index 1944c5fb474..c193c35a4b8 100644 --- a/net/ghttp/ghttp_z_unit_feature_router_strict_test.go +++ b/net/ghttp/ghttp_z_unit_feature_router_strict_test.go @@ -523,7 +523,7 @@ func Test_NullString_Issue3465(t *testing.T) { "name": "null", } - expect1 := `{"code":0,"message":"OK","data":{"name":null}}` + expect1 := `{"code":0,"message":"OK","data":{"name":["null"]}}` t.Assert(client.GetContent(ctx, "/test", data1), expect1) data2 := map[string]any{ diff --git a/util/gconv/gconv_map.go b/util/gconv/gconv_map.go index 1aede25b5e8..04733e8b3e8 100644 --- a/util/gconv/gconv_map.go +++ b/util/gconv/gconv_map.go @@ -23,10 +23,10 @@ func Map(value any, option ...MapOption) map[string]any { // Deprecated: used Map instead. func MapDeep(value any, tags ...string) map[string]any { result, _ := defaultConverter.Map(value, MapOption{ - Deep: true, - OmitEmpty: false, - Tags: tags, - BreakOnError: false, + Deep: true, + OmitEmpty: false, + Tags: tags, + ContinueOnError: true, }) return result } @@ -57,7 +57,9 @@ func MapStrStrDeep(value any, tags ...string) map[string]string { } func getUsedMapOption(option ...MapOption) MapOption { - var usedOption MapOption + var usedOption = MapOption{ + ContinueOnError: true, + } if len(option) > 0 { usedOption = option[0] } diff --git a/util/gconv/gconv_maps.go b/util/gconv/gconv_maps.go index 618ac85de25..b2d57499458 100644 --- a/util/gconv/gconv_maps.go +++ b/util/gconv/gconv_maps.go @@ -22,11 +22,15 @@ func SliceMapDeep(any any) []map[string]any { // Maps converts `value` to []map[string]any. // Note that it automatically checks and converts json string to []map if `value` is string/[]byte. func Maps(value any, option ...MapOption) []map[string]any { - mapOption := MapOption{} + mapOption := MapOption{ + ContinueOnError: true, + } if len(option) > 0 { mapOption = option[0] } - result, _ := defaultConverter.SliceMap(value, SliceOption{}, mapOption) + result, _ := defaultConverter.SliceMap(value, SliceOption{ + ContinueOnError: true, + }, mapOption) return result } diff --git a/util/gconv/gconv_scan.go b/util/gconv/gconv_scan.go index 8edbc0aca46..8d872420863 100644 --- a/util/gconv/gconv_scan.go +++ b/util/gconv/gconv_scan.go @@ -17,7 +17,9 @@ package gconv // The `paramKeyToAttrMap` parameter is used for mapping between attribute names and parameter keys. // TODO: change `paramKeyToAttrMap` to `ScanOption` to be more scalable; add `DeepCopy` option for `ScanOption`. func Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) { - option := ScanOption{} + option := ScanOption{ + ContinueOnError: true, + } if len(paramKeyToAttrMap) > 0 { option.ParamKeyToAttrMap = paramKeyToAttrMap[0] } diff --git a/util/gconv/gconv_slice_any.go b/util/gconv/gconv_slice_any.go index 94436f2f28d..8506f25428d 100644 --- a/util/gconv/gconv_slice_any.go +++ b/util/gconv/gconv_slice_any.go @@ -13,6 +13,8 @@ func SliceAny(any interface{}) []interface{} { // Interfaces converts `any` to []interface{}. func Interfaces(any interface{}) []interface{} { - result, _ := defaultConverter.SliceAny(any, SliceOption{}) + result, _ := defaultConverter.SliceAny(any, SliceOption{ + ContinueOnError: true, + }) return result } diff --git a/util/gconv/gconv_slice_float.go b/util/gconv/gconv_slice_float.go index 7803f2f46f6..32757782f79 100644 --- a/util/gconv/gconv_slice_float.go +++ b/util/gconv/gconv_slice_float.go @@ -28,12 +28,16 @@ func Floats(any interface{}) []float64 { // Float32s converts `any` to []float32. func Float32s(any interface{}) []float32 { - result, _ := defaultConverter.SliceFloat32(any, SliceOption{}) + result, _ := defaultConverter.SliceFloat32(any, SliceOption{ + ContinueOnError: true, + }) return result } // Float64s converts `any` to []float64. func Float64s(any interface{}) []float64 { - result, _ := defaultConverter.SliceFloat64(any, SliceOption{}) + result, _ := defaultConverter.SliceFloat64(any, SliceOption{ + ContinueOnError: true, + }) return result } diff --git a/util/gconv/gconv_slice_int.go b/util/gconv/gconv_slice_int.go index adc48bf0394..dedc634d115 100644 --- a/util/gconv/gconv_slice_int.go +++ b/util/gconv/gconv_slice_int.go @@ -23,18 +23,24 @@ func SliceInt64(any any) []int64 { // Ints converts `any` to []int. func Ints(any any) []int { - result, _ := defaultConverter.SliceInt(any, SliceOption{}) + result, _ := defaultConverter.SliceInt(any, SliceOption{ + ContinueOnError: true, + }) return result } // Int32s converts `any` to []int32. func Int32s(any any) []int32 { - result, _ := defaultConverter.SliceInt32(any, SliceOption{}) + result, _ := defaultConverter.SliceInt32(any, SliceOption{ + ContinueOnError: true, + }) return result } // Int64s converts `any` to []int64. func Int64s(any any) []int64 { - result, _ := defaultConverter.SliceInt64(any, SliceOption{}) + result, _ := defaultConverter.SliceInt64(any, SliceOption{ + ContinueOnError: true, + }) return result } diff --git a/util/gconv/gconv_slice_str.go b/util/gconv/gconv_slice_str.go index 05ee6d02dbd..b475dfb0836 100644 --- a/util/gconv/gconv_slice_str.go +++ b/util/gconv/gconv_slice_str.go @@ -13,6 +13,8 @@ func SliceStr(any interface{}) []string { // Strings converts `any` to []string. func Strings(any interface{}) []string { - result, _ := defaultConverter.SliceStr(any, SliceOption{}) + result, _ := defaultConverter.SliceStr(any, SliceOption{ + ContinueOnError: true, + }) return result } diff --git a/util/gconv/gconv_slice_uint.go b/util/gconv/gconv_slice_uint.go index a3c9f44c455..7ab9b4fdf22 100644 --- a/util/gconv/gconv_slice_uint.go +++ b/util/gconv/gconv_slice_uint.go @@ -23,18 +23,24 @@ func SliceUint64(any interface{}) []uint64 { // Uints converts `any` to []uint. func Uints(any interface{}) []uint { - result, _ := defaultConverter.SliceUint(any, SliceOption{}) + result, _ := defaultConverter.SliceUint(any, SliceOption{ + ContinueOnError: true, + }) return result } // Uint32s converts `any` to []uint32. func Uint32s(any interface{}) []uint32 { - result, _ := defaultConverter.SliceUint32(any, SliceOption{}) + result, _ := defaultConverter.SliceUint32(any, SliceOption{ + ContinueOnError: true, + }) return result } // Uint64s converts `any` to []uint64. func Uint64s(any interface{}) []uint64 { - result, _ := defaultConverter.SliceUint64(any, SliceOption{}) + result, _ := defaultConverter.SliceUint64(any, SliceOption{ + ContinueOnError: true, + }) return result } diff --git a/util/gconv/gconv_struct.go b/util/gconv/gconv_struct.go index 370f6c83aa7..e20b899581d 100644 --- a/util/gconv/gconv_struct.go +++ b/util/gconv/gconv_struct.go @@ -28,7 +28,8 @@ func Struct(params any, pointer any, paramKeyToAttrMap ...map[string]string) (er // The parameter `priorityTag` supports multiple priorityTagAndFieldName that can be joined with char ','. func StructTag(params any, pointer any, priorityTag string) (err error) { option := StructOption{ - PriorityTag: priorityTag, + PriorityTag: priorityTag, + ContinueOnError: true, } return defaultConverter.Struct(params, pointer, option) } diff --git a/util/gconv/gconv_structs.go b/util/gconv/gconv_structs.go index b4c43f1c4cb..3bfd7b42a2b 100644 --- a/util/gconv/gconv_structs.go +++ b/util/gconv/gconv_structs.go @@ -21,7 +21,10 @@ func SliceStruct(params any, pointer any, mapping ...map[string]string) (err err // specified priorityTagAndFieldName for `params` key-value items to struct attribute names mapping. // The parameter `priorityTag` supports multiple priorityTagAndFieldName that can be joined with char ','. func StructsTag(params any, pointer any, priorityTag string) (err error) { - return defaultConverter.Structs(params, pointer, SliceOption{}, StructOption{ - PriorityTag: priorityTag, + return defaultConverter.Structs(params, pointer, SliceOption{ + ContinueOnError: true, + }, StructOption{ + PriorityTag: priorityTag, + ContinueOnError: true, }) } diff --git a/util/gconv/internal/converter/converter_map.go b/util/gconv/internal/converter/converter_map.go index 46e9f27fb7a..1b8b93e4814 100644 --- a/util/gconv/internal/converter/converter_map.go +++ b/util/gconv/internal/converter/converter_map.go @@ -30,9 +30,9 @@ type MapOption struct { // Tags specifies the converted map key name by struct tag name. Tags []string - // BreakOnError specifies whether to break converting the next element - // if one element conversion fails in map. - BreakOnError bool + // ContinueOnError specifies whether to continue converting the next element + // if one element converting fails. + ContinueOnError bool } // Map converts any variable `value` to map[string]any. If the parameter `value` is not a @@ -52,7 +52,7 @@ func (c *Converter) MapStrStr(value any, option MapOption) (map[string]string, e return r, nil } m, err := c.Map(value, option) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } if len(m) > 0 { @@ -62,7 +62,7 @@ func (c *Converter) MapStrStr(value any, option MapOption) (map[string]string, e ) for k, v := range m { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } vMap[k] = s @@ -127,7 +127,7 @@ func (c *Converter) doMapConvert( recursiveOption.Tags = newTags for k, v := range r { s, err := c.String(k) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } dataMap[s], err = c.doMapConvertForMapOrStructValue( @@ -139,14 +139,14 @@ func (c *Converter) doMapConvert( Option: recursiveOption, }, ) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } } case map[interface{}]string: for k, v := range r { s, err := c.String(k) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } dataMap[s] = v @@ -154,7 +154,7 @@ func (c *Converter) doMapConvert( case map[interface{}]int: for k, v := range r { s, err := c.String(k) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } dataMap[s] = v @@ -162,7 +162,7 @@ func (c *Converter) doMapConvert( case map[interface{}]uint: for k, v := range r { s, err := c.String(k) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } dataMap[s] = v @@ -170,7 +170,7 @@ func (c *Converter) doMapConvert( case map[interface{}]float32: for k, v := range r { s, err := c.String(k) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } dataMap[s] = v @@ -178,7 +178,7 @@ func (c *Converter) doMapConvert( case map[interface{}]float64: for k, v := range r { s, err := c.String(k) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } dataMap[s] = v @@ -222,7 +222,7 @@ func (c *Converter) doMapConvert( Option: recursiveOption, }, ) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } } @@ -235,7 +235,7 @@ func (c *Converter) doMapConvert( recursiveOption.Tags = newTags for k, v := range r { s, err := c.String(k) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } dataMap[s], err = c.doMapConvertForMapOrStructValue( @@ -247,14 +247,14 @@ func (c *Converter) doMapConvert( Option: recursiveOption, }, ) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } } case map[int]string: for k, v := range r { s, err := c.String(k) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } dataMap[s] = v @@ -262,7 +262,7 @@ func (c *Converter) doMapConvert( case map[uint]string: for k, v := range r { s, err := c.String(k) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } dataMap[s] = v @@ -291,7 +291,7 @@ func (c *Converter) doMapConvert( length := reflectValue.Len() for i := 0; i < length; i += 2 { s, err := c.String(reflectValue.Index(i).Interface()) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } if i+1 < length { @@ -313,7 +313,7 @@ func (c *Converter) doMapConvert( MustMapReturn: mustMapReturn, }, ) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } if m, ok := convertedValue.(map[string]interface{}); ok { @@ -382,7 +382,7 @@ func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStruc mapValue = mapKeyValue.Interface() } s, err := c.String(mapIter.Key().Interface()) - if err != nil && in.Option.BreakOnError { + if err != nil && !in.Option.ContinueOnError { return nil, err } dataMap[s], err = c.doMapConvertForMapOrStructValue( @@ -394,7 +394,7 @@ func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStruc Option: in.Option, }, ) - if err != nil && in.Option.BreakOnError { + if err != nil && !in.Option.ContinueOnError { return nil, err } } @@ -416,7 +416,7 @@ func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStruc Option: in.Option, }, ) - if err != nil && in.Option.BreakOnError { + if err != nil && !in.Option.ContinueOnError { return nil, err } } else { @@ -510,7 +510,7 @@ func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStruc Option: in.Option, }, ) - if err != nil && in.Option.BreakOnError { + if err != nil && !in.Option.ContinueOnError { return nil, err } if m, ok := anonymousValue.(map[string]interface{}); ok { @@ -532,7 +532,7 @@ func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStruc Option: in.Option, }, ) - if err != nil && in.Option.BreakOnError { + if err != nil && !in.Option.ContinueOnError { return nil, err } @@ -546,7 +546,7 @@ func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStruc Option: in.Option, }, ) - if err != nil && in.Option.BreakOnError { + if err != nil && !in.Option.ContinueOnError { return nil, err } } @@ -569,7 +569,7 @@ func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStruc Option: in.Option, }, ) - if err != nil && in.Option.BreakOnError { + if err != nil && !in.Option.ContinueOnError { return nil, err } } @@ -581,7 +581,7 @@ func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStruc ) for mapIter.Next() { s, err := c.String(mapIter.Key().Interface()) - if err != nil && in.Option.BreakOnError { + if err != nil && !in.Option.ContinueOnError { return nil, err } nestedMap[s], err = c.doMapConvertForMapOrStructValue( @@ -593,7 +593,7 @@ func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStruc Option: in.Option, }, ) - if err != nil && in.Option.BreakOnError { + if err != nil && !in.Option.ContinueOnError { return nil, err } } @@ -634,7 +634,7 @@ func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStruc RecursiveOption: in.RecursiveType == RecursiveTypeTrue, Option: in.Option, }) - if err != nil && in.Option.BreakOnError { + if err != nil && !in.Option.ContinueOnError { return nil, err } } diff --git a/util/gconv/internal/converter/converter_maptomap.go b/util/gconv/internal/converter/converter_maptomap.go index d1d4cb1cf05..4fb75179b2c 100644 --- a/util/gconv/internal/converter/converter_maptomap.go +++ b/util/gconv/internal/converter/converter_maptomap.go @@ -97,6 +97,7 @@ func (c *Converter) MapToMap( structOption := StructOption{ ParamKeyToAttrMap: mapping, PriorityTag: "", + ContinueOnError: option.ContinueOnError, } if err = c.Struct(paramsRv.MapIndex(key).Interface(), mapValue, structOption); err != nil { return err diff --git a/util/gconv/internal/converter/converter_scan.go b/util/gconv/internal/converter/converter_scan.go index 003082f3c5e..2fe16fab340 100644 --- a/util/gconv/internal/converter/converter_scan.go +++ b/util/gconv/internal/converter/converter_scan.go @@ -20,9 +20,9 @@ type ScanOption struct { // ParamKeyToAttrMap specifies the mapping between parameter keys and struct attribute names. ParamKeyToAttrMap map[string]string - // BreakOnError specifies whether to break converting the next element - // if one element conversion fails. - BreakOnError bool + // ContinueOnError specifies whether to continue converting the next element + // if one element converting fails. + ContinueOnError bool } // Scan automatically checks the type of `pointer` and converts `params` to `pointer`. @@ -107,7 +107,7 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err e switch dstPointerReflectValueElemKind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: v, err := c.Int64(srcValue) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return err } dstPointerReflectValueElem.SetInt(v) @@ -115,7 +115,7 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err e case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: v, err := c.Uint64(srcValue) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return err } dstPointerReflectValueElem.SetUint(v) @@ -123,7 +123,7 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err e case reflect.Float32, reflect.Float64: v, err := c.Float64(srcValue) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return err } dstPointerReflectValueElem.SetFloat(v) @@ -131,7 +131,7 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err e case reflect.String: v, err := c.String(srcValue) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return err } dstPointerReflectValueElem.SetString(v) @@ -139,7 +139,7 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err e case reflect.Bool: v, err := c.Bool(srcValue) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return err } dstPointerReflectValueElem.SetBool(v) @@ -172,31 +172,31 @@ func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err e switch dstElemType.Kind() { case reflect.String: v, err := c.String(srcElem) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return err } newSlice.Index(i).SetString(v) case reflect.Int: v, err := c.Int64(srcElem) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return err } newSlice.Index(i).SetInt(v) case reflect.Int64: v, err := c.Int64(srcElem) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return err } newSlice.Index(i).SetInt(v) case reflect.Float64: v, err := c.Float64(srcElem) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return err } newSlice.Index(i).SetFloat(v) case reflect.Bool: v, err := c.Bool(srcElem) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return err } newSlice.Index(i).SetBool(v) @@ -267,7 +267,7 @@ func (c *Converter) doScanForComplicatedTypes( if sliceElemKind == reflect.Map { // Convert to slice of maps return c.MapToMaps(srcValue, dstPointer, keyToAttributeNameMapping, MapOption{ - BreakOnError: option.BreakOnError, + ContinueOnError: option.ContinueOnError, }) } // Convert to slice of structs @@ -279,6 +279,7 @@ func (c *Converter) doScanForComplicatedTypes( structOption := StructOption{ ParamKeyToAttrMap: keyToAttributeNameMapping, PriorityTag: "", + ContinueOnError: option.ContinueOnError, } return c.Struct(srcValue, dstPointer, structOption) } diff --git a/util/gconv/internal/converter/converter_slice_any.go b/util/gconv/internal/converter/converter_slice_any.go index fbbde71b1c3..8a0402ec1cb 100644 --- a/util/gconv/internal/converter/converter_slice_any.go +++ b/util/gconv/internal/converter/converter_slice_any.go @@ -17,9 +17,9 @@ import ( // SliceOption is the option for Slice type converting. type SliceOption struct { - // BreakOnError specifies whether to break converting the next element - // if one element conversion fails in slice. - BreakOnError bool + // ContinueOnError specifies whether to continue converting the next element + // if one element converting fails. + ContinueOnError bool } // SliceAny converts `any` to []any. diff --git a/util/gconv/internal/converter/converter_slice_float.go b/util/gconv/internal/converter/converter_slice_float.go index 0019e790c71..27d59c6abbc 100644 --- a/util/gconv/internal/converter/converter_slice_float.go +++ b/util/gconv/internal/converter/converter_slice_float.go @@ -31,7 +31,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -40,7 +40,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -49,7 +49,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -58,7 +58,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -67,7 +67,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -76,7 +76,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -85,7 +85,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -99,7 +99,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -116,7 +116,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 } if utils.IsNumeric(value) { f, err = c.Float32(value) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []float32{f}, err @@ -125,7 +125,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -134,7 +134,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -143,7 +143,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -152,7 +152,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -163,7 +163,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -172,7 +172,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 array = make([]float32, len(value)) for k, v := range value { f, err = c.Float32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -197,7 +197,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 ) for i := 0; i < length; i++ { f, err = c.Float32(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } slice[i] = f @@ -209,7 +209,7 @@ func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32 return []float32{}, err } f, err = c.Float32(any) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []float32{f}, err @@ -231,7 +231,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -240,7 +240,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -249,7 +249,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -258,7 +258,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -267,7 +267,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -276,7 +276,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -285,7 +285,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -299,7 +299,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -316,7 +316,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 } if utils.IsNumeric(value) { f, err = c.Float64(value) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []float64{f}, err @@ -325,7 +325,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -334,7 +334,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -343,7 +343,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -352,7 +352,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -361,7 +361,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -372,7 +372,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 array = make([]float64, len(value)) for k, v := range value { f, err = c.Float64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = f @@ -397,7 +397,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 ) for i := 0; i < length; i++ { f, err = c.Float64(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } slice[i] = f @@ -409,7 +409,7 @@ func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64 return []float64{}, err } f, err = c.Float64(any) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []float64{f}, err diff --git a/util/gconv/internal/converter/converter_slice_int.go b/util/gconv/internal/converter/converter_slice_int.go index 653f3701470..b1a769d275a 100644 --- a/util/gconv/internal/converter/converter_slice_int.go +++ b/util/gconv/internal/converter/converter_slice_int.go @@ -31,7 +31,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) { array = make([]int, len(value)) for k, v := range value { ii, err = c.Int(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ii @@ -85,7 +85,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) { } if utils.IsNumeric(value) { ii, err = c.Int(value) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []int{ii}, err @@ -118,7 +118,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) { array = make([]int, len(value)) for k, v := range value { ii, err = c.Int(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ii @@ -127,7 +127,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) { array = make([]int, len(value)) for k, v := range value { ii, err = c.Int(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ii @@ -136,7 +136,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) { array = make([]int, len(value)) for k, v := range value { ii, err = c.Int(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ii @@ -145,7 +145,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) { array = make([]int, len(value)) for k, v := range value { ii, err = c.Int(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ii @@ -170,7 +170,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) { ) for i := 0; i < length; i++ { ii, err = c.Int(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } slice[i] = ii @@ -182,7 +182,7 @@ func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) { return []int{}, err } ii, err = c.Int(any) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []int{ii}, err @@ -204,7 +204,7 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) { array = make([]int32, len(value)) for k, v := range value { ii, err = c.Int32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ii @@ -258,7 +258,7 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) { } if utils.IsNumeric(value) { ii, err = c.Int32(value) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []int32{ii}, err @@ -291,7 +291,7 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) { array = make([]int32, len(value)) for k, v := range value { ii, err = c.Int32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ii @@ -300,7 +300,7 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) { array = make([]int32, len(value)) for k, v := range value { ii, err = c.Int32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ii @@ -309,7 +309,7 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) { array = make([]int32, len(value)) for k, v := range value { ii, err = c.Int32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ii @@ -318,7 +318,7 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) { array = make([]int32, len(value)) for k, v := range value { ii, err = c.Int32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ii @@ -343,7 +343,7 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) { ) for i := 0; i < length; i++ { ii, err = c.Int32(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } slice[i] = ii @@ -355,7 +355,7 @@ func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) { return []int32{}, err } ii, err = c.Int32(any) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []int32{ii}, err @@ -377,7 +377,7 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) { array = make([]int64, len(value)) for k, v := range value { ii, err = c.Int64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ii @@ -431,7 +431,7 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) { } if utils.IsNumeric(value) { ii, err = c.Int64(value) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []int64{ii}, err @@ -464,7 +464,7 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) { array = make([]int64, len(value)) for k, v := range value { ii, err = c.Int64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ii @@ -473,7 +473,7 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) { array = make([]int64, len(value)) for k, v := range value { ii, err = c.Int64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ii @@ -482,7 +482,7 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) { array = make([]int64, len(value)) for k, v := range value { ii, err = c.Int64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ii @@ -491,7 +491,7 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) { array = make([]int64, len(value)) for k, v := range value { ii, err = c.Int64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ii @@ -516,7 +516,7 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) { ) for i := 0; i < length; i++ { ii, err = c.Int64(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } slice[i] = ii @@ -528,7 +528,7 @@ func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) { return []int64{}, err } ii, err = c.Int64(any) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []int64{ii}, err diff --git a/util/gconv/internal/converter/converter_slice_map.go b/util/gconv/internal/converter/converter_slice_map.go index c14f48157c8..837f51ab945 100644 --- a/util/gconv/internal/converter/converter_slice_map.go +++ b/util/gconv/internal/converter/converter_slice_map.go @@ -49,7 +49,7 @@ func (c *Converter) SliceMap(value any, sliceOption SliceOption, mapOption MapOp list := make([]map[string]any, len(array)) for k, v := range array { m, err := c.Map(v, mapOption) - if err != nil && sliceOption.BreakOnError { + if err != nil && !sliceOption.ContinueOnError { return nil, err } list[k] = m diff --git a/util/gconv/internal/converter/converter_slice_str.go b/util/gconv/internal/converter/converter_slice_str.go index 850c68382f2..e95f70b8a27 100644 --- a/util/gconv/internal/converter/converter_slice_str.go +++ b/util/gconv/internal/converter/converter_slice_str.go @@ -30,7 +30,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = s @@ -39,7 +39,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = s @@ -48,7 +48,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = s @@ -57,7 +57,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = s @@ -66,7 +66,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = s @@ -75,7 +75,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = s @@ -89,7 +89,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = s @@ -110,7 +110,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = s @@ -119,7 +119,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = s @@ -128,7 +128,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = s @@ -137,7 +137,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = s @@ -146,7 +146,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = s @@ -155,7 +155,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = s @@ -164,7 +164,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = s @@ -175,7 +175,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err array = make([]string, len(value)) for k, v := range value { s, err = c.String(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = s @@ -200,7 +200,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err ) for i := 0; i < length; i++ { s, err = c.String(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } slice[i] = s @@ -212,7 +212,7 @@ func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, err return []string{}, err } s, err = c.String(any) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []string{s}, err diff --git a/util/gconv/internal/converter/converter_slice_uint.go b/util/gconv/internal/converter/converter_slice_uint.go index 22b749ce82b..173c96469cd 100644 --- a/util/gconv/internal/converter/converter_slice_uint.go +++ b/util/gconv/internal/converter/converter_slice_uint.go @@ -31,7 +31,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro array = make([]uint, len(value)) for k, v := range value { ui, err = c.Uint(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ui @@ -80,7 +80,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro } if utils.IsNumeric(value) { ui, err = c.Uint(value) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []uint{ui}, err @@ -113,7 +113,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro array = make([]uint, len(value)) for k, v := range value { ui, err = c.Uint(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ui @@ -122,7 +122,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro array = make([]uint, len(value)) for k, v := range value { ui, err = c.Uint(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ui @@ -131,7 +131,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro array = make([]uint, len(value)) for k, v := range value { ui, err = c.Uint(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ui @@ -140,7 +140,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro array = make([]uint, len(value)) for k, v := range value { ui, err = c.Uint(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ui @@ -168,7 +168,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro ) for i := 0; i < length; i++ { ui, err = c.Uint(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } slice[i] = ui @@ -180,7 +180,7 @@ func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, erro return []uint{}, err } ui, err = c.Uint(any) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []uint{ui}, err @@ -202,7 +202,7 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32, array = make([]uint32, len(value)) for k, v := range value { ui, err = c.Uint32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ui @@ -254,7 +254,7 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32, } if utils.IsNumeric(value) { ui, err = c.Uint32(value) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []uint32{ui}, err @@ -284,7 +284,7 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32, array = make([]uint32, len(value)) for k, v := range value { ui, err = c.Uint32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ui @@ -293,7 +293,7 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32, array = make([]uint32, len(value)) for k, v := range value { ui, err = c.Uint32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ui @@ -302,7 +302,7 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32, array = make([]uint32, len(value)) for k, v := range value { ui, err = c.Uint32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ui @@ -311,7 +311,7 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32, array = make([]uint32, len(value)) for k, v := range value { ui, err = c.Uint32(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ui @@ -338,7 +338,7 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32, ) for i := 0; i < length; i++ { ui, err = c.Uint32(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } slice[i] = ui @@ -350,7 +350,7 @@ func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32, return []uint32{}, err } ui, err = c.Uint32(any) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []uint32{ui}, err @@ -372,7 +372,7 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64, array = make([]uint64, len(value)) for k, v := range value { ui, err = c.Uint64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ui @@ -424,7 +424,7 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64, } if utils.IsNumeric(value) { ui, err = c.Uint64(value) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []uint64{ui}, err @@ -454,7 +454,7 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64, array = make([]uint64, len(value)) for k, v := range value { ui, err = c.Uint64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ui @@ -463,7 +463,7 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64, array = make([]uint64, len(value)) for k, v := range value { ui, err = c.Uint64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ui @@ -472,7 +472,7 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64, array = make([]uint64, len(value)) for k, v := range value { ui, err = c.Uint64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ui @@ -481,7 +481,7 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64, array = make([]uint64, len(value)) for k, v := range value { ui, err = c.Uint64(v) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } array[k] = ui @@ -507,7 +507,7 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64, ) for i := 0; i < length; i++ { ui, err = c.Uint64(originValueAndKind.OriginValue.Index(i).Interface()) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } slice[i] = ui @@ -519,7 +519,7 @@ func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64, return []uint64{}, err } ui, err = c.Uint64(any) - if err != nil && option.BreakOnError { + if err != nil && !option.ContinueOnError { return nil, err } return []uint64{ui}, err diff --git a/util/gconv/internal/converter/converter_struct.go b/util/gconv/internal/converter/converter_struct.go index 0dc48063d8d..9617441ce65 100644 --- a/util/gconv/internal/converter/converter_struct.go +++ b/util/gconv/internal/converter/converter_struct.go @@ -26,6 +26,10 @@ type StructOption struct { // PriorityTag is the priority tag for struct converting. PriorityTag string + + // ContinueOnError specifies whether to continue converting the next element + // if one element converting fails. + ContinueOnError bool } // Struct is the core internal converting function for any data to struct. @@ -207,8 +211,9 @@ func (c *Converter) Struct(params, pointer any, option StructOption) (err error) return nil } return c.bindStructWithLoopFieldInfos( - paramsMap, pointerElemReflectValue, option.ParamKeyToAttrMap, + paramsMap, pointerElemReflectValue, usedParamsKeyOrTagNameMap, cachedStructInfo, + option, ) } @@ -231,9 +236,9 @@ func (c *Converter) setOtherSameNameField( func (c *Converter) bindStructWithLoopFieldInfos( paramsMap map[string]any, structValue reflect.Value, - paramKeyToAttrMap map[string]string, usedParamsKeyOrTagNameMap map[string]struct{}, cachedStructInfo *structcache.CachedStructInfo, + option StructOption, ) (err error) { var ( cachedFieldInfo *structcache.CachedFieldInfo @@ -251,15 +256,15 @@ func (c *Converter) bindStructWithLoopFieldInfos( } fieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue) if err = c.bindVarToStructField( - cachedFieldInfo, fieldValue, paramValue, paramKeyToAttrMap, - ); err != nil { + cachedFieldInfo, fieldValue, paramValue, option.ParamKeyToAttrMap, + ); err != nil && !option.ContinueOnError { return err } // handle same field name in nested struct. if len(cachedFieldInfo.OtherSameNameField) > 0 { if err = c.setOtherSameNameField( - cachedFieldInfo, paramValue, structValue, paramKeyToAttrMap, - ); err != nil { + cachedFieldInfo, paramValue, structValue, option.ParamKeyToAttrMap, + ); err != nil && !option.ContinueOnError { return err } } @@ -284,15 +289,15 @@ func (c *Converter) bindStructWithLoopFieldInfos( fieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue) if paramValue != nil { if err = c.bindVarToStructField( - cachedFieldInfo, fieldValue, paramValue, paramKeyToAttrMap, - ); err != nil { + cachedFieldInfo, fieldValue, paramValue, option.ParamKeyToAttrMap, + ); err != nil && !option.ContinueOnError { return err } // handle same field name in nested struct. if len(cachedFieldInfo.OtherSameNameField) > 0 { if err = c.setOtherSameNameField( - cachedFieldInfo, paramValue, structValue, paramKeyToAttrMap, - ); err != nil { + cachedFieldInfo, paramValue, structValue, option.ParamKeyToAttrMap, + ); err != nil && !option.ContinueOnError { return err } } From 19446fc2c7a6bf168bae1e6bd09e5f3890677163 Mon Sep 17 00:00:00 2001 From: John Guo Date: Mon, 3 Mar 2025 14:12:18 +0800 Subject: [PATCH 36/48] up --- database/gdb/gdb_type_record.go | 3 ++- database/gdb/gdb_type_result.go | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/database/gdb/gdb_type_record.go b/database/gdb/gdb_type_record.go index a32807dcfc9..93470551026 100644 --- a/database/gdb/gdb_type_record.go +++ b/database/gdb/gdb_type_record.go @@ -54,7 +54,8 @@ func (r Record) Struct(pointer interface{}) error { return nil } return converter.Struct(r, pointer, gconv.StructOption{ - PriorityTag: OrmTagForStruct, + PriorityTag: OrmTagForStruct, + ContinueOnError: true, }) } diff --git a/database/gdb/gdb_type_result.go b/database/gdb/gdb_type_result.go index 60976d30e96..8c02d828c8c 100644 --- a/database/gdb/gdb_type_result.go +++ b/database/gdb/gdb_type_result.go @@ -200,7 +200,12 @@ func (r Result) Structs(pointer interface{}) (err error) { } return nil } - return converter.Structs(r, pointer, gconv.SliceOption{}, gconv.StructOption{ - PriorityTag: OrmTagForStruct, - }) + var ( + sliceOption = gconv.SliceOption{ContinueOnError: true} + mapOption = gconv.StructOption{ + PriorityTag: OrmTagForStruct, + ContinueOnError: true, + } + ) + return converter.Structs(r, pointer, sliceOption, mapOption) } From 9546cd6b0a0203c66c86bac6fc4961035f118f36 Mon Sep 17 00:00:00 2001 From: John Guo Date: Mon, 3 Mar 2025 14:29:56 +0800 Subject: [PATCH 37/48] up --- database/gdb/gdb_converter.go | 7 +- util/gconv/gconv.go | 7 +- util/gconv/gconv_convert.go | 14 ++- .../internal/converter/converter_convert.go | 90 ++++++++++--------- .../internal/converter/converter_maptomap.go | 33 ++++--- .../internal/converter/converter_struct.go | 49 ++++++---- 6 files changed, 122 insertions(+), 78 deletions(-) diff --git a/database/gdb/gdb_converter.go b/database/gdb/gdb_converter.go index f2c96bebccc..486ca61d5de 100644 --- a/database/gdb/gdb_converter.go +++ b/database/gdb/gdb_converter.go @@ -61,7 +61,12 @@ func sliceTypeConverterFunc(from any, to reflect.Value) (err error) { fromType := reflect.TypeOf(fromVal) switch fromType.Kind() { case reflect.Slice: - dv, err := converter.ConvertWithTypeName(fromVal, to.Type().String()) + convertOption := gconv.ConvertOption{ + SliceOption: gconv.SliceOption{ContinueOnError: true}, + MapOption: gconv.MapOption{ContinueOnError: true}, + StructOption: gconv.StructOption{ContinueOnError: true}, + } + dv, err := converter.ConvertWithTypeName(fromVal, to.Type().String(), convertOption) if err != nil { return err } diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index 478a796a0cd..d40764d48b5 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -103,8 +103,8 @@ type ConverterForStruct interface { // ConverterForConvert is the converting interface for custom converting. type ConverterForConvert interface { - ConvertWithRefer(fromValue, referValue any, extraParams ...any) (any, error) - ConvertWithTypeName(fromValue any, toTypeName string, extraParams ...any) (any, error) + ConvertWithRefer(fromValue, referValue any, option ConvertOption) (any, error) + ConvertWithTypeName(fromValue any, toTypeName string, option ConvertOption) (any, error) } // ConverterForRegister is the converting interface for custom converter registration. @@ -128,6 +128,9 @@ type ( // StructOption is the option for Struct converting. StructOption = converter.StructOption + + // ConvertOption is the option for converting. + ConvertOption = converter.ConvertOption ) // IUnmarshalValue is the interface for custom defined types customizing value assignment. diff --git a/util/gconv/gconv_convert.go b/util/gconv/gconv_convert.go index 134651aca0e..eb47a6d4b93 100644 --- a/util/gconv/gconv_convert.go +++ b/util/gconv/gconv_convert.go @@ -11,7 +11,12 @@ package gconv // The optional parameter `extraParams` is used for additional necessary parameter for this conversion. // It supports common basic types conversion as its conversion based on type name string. func Convert(fromValue any, toTypeName string, extraParams ...any) any { - result, _ := defaultConverter.ConvertWithTypeName(fromValue, toTypeName, extraParams...) + result, _ := defaultConverter.ConvertWithTypeName(fromValue, toTypeName, ConvertOption{ + ExtraParams: extraParams, + SliceOption: SliceOption{ContinueOnError: true}, + MapOption: MapOption{ContinueOnError: true}, + StructOption: StructOption{ContinueOnError: true}, + }) return result } @@ -20,6 +25,11 @@ func Convert(fromValue any, toTypeName string, extraParams ...any) any { // The optional parameter `extraParams` is used for additional necessary parameter for this conversion. // It supports common basic types conversion as its conversion based on type name string. func ConvertWithRefer(fromValue any, referValue any, extraParams ...any) any { - result, _ := defaultConverter.ConvertWithRefer(fromValue, referValue, extraParams...) + result, _ := defaultConverter.ConvertWithRefer(fromValue, referValue, ConvertOption{ + ExtraParams: extraParams, + SliceOption: SliceOption{ContinueOnError: true}, + MapOption: MapOption{ContinueOnError: true}, + StructOption: StructOption{ContinueOnError: true}, + }) return result } diff --git a/util/gconv/internal/converter/converter_convert.go b/util/gconv/internal/converter/converter_convert.go index 5668a6b349a..3d367a4692f 100644 --- a/util/gconv/internal/converter/converter_convert.go +++ b/util/gconv/internal/converter/converter_convert.go @@ -14,45 +14,49 @@ import ( "github.com/gogf/gf/v2/os/gtime" ) +// ConvertOption is the option for converting. +type ConvertOption struct { + // ExtraParams are extra values for implementing the converting. + ExtraParams []any + SliceOption SliceOption + MapOption MapOption + StructOption StructOption +} + // ConvertWithTypeName converts the variable `fromValue` to the type `toTypeName`, the type `toTypeName` is specified by string. -// -// The optional parameter `extraParams` is used for additional necessary parameter for this conversion. -// It supports common basic types conversion as its conversion based on type name string. -func (c *Converter) ConvertWithTypeName(fromValue any, toTypeName string, extraParams ...any) (any, error) { +func (c *Converter) ConvertWithTypeName(fromValue any, toTypeName string, option ConvertOption) (any, error) { return c.doConvert( doConvertInput{ FromValue: fromValue, ToTypeName: toTypeName, ReferValue: nil, - Extra: extraParams, }, + option, ) } // ConvertWithRefer converts the variable `fromValue` to the type referred by value `referValue`. -// -// The optional parameter `extraParams` is used for additional necessary parameter for this conversion. -// It supports common basic types conversion as its conversion based on type name string. -func (c *Converter) ConvertWithRefer(fromValue, referValue any, extraParams ...any) (any, error) { +func (c *Converter) ConvertWithRefer(fromValue, referValue any, option ConvertOption) (any, error) { var referValueRf reflect.Value if v, ok := referValue.(reflect.Value); ok { referValueRf = v } else { referValueRf = reflect.ValueOf(referValue) } - return c.doConvert(doConvertInput{ - FromValue: fromValue, - ToTypeName: referValueRf.Type().String(), - ReferValue: referValue, - Extra: extraParams, - }) + return c.doConvert( + doConvertInput{ + FromValue: fromValue, + ToTypeName: referValueRf.Type().String(), + ReferValue: referValue, + }, + option, + ) } type doConvertInput struct { FromValue any // Value that is converted from. ToTypeName string // Target value type name in string. ReferValue any // Referred value, a value in type `ToTypeName`. Note that its type might be reflect.Value. - Extra []any // Extra values for implementing the converting. // Marks that the value is already converted and set to `ReferValue`. Caller can ignore the returned result. // It is an attribute for internal usage purpose. @@ -60,7 +64,7 @@ type doConvertInput struct { } // doConvert does commonly use types converting. -func (c *Converter) doConvert(in doConvertInput) (convertedValue any, err error) { +func (c *Converter) doConvert(in doConvertInput, option ConvertOption) (convertedValue any, err error) { switch in.ToTypeName { case "int": return c.Int(in.FromValue) @@ -233,29 +237,29 @@ func (c *Converter) doConvert(in doConvertInput) (convertedValue any, err error) case "[]byte": return c.Bytes(in.FromValue) case "[]int": - return c.SliceInt(in.FromValue, SliceOption{}) + return c.SliceInt(in.FromValue, option.SliceOption) case "[]int32": - return c.SliceInt32(in.FromValue, SliceOption{}) + return c.SliceInt32(in.FromValue, option.SliceOption) case "[]int64": - return c.SliceInt64(in.FromValue, SliceOption{}) + return c.SliceInt64(in.FromValue, option.SliceOption) case "[]uint": - return c.SliceUint(in.FromValue, SliceOption{}) + return c.SliceUint(in.FromValue, option.SliceOption) case "[]uint8": return c.Bytes(in.FromValue) case "[]uint32": - return c.SliceUint32(in.FromValue, SliceOption{}) + return c.SliceUint32(in.FromValue, option.SliceOption) case "[]uint64": - return c.SliceUint64(in.FromValue, SliceOption{}) + return c.SliceUint64(in.FromValue, option.SliceOption) case "[]float32": - return c.SliceFloat32(in.FromValue, SliceOption{}) + return c.SliceFloat32(in.FromValue, option.SliceOption) case "[]float64": - return c.SliceFloat64(in.FromValue, SliceOption{}) + return c.SliceFloat64(in.FromValue, option.SliceOption) case "[]string": - return c.SliceStr(in.FromValue, SliceOption{}) + return c.SliceStr(in.FromValue, option.SliceOption) case "Time", "time.Time": - if len(in.Extra) > 0 { - s, err := c.String(in.Extra[0]) + if len(option.ExtraParams) > 0 { + s, err := c.String(option.ExtraParams[0]) if err != nil { return nil, err } @@ -264,8 +268,8 @@ func (c *Converter) doConvert(in doConvertInput) (convertedValue any, err error) return c.Time(in.FromValue) case "*time.Time": var v time.Time - if len(in.Extra) > 0 { - s, err := c.String(in.Extra[0]) + if len(option.ExtraParams) > 0 { + s, err := c.String(option.ExtraParams[0]) if err != nil { return time.Time{}, err } @@ -285,8 +289,8 @@ func (c *Converter) doConvert(in doConvertInput) (convertedValue any, err error) return &v, nil case "GTime", "gtime.Time": - if len(in.Extra) > 0 { - s, err := c.String(in.Extra[0]) + if len(option.ExtraParams) > 0 { + s, err := c.String(option.ExtraParams[0]) if err != nil { return *gtime.New(), err } @@ -308,8 +312,8 @@ func (c *Converter) doConvert(in doConvertInput) (convertedValue any, err error) } return *gtime.New(), nil case "*gtime.Time": - if len(in.Extra) > 0 { - s, err := c.String(in.Extra[0]) + if len(option.ExtraParams) > 0 { + s, err := c.String(option.ExtraParams[0]) if err != nil { return gtime.New(), err } @@ -344,13 +348,13 @@ func (c *Converter) doConvert(in doConvertInput) (convertedValue any, err error) return &v, nil case "map[string]string": - return c.MapStrStr(in.FromValue, MapOption{}) + return c.MapStrStr(in.FromValue, option.MapOption) case "map[string]interface {}": - return c.Map(in.FromValue, MapOption{}) + return c.Map(in.FromValue, option.MapOption) case "[]map[string]interface {}": - return c.SliceMap(in.FromValue, SliceOption{}, MapOption{}) + return c.SliceMap(in.FromValue, option.SliceOption, option.MapOption) case "RawMessage", "json.RawMessage": // issue 3449 @@ -387,7 +391,7 @@ func (c *Converter) doConvert(in doConvertInput) (convertedValue any, err error) defer func() { if recover() != nil { in.alreadySetToReferValue = false - if err := c.bindVarToReflectValue(referReflectValue, in.FromValue, nil); err == nil { + if err = c.bindVarToReflectValue(referReflectValue, in.FromValue, option.StructOption); err == nil { in.alreadySetToReferValue = true convertedValue = referReflectValue.Interface() } @@ -410,7 +414,7 @@ func (c *Converter) doConvert(in doConvertInput) (convertedValue any, err error) default: in.ToTypeName = originType.Kind().String() in.ReferValue = nil - result, err := c.doConvert(in) + result, err := c.doConvert(in, option) if err != nil { return nil, err } @@ -423,7 +427,7 @@ func (c *Converter) doConvert(in doConvertInput) (convertedValue any, err error) case reflect.Map: var targetValue = reflect.New(referReflectValue.Type()).Elem() - if err = c.MapToMap(in.FromValue, targetValue, nil, MapOption{}); err == nil { + if err = c.MapToMap(in.FromValue, targetValue, nil, option.MapOption); err == nil { in.alreadySetToReferValue = true } return targetValue.Interface(), nil @@ -434,7 +438,7 @@ func (c *Converter) doConvert(in doConvertInput) (convertedValue any, err error) in.ToTypeName = referReflectValue.Kind().String() in.ReferValue = nil in.alreadySetToReferValue = true - result, err := c.doConvert(in) + result, err := c.doConvert(in, option) if err != nil { return nil, err } @@ -445,8 +449,8 @@ func (c *Converter) doConvert(in doConvertInput) (convertedValue any, err error) } } -func (c *Converter) doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput) error { - convertedValue, err := c.doConvert(in) +func (c *Converter) doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput, option ConvertOption) error { + convertedValue, err := c.doConvert(in, option) if err != nil { return err } diff --git a/util/gconv/internal/converter/converter_maptomap.go b/util/gconv/internal/converter/converter_maptomap.go index 4fb75179b2c..2aafabca712 100644 --- a/util/gconv/internal/converter/converter_maptomap.go +++ b/util/gconv/internal/converter/converter_maptomap.go @@ -85,6 +85,11 @@ func (c *Converter) MapToMap( pointerValueType = pointerRv.Type().Elem() pointerValueKind = pointerValueType.Kind() dataMap = reflect.MakeMapWithSize(pointerRv.Type(), len(paramsKeys)) + convertOption = ConvertOption{ + StructOption: StructOption{ContinueOnError: option.ContinueOnError}, + SliceOption: SliceOption{ContinueOnError: option.ContinueOnError}, + MapOption: option, + } ) // Retrieve the true element type of target map. if pointerValueKind == reflect.Ptr { @@ -103,23 +108,27 @@ func (c *Converter) MapToMap( return err } default: - convertResult, err := c.doConvert(doConvertInput{ - FromValue: paramsRv.MapIndex(key).Interface(), - ToTypeName: pointerValueType.String(), - ReferValue: mapValue, - Extra: nil, - }) + convertResult, err := c.doConvert( + doConvertInput{ + FromValue: paramsRv.MapIndex(key).Interface(), + ToTypeName: pointerValueType.String(), + ReferValue: mapValue, + }, + convertOption, + ) if err != nil { return err } mapValue.Set(reflect.ValueOf(convertResult)) } - convertResult, err := c.doConvert(doConvertInput{ - FromValue: key.Interface(), - ToTypeName: pointerKeyType.Name(), - ReferValue: reflect.New(pointerKeyType).Elem().Interface(), - Extra: nil, - }) + convertResult, err := c.doConvert( + doConvertInput{ + FromValue: key.Interface(), + ToTypeName: pointerKeyType.Name(), + ReferValue: reflect.New(pointerKeyType).Elem().Interface(), + }, + convertOption, + ) if err != nil { return err } diff --git a/util/gconv/internal/converter/converter_struct.go b/util/gconv/internal/converter/converter_struct.go index 9617441ce65..709b9e7ad68 100644 --- a/util/gconv/internal/converter/converter_struct.go +++ b/util/gconv/internal/converter/converter_struct.go @@ -192,13 +192,13 @@ func (c *Converter) Struct(params, pointer any, option StructOption) (err error) cachedFieldInfo, fieldValue, paramsValue, - option.ParamKeyToAttrMap, + option, ); err != nil { return err } if len(cachedFieldInfo.OtherSameNameField) > 0 { if err = c.setOtherSameNameField( - cachedFieldInfo, paramsValue, pointerReflectValue, option.ParamKeyToAttrMap, + cachedFieldInfo, paramsValue, pointerReflectValue, option, ); err != nil { return err } @@ -221,12 +221,12 @@ func (c *Converter) setOtherSameNameField( cachedFieldInfo *structcache.CachedFieldInfo, srcValue any, structValue reflect.Value, - paramKeyToAttrMap map[string]string, + option StructOption, ) (err error) { // loop the same field name of all sub attributes. for _, otherFieldInfo := range cachedFieldInfo.OtherSameNameField { fieldValue := cachedFieldInfo.GetOtherFieldReflectValueFrom(structValue, otherFieldInfo.FieldIndexes) - if err = c.bindVarToStructField(otherFieldInfo, fieldValue, srcValue, paramKeyToAttrMap); err != nil { + if err = c.bindVarToStructField(otherFieldInfo, fieldValue, srcValue, option); err != nil { return err } } @@ -256,14 +256,14 @@ func (c *Converter) bindStructWithLoopFieldInfos( } fieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue) if err = c.bindVarToStructField( - cachedFieldInfo, fieldValue, paramValue, option.ParamKeyToAttrMap, + cachedFieldInfo, fieldValue, paramValue, option, ); err != nil && !option.ContinueOnError { return err } // handle same field name in nested struct. if len(cachedFieldInfo.OtherSameNameField) > 0 { if err = c.setOtherSameNameField( - cachedFieldInfo, paramValue, structValue, option.ParamKeyToAttrMap, + cachedFieldInfo, paramValue, structValue, option, ); err != nil && !option.ContinueOnError { return err } @@ -289,14 +289,14 @@ func (c *Converter) bindStructWithLoopFieldInfos( fieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue) if paramValue != nil { if err = c.bindVarToStructField( - cachedFieldInfo, fieldValue, paramValue, option.ParamKeyToAttrMap, + cachedFieldInfo, fieldValue, paramValue, option, ); err != nil && !option.ContinueOnError { return err } // handle same field name in nested struct. if len(cachedFieldInfo.OtherSameNameField) > 0 { if err = c.setOtherSameNameField( - cachedFieldInfo, paramValue, structValue, option.ParamKeyToAttrMap, + cachedFieldInfo, paramValue, structValue, option, ); err != nil && !option.ContinueOnError { return err } @@ -333,7 +333,7 @@ func (c *Converter) bindVarToStructField( cachedFieldInfo *structcache.CachedFieldInfo, fieldValue reflect.Value, srcValue any, - paramKeyToAttrMap map[string]string, + option StructOption, ) (err error) { if !fieldValue.IsValid() { return nil @@ -344,7 +344,7 @@ func (c *Converter) bindVarToStructField( } defer func() { if exception := recover(); exception != nil { - if err = c.bindVarToReflectValue(fieldValue, srcValue, paramKeyToAttrMap); err != nil { + if err = c.bindVarToReflectValue(fieldValue, srcValue, option); err != nil { err = gerror.Wrapf(err, `error binding srcValue to attribute "%s"`, cachedFieldInfo.FieldName()) } } @@ -377,12 +377,18 @@ func (c *Converter) bindVarToStructField( if cachedFieldInfo.ConvertFunc != nil { return cachedFieldInfo.ConvertFunc(srcValue, fieldValue) } + convertOption := ConvertOption{ + StructOption: option, + SliceOption: SliceOption{ContinueOnError: option.ContinueOnError}, + MapOption: MapOption{ContinueOnError: option.ContinueOnError}, + } err = c.doConvertWithReflectValueSet( fieldValue, doConvertInput{ FromValue: srcValue, ToTypeName: cachedFieldInfo.StructField.Type.String(), ReferValue: fieldValue, }, + convertOption, ) return err } @@ -452,9 +458,7 @@ func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value a } // bindVarToReflectValue sets `value` to reflect value object `structFieldValue`. -func (c *Converter) bindVarToReflectValue( - structFieldValue reflect.Value, value any, paramKeyToAttrMap map[string]string, -) (err error) { +func (c *Converter) bindVarToReflectValue(structFieldValue reflect.Value, value any, option StructOption) (err error) { // JSON content converting. ok, err := c.doConvertWithJsonCheck(value, structFieldValue) if err != nil { @@ -480,7 +484,9 @@ func (c *Converter) bindVarToReflectValue( // Converting using reflection by kind. switch kind { case reflect.Map: - return c.MapToMap(value, structFieldValue, paramKeyToAttrMap, MapOption{}) + return c.MapToMap(value, structFieldValue, option.ParamKeyToAttrMap, MapOption{ + ContinueOnError: option.ContinueOnError, + }) case reflect.Struct: // Recursively converting for struct attribute. @@ -493,8 +499,13 @@ func (c *Converter) bindVarToReflectValue( // so it uses Struct function doing the converting internally. case reflect.Slice, reflect.Array: var ( - reflectArray reflect.Value - reflectValue = reflect.ValueOf(value) + reflectArray reflect.Value + reflectValue = reflect.ValueOf(value) + convertOption = ConvertOption{ + StructOption: option, + SliceOption: SliceOption{ContinueOnError: option.ContinueOnError}, + MapOption: MapOption{ContinueOnError: option.ContinueOnError}, + } ) if reflectValue.Kind() == reflect.Slice || reflectValue.Kind() == reflect.Array { reflectArray = reflect.MakeSlice(structFieldValue.Type(), reflectValue.Len(), reflectValue.Len()) @@ -528,6 +539,7 @@ func (c *Converter) bindVarToReflectValue( ToTypeName: elemTypeName, ReferValue: elem, }, + convertOption, ) if err != nil { return err @@ -585,6 +597,7 @@ func (c *Converter) bindVarToReflectValue( ToTypeName: elemTypeName, ReferValue: elem, }, + convertOption, ) if err != nil { return err @@ -608,12 +621,12 @@ func (c *Converter) bindVarToReflectValue( return err } elem := item.Elem() - if err = c.bindVarToReflectValue(elem, value, paramKeyToAttrMap); err == nil { + if err = c.bindVarToReflectValue(elem, value, option); err == nil { structFieldValue.Set(elem.Addr()) } } else { // Not empty pointer, it assigns values to it. - return c.bindVarToReflectValue(structFieldValue.Elem(), value, paramKeyToAttrMap) + return c.bindVarToReflectValue(structFieldValue.Elem(), value, option) } // It mainly and specially handles the interface of nil value. From 787853081ccd2d50f26d3547ee25506f531b2db2 Mon Sep 17 00:00:00 2001 From: John Guo Date: Mon, 3 Mar 2025 14:38:02 +0800 Subject: [PATCH 38/48] up --- util/gconv/internal/converter/converter_scan.go | 17 +++++++++++++---- .../internal/converter/converter_struct.go | 10 ++++++---- .../internal/converter/converter_structs.go | 4 +++- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/util/gconv/internal/converter/converter_scan.go b/util/gconv/internal/converter/converter_scan.go index 2fe16fab340..b580e9abedb 100644 --- a/util/gconv/internal/converter/converter_scan.go +++ b/util/gconv/internal/converter/converter_scan.go @@ -252,7 +252,9 @@ func (c *Converter) doScanForComplicatedTypes( switch dstPointerReflectTypeElemKind { case reflect.Map: // Convert map to map - return c.MapToMap(srcValue, dstPointer, keyToAttributeNameMapping, MapOption{}) + return c.MapToMap(srcValue, dstPointer, keyToAttributeNameMapping, MapOption{ + ContinueOnError: option.ContinueOnError, + }) case reflect.Array, reflect.Slice: var ( @@ -271,9 +273,16 @@ func (c *Converter) doScanForComplicatedTypes( }) } // Convert to slice of structs - return c.Structs(srcValue, dstPointer, SliceOption{}, StructOption{ - ParamKeyToAttrMap: keyToAttributeNameMapping, - }) + var ( + sliceOption = SliceOption{ + ContinueOnError: option.ContinueOnError, + } + mapOption = StructOption{ + ParamKeyToAttrMap: keyToAttributeNameMapping, + ContinueOnError: option.ContinueOnError, + } + ) + return c.Structs(srcValue, dstPointer, sliceOption, mapOption) default: structOption := StructOption{ diff --git a/util/gconv/internal/converter/converter_struct.go b/util/gconv/internal/converter/converter_struct.go index 709b9e7ad68..a3923d0142c 100644 --- a/util/gconv/internal/converter/converter_struct.go +++ b/util/gconv/internal/converter/converter_struct.go @@ -141,7 +141,9 @@ func (c *Converter) Struct(params, pointer any, option StructOption) (err error) if !ok { // paramsMap is the map[string]any type variable for params. // DO NOT use MapDeep here. - paramsMap, err = c.doMapConvert(paramsInterface, RecursiveTypeAuto, true, MapOption{}) + paramsMap, err = c.doMapConvert(paramsInterface, RecursiveTypeAuto, true, MapOption{ + ContinueOnError: option.ContinueOnError, + }) if err != nil { return err } @@ -490,7 +492,7 @@ func (c *Converter) bindVarToReflectValue(structFieldValue reflect.Value, value case reflect.Struct: // Recursively converting for struct attribute. - if err = c.Struct(value, structFieldValue, StructOption{}); err != nil { + if err = c.Struct(value, structFieldValue, option); err != nil { // Note there's reflect conversion mechanism here. structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type())) } @@ -528,7 +530,7 @@ func (c *Converter) bindVarToReflectValue(structFieldValue reflect.Value, value elem = reflect.New(elemType).Elem() } if elem.Kind() == reflect.Struct { - if err = c.Struct(reflectValue.Index(i).Interface(), elem, StructOption{}); err == nil { + if err = c.Struct(reflectValue.Index(i).Interface(), elem, option); err == nil { converted = true } } @@ -586,7 +588,7 @@ func (c *Converter) bindVarToReflectValue(structFieldValue reflect.Value, value elem = reflect.New(elemType).Elem() } if elem.Kind() == reflect.Struct { - if err = c.Struct(value, elem, StructOption{}); err == nil { + if err = c.Struct(value, elem, option); err == nil { converted = true } } diff --git a/util/gconv/internal/converter/converter_structs.go b/util/gconv/internal/converter/converter_structs.go index ceaa385443e..d2eeec733fb 100644 --- a/util/gconv/internal/converter/converter_structs.go +++ b/util/gconv/internal/converter/converter_structs.go @@ -62,7 +62,9 @@ func (c *Converter) Structs( paramsList[i] = paramsRv.Index(i).Interface() } default: - paramsMaps, err := c.SliceMap(params, sliceOption, MapOption{}) + paramsMaps, err := c.SliceMap(params, sliceOption, MapOption{ + ContinueOnError: structOption.ContinueOnError, + }) if err != nil { return err } From ceafbfddbf345f1f611804e54191005a0a2fb2db Mon Sep 17 00:00:00 2001 From: John Guo Date: Mon, 3 Mar 2025 14:41:18 +0800 Subject: [PATCH 39/48] make lint --- database/gdb/gdb_core.go | 1 - .../internal/converter/converter_convert.go | 147 +++++++++--------- 2 files changed, 75 insertions(+), 73 deletions(-) diff --git a/database/gdb/gdb_core.go b/database/gdb/gdb_core.go index ef85df24d79..3665841a364 100644 --- a/database/gdb/gdb_core.go +++ b/database/gdb/gdb_core.go @@ -225,7 +225,6 @@ func (c *Core) GetScan(ctx context.Context, pointer interface{}, sql string, arg return c.db.GetCore().doGetStruct(ctx, pointer, sql, args...) default: - } return gerror.NewCodef( gcode.CodeInvalidParameter, diff --git a/util/gconv/internal/converter/converter_convert.go b/util/gconv/internal/converter/converter_convert.go index 3d367a4692f..ec1f545cfdd 100644 --- a/util/gconv/internal/converter/converter_convert.go +++ b/util/gconv/internal/converter/converter_convert.go @@ -365,88 +365,91 @@ func (c *Converter) doConvert(in doConvertInput, option ConvertOption) (converte return bytes, nil default: - if in.ReferValue != nil { - var referReflectValue reflect.Value - if v, ok := in.ReferValue.(reflect.Value); ok { - referReflectValue = v - } else { - referReflectValue = reflect.ValueOf(in.ReferValue) - } - var fromReflectValue reflect.Value - if v, ok := in.FromValue.(reflect.Value); ok { - fromReflectValue = v - } else { - fromReflectValue = reflect.ValueOf(in.FromValue) - } + return c.doConvertForDefault(in, option) + } +} - // custom converter. - dstReflectValue, ok, err := c.callCustomConverterWithRefer(fromReflectValue, referReflectValue) - if err != nil { - return nil, err - } - if ok { - return dstReflectValue.Interface(), nil - } +func (c *Converter) doConvertForDefault(in doConvertInput, option ConvertOption) (convertedValue any, err error) { + if in.ReferValue != nil { + var referReflectValue reflect.Value + if v, ok := in.ReferValue.(reflect.Value); ok { + referReflectValue = v + } else { + referReflectValue = reflect.ValueOf(in.ReferValue) + } + var fromReflectValue reflect.Value + if v, ok := in.FromValue.(reflect.Value); ok { + fromReflectValue = v + } else { + fromReflectValue = reflect.ValueOf(in.FromValue) + } - defer func() { - if recover() != nil { - in.alreadySetToReferValue = false - if err = c.bindVarToReflectValue(referReflectValue, in.FromValue, option.StructOption); err == nil { - in.alreadySetToReferValue = true - convertedValue = referReflectValue.Interface() - } - } - }() - switch referReflectValue.Kind() { - case reflect.Ptr: - // Type converting for custom type pointers. - // Eg: - // type PayMode int - // type Req struct{ - // Mode *PayMode - // } - // - // Struct(`{"Mode": 1000}`, &req) - originType := referReflectValue.Type().Elem() - switch originType.Kind() { - case reflect.Struct: - // Not support some kinds. - default: - in.ToTypeName = originType.Kind().String() - in.ReferValue = nil - result, err := c.doConvert(in, option) - if err != nil { - return nil, err - } - refElementValue := reflect.ValueOf(result) - originTypeValue := reflect.New(refElementValue.Type()).Elem() - originTypeValue.Set(refElementValue) - in.alreadySetToReferValue = true - return originTypeValue.Addr().Convert(referReflectValue.Type()).Interface(), nil - } + // custom converter. + dstReflectValue, ok, err := c.callCustomConverterWithRefer(fromReflectValue, referReflectValue) + if err != nil { + return nil, err + } + if ok { + return dstReflectValue.Interface(), nil + } - case reflect.Map: - var targetValue = reflect.New(referReflectValue.Type()).Elem() - if err = c.MapToMap(in.FromValue, targetValue, nil, option.MapOption); err == nil { + defer func() { + if recover() != nil { + in.alreadySetToReferValue = false + if err = c.bindVarToReflectValue(referReflectValue, in.FromValue, option.StructOption); err == nil { in.alreadySetToReferValue = true + convertedValue = referReflectValue.Interface() } - return targetValue.Interface(), nil - + } + }() + switch referReflectValue.Kind() { + case reflect.Ptr: + // Type converting for custom type pointers. + // Eg: + // type PayMode int + // type Req struct{ + // Mode *PayMode + // } + // + // Struct(`{"Mode": 1000}`, &req) + originType := referReflectValue.Type().Elem() + switch originType.Kind() { + case reflect.Struct: + // Not support some kinds. default: - + in.ToTypeName = originType.Kind().String() + in.ReferValue = nil + result, err := c.doConvert(in, option) + if err != nil { + return nil, err + } + refElementValue := reflect.ValueOf(result) + originTypeValue := reflect.New(refElementValue.Type()).Elem() + originTypeValue.Set(refElementValue) + in.alreadySetToReferValue = true + return originTypeValue.Addr().Convert(referReflectValue.Type()).Interface(), nil } - in.ToTypeName = referReflectValue.Kind().String() - in.ReferValue = nil - in.alreadySetToReferValue = true - result, err := c.doConvert(in, option) - if err != nil { - return nil, err + + case reflect.Map: + var targetValue = reflect.New(referReflectValue.Type()).Elem() + if err = c.MapToMap(in.FromValue, targetValue, nil, option.MapOption); err == nil { + in.alreadySetToReferValue = true } - convertedValue = reflect.ValueOf(result).Convert(referReflectValue.Type()).Interface() - return convertedValue, nil + return targetValue.Interface(), nil + + default: + } + in.ToTypeName = referReflectValue.Kind().String() + in.ReferValue = nil + in.alreadySetToReferValue = true + result, err := c.doConvert(in, option) + if err != nil { + return nil, err } - return in.FromValue, nil + convertedValue = reflect.ValueOf(result).Convert(referReflectValue.Type()).Interface() + return convertedValue, nil } + return in.FromValue, nil } func (c *Converter) doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput, option ConvertOption) error { From 65172fbee349568a505b3dbc29f27b44eb966d2b Mon Sep 17 00:00:00 2001 From: John Guo Date: Mon, 3 Mar 2025 15:46:29 +0800 Subject: [PATCH 40/48] make lint --- util/gconv/internal/converter/converter.go | 2 +- util/gconv/internal/structcache/structcache.go | 18 +++++++++--------- .../internal/structcache/structcache_cached.go | 2 +- .../structcache_cached_struct_info.go | 14 +++++++------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/util/gconv/internal/converter/converter.go b/util/gconv/internal/converter/converter.go index 13845929e56..cd69edda5c7 100644 --- a/util/gconv/internal/converter/converter.go +++ b/util/gconv/internal/converter/converter.go @@ -122,7 +122,7 @@ func (c *Converter) RegisterTypeConverterFunc(f any) (err error) { return } registeredOutTypeMap[outType] = reflect.ValueOf(f) - c.internalConverter.RegisterTypeConvertFunc(outType) + c.internalConverter.MarkTypeConvertFunc(outType) return } diff --git a/util/gconv/internal/structcache/structcache.go b/util/gconv/internal/structcache/structcache.go index 4f753132bc4..68e40e13636 100644 --- a/util/gconv/internal/structcache/structcache.go +++ b/util/gconv/internal/structcache/structcache.go @@ -19,11 +19,11 @@ type Converter struct { // map[reflect.Type]*CachedStructInfo cachedStructsInfoMap sync.Map - // typeConverterFuncMap is used to store whether field types are registered to custom conversions - typeConverterFuncMap map[reflect.Type]struct{} - // anyToTypeConvertMap for custom type converting from any to its reflect.Value. anyToTypeConvertMap map[reflect.Type]AnyConvertFunc + + // typeConverterFuncMarkMap is used to store whether field types are registered to custom conversions + typeConverterFuncMarkMap map[reflect.Type]struct{} } // AnyConvertFunc is the function type for converting any to specified type. @@ -32,18 +32,18 @@ type AnyConvertFunc func(from any, to reflect.Value) error // NewConverter creates and returns a new Converter object. func NewConverter() *Converter { return &Converter{ - cachedStructsInfoMap: sync.Map{}, - typeConverterFuncMap: make(map[reflect.Type]struct{}), - anyToTypeConvertMap: make(map[reflect.Type]AnyConvertFunc), + cachedStructsInfoMap: sync.Map{}, + typeConverterFuncMarkMap: make(map[reflect.Type]struct{}), + anyToTypeConvertMap: make(map[reflect.Type]AnyConvertFunc), } } -// RegisterTypeConvertFunc registers converting function for custom type. -func (cf *Converter) RegisterTypeConvertFunc(fieldType reflect.Type) { +// MarkTypeConvertFunc marks converting function registered for custom type. +func (cf *Converter) MarkTypeConvertFunc(fieldType reflect.Type) { if fieldType.Kind() == reflect.Ptr { fieldType = fieldType.Elem() } - cf.typeConverterFuncMap[fieldType] = struct{}{} + cf.typeConverterFuncMarkMap[fieldType] = struct{}{} } // RegisterAnyConvertFunc registers custom type converting function for specified type. diff --git a/util/gconv/internal/structcache/structcache_cached.go b/util/gconv/internal/structcache/structcache_cached.go index 44f1412dfb2..4586a5f0615 100644 --- a/util/gconv/internal/structcache/structcache_cached.go +++ b/util/gconv/internal/structcache/structcache_cached.go @@ -29,7 +29,7 @@ func (cf *Converter) GetCachedStructInfo(structType reflect.Type, priorityTag st // else create one. // it parses and generates a cache info for given struct type. - cachedStructInfo = NewCachedStructInfo(cf.typeConverterFuncMap, cf.anyToTypeConvertMap) + cachedStructInfo = NewCachedStructInfo(cf.typeConverterFuncMarkMap, cf.anyToTypeConvertMap) var ( priorityTagArray []string parentIndex = make([]int, 0) diff --git a/util/gconv/internal/structcache/structcache_cached_struct_info.go b/util/gconv/internal/structcache/structcache_cached_struct_info.go index b78a3806c1e..bb8f945fe0a 100644 --- a/util/gconv/internal/structcache/structcache_cached_struct_info.go +++ b/util/gconv/internal/structcache/structcache_cached_struct_info.go @@ -18,13 +18,13 @@ type CachedStructInfo struct { // All sub attributes field info slice. fieldConvertInfos []*CachedFieldInfo - // typeConverterFuncMap is used to store whether field types are registered to custom conversions, - // for enhance converting performance in runtime. - typeConverterFuncMap map[reflect.Type]struct{} - // anyToTypeConvertMap for custom type converting from any to its reflect.Value. anyToTypeConvertMap map[reflect.Type]AnyConvertFunc + // typeConverterFuncMarkMap is used to store whether field types are registered to custom conversions, + // for enhance converting performance in runtime. + typeConverterFuncMarkMap map[reflect.Type]struct{} + // This map field is mainly used in the bindStructWithLoopParamsMap method // key = field's name // Will save all field names and PriorityTagAndFieldName @@ -37,13 +37,13 @@ type CachedStructInfo struct { // NewCachedStructInfo creates and returns a new CachedStructInfo object. func NewCachedStructInfo( - typeConverterFuncMap map[reflect.Type]struct{}, + typeConverterFuncMarkMap map[reflect.Type]struct{}, anyToTypeConvertMap map[reflect.Type]AnyConvertFunc, ) *CachedStructInfo { return &CachedStructInfo{ tagOrFiledNameToFieldInfoMap: make(map[string]*CachedFieldInfo), fieldConvertInfos: make([]*CachedFieldInfo, 0), - typeConverterFuncMap: typeConverterFuncMap, + typeConverterFuncMarkMap: typeConverterFuncMarkMap, anyToTypeConvertMap: anyToTypeConvertMap, } } @@ -186,6 +186,6 @@ func (csi *CachedStructInfo) checkTypeHasCustomConvert(fieldType reflect.Type) b if fieldType.Kind() == reflect.Ptr { fieldType = fieldType.Elem() } - _, ok := csi.typeConverterFuncMap[fieldType] + _, ok := csi.typeConverterFuncMarkMap[fieldType] return ok } From f97a6fa08e6eb3ce3e46897627a364f27e3b8081 Mon Sep 17 00:00:00 2001 From: John Guo Date: Mon, 3 Mar 2025 16:41:15 +0800 Subject: [PATCH 41/48] up --- util/gconv/internal/converter/converter_struct.go | 2 +- .../internal/structcache/structcache_cached_field_info.go | 4 ++-- .../internal/structcache/structcache_cached_struct_info.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/util/gconv/internal/converter/converter_struct.go b/util/gconv/internal/converter/converter_struct.go index a3923d0142c..6bf8c6913d1 100644 --- a/util/gconv/internal/converter/converter_struct.go +++ b/util/gconv/internal/converter/converter_struct.go @@ -362,7 +362,7 @@ func (c *Converter) bindVarToStructField( customConverterInput reflect.Value ok bool ) - if cachedFieldInfo.IsCustomConvert { + if cachedFieldInfo.HasCustomConvert { if customConverterInput, ok = srcValue.(reflect.Value); !ok { customConverterInput = reflect.ValueOf(srcValue) } diff --git a/util/gconv/internal/structcache/structcache_cached_field_info.go b/util/gconv/internal/structcache/structcache_cached_field_info.go index ff89e15cf85..084b609bb45 100644 --- a/util/gconv/internal/structcache/structcache_cached_field_info.go +++ b/util/gconv/internal/structcache/structcache_cached_field_info.go @@ -50,10 +50,10 @@ type CachedFieldInfoBase struct { // Purpose: reduce the interface asserting cost in runtime. IsCommonInterface bool - // IsCustomConvert marks there custom converting function for this field type. + // HasCustomConvert marks there custom converting function for this field type. // A custom converting function is a function that user defined for converting specified type // to another type. - IsCustomConvert bool + HasCustomConvert bool // StructField is the type info of this field. StructField reflect.StructField diff --git a/util/gconv/internal/structcache/structcache_cached_struct_info.go b/util/gconv/internal/structcache/structcache_cached_struct_info.go index bb8f945fe0a..7e1d08540ac 100644 --- a/util/gconv/internal/structcache/structcache_cached_struct_info.go +++ b/util/gconv/internal/structcache/structcache_cached_struct_info.go @@ -123,7 +123,7 @@ func (csi *CachedStructInfo) makeCachedFieldInfo( StructField: field, FieldIndexes: fieldIndexes, ConvertFunc: csi.genFieldConvertFunc(field.Type), - IsCustomConvert: csi.checkTypeHasCustomConvert(field.Type), + HasCustomConvert: csi.checkTypeHasCustomConvert(field.Type), PriorityTagAndFieldName: csi.genPriorityTagAndFieldName(field, priorityTags), RemoveSymbolsFieldName: utils.RemoveSymbols(field.Name), } From 23c7aae8035606cb8b7582d75d626f0f0f745480 Mon Sep 17 00:00:00 2001 From: John Guo Date: Mon, 3 Mar 2025 22:49:52 +0800 Subject: [PATCH 42/48] up --- cmd/gf/internal/cmd/gendao/gendao.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/gf/internal/cmd/gendao/gendao.go b/cmd/gf/internal/cmd/gendao/gendao.go index ff190a401cf..5c38c5c69a8 100644 --- a/cmd/gf/internal/cmd/gendao/gendao.go +++ b/cmd/gf/internal/cmd/gendao/gendao.go @@ -36,7 +36,7 @@ type ( Link string `name:"link" short:"l" brief:"{CGenDaoBriefLink}"` Tables string `name:"tables" short:"t" brief:"{CGenDaoBriefTables}"` TablesEx string `name:"tablesEx" short:"x" brief:"{CGenDaoBriefTablesEx}"` - ShardingPattern []string `name:"ShardingPattern" short:"sp" brief:"{CGenDaoBriefShardingPattern}"` + ShardingPattern []string `name:"shardingPattern" short:"sp" brief:"{CGenDaoBriefShardingPattern}"` Group string `name:"group" short:"g" brief:"{CGenDaoBriefGroup}" d:"default"` Prefix string `name:"prefix" short:"f" brief:"{CGenDaoBriefPrefix}"` RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenDaoBriefRemovePrefix}"` From 6e430727ef8039c19279410f756436ec95cf5355 Mon Sep 17 00:00:00 2001 From: John Guo Date: Mon, 3 Mar 2025 22:52:44 +0800 Subject: [PATCH 43/48] up --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 85d4f529958..03f69483951 100644 --- a/Makefile +++ b/Makefile @@ -34,8 +34,8 @@ version: subup: @set -e; \ echo "Updating submodules..."; \ - cd examples && git pull origin main; \ - cd ..; + git submodule init;\ + git submodule update; # update and commit submodules .PHONY: subsync From 760799fc483876946d7260c1f0d26a613d9d5a80 Mon Sep 17 00:00:00 2001 From: John Guo Date: Mon, 3 Mar 2025 23:08:32 +0800 Subject: [PATCH 44/48] up --- examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples b/examples index 2544fee34dd..c454db2549a 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 2544fee34dd10e6914687f7335bd9e772215ce07 +Subproject commit c454db2549ac7ecce844b687c1e610461818830d From 65a0d51056c93142e3edd4ac1a4e45212e92956b Mon Sep 17 00:00:00 2001 From: wln32 Date: Wed, 5 Mar 2025 09:17:13 +0800 Subject: [PATCH 45/48] =?UTF-8?q?=E5=BC=80=E6=94=BERegisterAnyConverterFun?= =?UTF-8?q?c=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- util/gconv/gconv.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index d40764d48b5..38302b1e3cf 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -142,6 +142,11 @@ var ( defaultConverter = converter.NewConverter() ) +// RegisterAnyConverterFunc registers custom type converting function for specified type. +func RegisterAnyConverterFunc(f AnyConvertFunc, types ...reflect.Type) { + defaultConverter.RegisterAnyConverterFunc(f, types...) +} + // NewConverter creates and returns management object for type converting. func NewConverter() Converter { return converter.NewConverter() From a4add90ae1b10e4475dc4dd2dffe22544bc42250 Mon Sep 17 00:00:00 2001 From: wln32 Date: Wed, 5 Mar 2025 09:46:18 +0800 Subject: [PATCH 46/48] =?UTF-8?q?1.=E6=94=AF=E6=8C=81=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E7=9A=84=E8=87=AA=E5=AE=9A=E4=B9=89=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=202.=E5=AE=9E=E4=BE=8B=E5=8C=96CachedStructInfo?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E7=9B=B4=E6=8E=A5=E4=BC=A0=E5=85=A5Converter?= =?UTF-8?q?=203.=E5=A2=9E=E5=BC=BA(*CachedStructInfo).genFieldConvertFunc?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gconv/internal/structcache/structcache.go | 34 +++++++++++++ .../structcache/structcache_cached.go | 2 +- .../structcache_cached_struct_info.go | 49 +++++++++---------- 3 files changed, 59 insertions(+), 26 deletions(-) diff --git a/util/gconv/internal/structcache/structcache.go b/util/gconv/internal/structcache/structcache.go index 68e40e13636..0256302c301 100644 --- a/util/gconv/internal/structcache/structcache.go +++ b/util/gconv/internal/structcache/structcache.go @@ -14,6 +14,11 @@ import ( "github.com/gogf/gf/v2/util/gconv/internal/localinterface" ) +type interfaceTypeConverter struct { + interfaceType reflect.Type + convertFunc AnyConvertFunc +} + // Converter is the configuration for type converting. type Converter struct { // map[reflect.Type]*CachedStructInfo @@ -22,6 +27,10 @@ type Converter struct { // anyToTypeConvertMap for custom type converting from any to its reflect.Value. anyToTypeConvertMap map[reflect.Type]AnyConvertFunc + // interfaceToTypeConvertMap used for converting any interface type + // the reason why map is not used is because interface types cannot be instantiated + interfaceToTypeConvertMap []interfaceTypeConverter + // typeConverterFuncMarkMap is used to store whether field types are registered to custom conversions typeConverterFuncMarkMap map[reflect.Type]struct{} } @@ -48,9 +57,34 @@ func (cf *Converter) MarkTypeConvertFunc(fieldType reflect.Type) { // RegisterAnyConvertFunc registers custom type converting function for specified type. func (cf *Converter) RegisterAnyConvertFunc(t reflect.Type, convertFunc AnyConvertFunc) { + if t == nil || convertFunc == nil { + panic("cannot register nil convertFunc") + } + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + if t.Kind() == reflect.Interface { + cf.interfaceToTypeConvertMap = append(cf.interfaceToTypeConvertMap, interfaceTypeConverter{ + interfaceType: t, + convertFunc: convertFunc, + }) + return + } cf.anyToTypeConvertMap[t] = convertFunc } +func (cf *Converter) checkTypeImplInterface(t reflect.Type) AnyConvertFunc { + if t.Kind() != reflect.Ptr { + t = reflect.PointerTo(t) + } + for _, inter := range cf.interfaceToTypeConvertMap { + if t.Implements(inter.interfaceType) { + return inter.convertFunc + } + } + return nil +} + var ( implUnmarshalText = reflect.TypeOf((*localinterface.IUnmarshalText)(nil)).Elem() implUnmarshalJson = reflect.TypeOf((*localinterface.IUnmarshalJSON)(nil)).Elem() diff --git a/util/gconv/internal/structcache/structcache_cached.go b/util/gconv/internal/structcache/structcache_cached.go index 4586a5f0615..041b3c79be6 100644 --- a/util/gconv/internal/structcache/structcache_cached.go +++ b/util/gconv/internal/structcache/structcache_cached.go @@ -29,7 +29,7 @@ func (cf *Converter) GetCachedStructInfo(structType reflect.Type, priorityTag st // else create one. // it parses and generates a cache info for given struct type. - cachedStructInfo = NewCachedStructInfo(cf.typeConverterFuncMarkMap, cf.anyToTypeConvertMap) + cachedStructInfo = NewCachedStructInfo(cf) var ( priorityTagArray []string parentIndex = make([]int, 0) diff --git a/util/gconv/internal/structcache/structcache_cached_struct_info.go b/util/gconv/internal/structcache/structcache_cached_struct_info.go index 7e1d08540ac..f3ff52d5d54 100644 --- a/util/gconv/internal/structcache/structcache_cached_struct_info.go +++ b/util/gconv/internal/structcache/structcache_cached_struct_info.go @@ -18,12 +18,7 @@ type CachedStructInfo struct { // All sub attributes field info slice. fieldConvertInfos []*CachedFieldInfo - // anyToTypeConvertMap for custom type converting from any to its reflect.Value. - anyToTypeConvertMap map[reflect.Type]AnyConvertFunc - - // typeConverterFuncMarkMap is used to store whether field types are registered to custom conversions, - // for enhance converting performance in runtime. - typeConverterFuncMarkMap map[reflect.Type]struct{} + converter *Converter // This map field is mainly used in the bindStructWithLoopParamsMap method // key = field's name @@ -36,15 +31,11 @@ type CachedStructInfo struct { } // NewCachedStructInfo creates and returns a new CachedStructInfo object. -func NewCachedStructInfo( - typeConverterFuncMarkMap map[reflect.Type]struct{}, - anyToTypeConvertMap map[reflect.Type]AnyConvertFunc, -) *CachedStructInfo { +func NewCachedStructInfo(converter *Converter) *CachedStructInfo { return &CachedStructInfo{ tagOrFiledNameToFieldInfoMap: make(map[string]*CachedFieldInfo), fieldConvertInfos: make([]*CachedFieldInfo, 0), - typeConverterFuncMarkMap: typeConverterFuncMarkMap, - anyToTypeConvertMap: anyToTypeConvertMap, + converter: converter, } } @@ -134,19 +125,27 @@ func (csi *CachedStructInfo) makeCachedFieldInfo( } func (csi *CachedStructInfo) genFieldConvertFunc(fieldType reflect.Type) (convertFunc AnyConvertFunc) { - if v := csi.anyToTypeConvertMap[fieldType]; v != nil { - return v + ptr := 0 + for fieldType.Kind() == reflect.Ptr { + fieldType = fieldType.Elem() + ptr++ } - - var fieldTypeKind = fieldType.Kind() - if fieldTypeKind == reflect.Ptr { - convertFunc = csi.genFieldConvertFunc(fieldType.Elem()) - if convertFunc == nil { - return nil - } - return csi.genPtrConvertFunc(convertFunc) + convertFunc = csi.converter.anyToTypeConvertMap[fieldType] + if convertFunc == nil { + // If the registered custom implementation cannot be found, + // try to check if there is an implementation interface + convertFunc = csi.converter.checkTypeImplInterface(fieldType) + } + // if the registered type is not found and + // the corresponding interface is not implemented, return directly + if convertFunc == nil { + return nil + } + for i := 0; i < ptr; i++ { + // If it is a pointer type, it needs to be packaged + convertFunc = genPtrConvertFunc(convertFunc) } - return nil + return convertFunc } func (csi *CachedStructInfo) genPriorityTagAndFieldName( @@ -173,7 +172,7 @@ func (csi *CachedStructInfo) genPriorityTagAndFieldName( return } -func (csi *CachedStructInfo) genPtrConvertFunc(convertFunc AnyConvertFunc) AnyConvertFunc { +func genPtrConvertFunc(convertFunc AnyConvertFunc) AnyConvertFunc { return func(from any, to reflect.Value) error { if to.IsNil() { to.Set(reflect.New(to.Type().Elem())) @@ -186,6 +185,6 @@ func (csi *CachedStructInfo) checkTypeHasCustomConvert(fieldType reflect.Type) b if fieldType.Kind() == reflect.Ptr { fieldType = fieldType.Elem() } - _, ok := csi.typeConverterFuncMarkMap[fieldType] + _, ok := csi.converter.typeConverterFuncMarkMap[fieldType] return ok } From 9c458baa03faf9ad549a521bc73f3b053d5d4318 Mon Sep 17 00:00:00 2001 From: wln32 Date: Wed, 5 Mar 2025 10:04:25 +0800 Subject: [PATCH 47/48] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B5=8B=E8=AF=95=201.?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E6=8C=87=E9=92=88=E7=B1=BB=E5=9E=8B=EF=BC=8C?= =?UTF-8?q?=E4=BD=86=E6=98=AF=E8=BD=AC=E6=8D=A2=E5=88=B0=E5=80=BC=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=202.=E6=B3=A8=E5=86=8C=E5=80=BC=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=EF=BC=8C=E4=BD=86=E6=98=AF=E8=BD=AC=E6=8D=A2=E5=88=B0=E6=8C=87?= =?UTF-8?q?=E9=92=88=E7=B1=BB=E5=9E=8B=203.=E6=B3=A8=E5=86=8C=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E7=B1=BB=E5=9E=8B=EF=BC=8C=E8=BD=AC=E6=8D=A2=E5=88=B0?= =?UTF-8?q?=E5=85=B7=E4=BD=93=E5=AE=9E=E7=8E=B0=E6=8E=A5=E5=8F=A3=E7=9A=84?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- util/gconv/gconv_z_unit_converter_test.go | 73 +++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/util/gconv/gconv_z_unit_converter_test.go b/util/gconv/gconv_z_unit_converter_test.go index ad88c3175c3..edf8850ad61 100644 --- a/util/gconv/gconv_z_unit_converter_test.go +++ b/util/gconv/gconv_z_unit_converter_test.go @@ -7,6 +7,9 @@ package gconv_test import ( + "database/sql" + "fmt" + "reflect" "testing" "github.com/gogf/gf/v2/test/gtest" @@ -84,3 +87,73 @@ func TestConvertWithRefer(t *testing.T) { t.AssertNE(gconv.ConvertWithRefer("1.01", false), false) }) } + +func testAnyToMyInt(from any, to reflect.Value) error { + switch x := from.(type) { + case int: + to.SetInt(123456) + default: + return fmt.Errorf("unsupported type %T(%v)", x, x) + } + return nil +} + +func testAnyToSqlNullType(_ any, to reflect.Value) error { + if to.Kind() != reflect.Ptr { + to = to.Addr() + } + return to.Interface().(sql.Scanner).Scan(123456) +} + +func TestNewConverter(t *testing.T) { + type Dst[T any] struct { + A T + } + gtest.C(t, func(t *gtest.T) { + conv := gconv.NewConverter() + conv.RegisterAnyConverterFunc(testAnyToMyInt, reflect.TypeOf((*myInt)(nil))) + var dst Dst[myInt] + err := conv.Struct(map[string]any{ + "a": 1200, + }, &dst, gconv.StructOption{}) + t.AssertNil(err) + t.Assert(dst, Dst[myInt]{ + A: 123456, + }) + }) + gtest.C(t, func(t *gtest.T) { + conv := gconv.NewConverter() + conv.RegisterAnyConverterFunc(testAnyToMyInt, reflect.TypeOf((myInt)(0))) + var dst Dst[*myInt] + err := conv.Struct(map[string]any{ + "a": 1200, + }, &dst, gconv.StructOption{}) + t.AssertNil(err) + t.Assert(*dst.A, 123456) + }) + + gtest.C(t, func(t *gtest.T) { + conv := gconv.NewConverter() + conv.RegisterAnyConverterFunc(testAnyToSqlNullType, reflect.TypeOf((*sql.Scanner)(nil))) + type sqlNullDst struct { + A sql.Null[int] + B sql.Null[float32] + C sql.NullInt64 + D sql.NullString + } + var dst sqlNullDst + err := conv.Struct(map[string]any{ + "a": 12, + "b": 34, + "c": 56, + "d": "sqlNull", + }, &dst, gconv.StructOption{}) + t.AssertNil(err) + t.Assert(dst, sqlNullDst{ + A: sql.Null[int]{V: 123456, Valid: true}, + B: sql.Null[float32]{V: 123456, Valid: true}, + C: sql.NullInt64{Int64: 123456, Valid: true}, + D: sql.NullString{String: "123456", Valid: true}, + }) + }) +} From 4ac735979423900aae002cad7e2a45ef3a1c12a6 Mon Sep 17 00:00:00 2001 From: wln32 Date: Wed, 5 Mar 2025 10:15:06 +0800 Subject: [PATCH 48/48] =?UTF-8?q?=E8=A1=A5=E5=85=85=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- util/gconv/gconv_z_unit_converter_test.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/util/gconv/gconv_z_unit_converter_test.go b/util/gconv/gconv_z_unit_converter_test.go index edf8850ad61..ccaee32b4d3 100644 --- a/util/gconv/gconv_z_unit_converter_test.go +++ b/util/gconv/gconv_z_unit_converter_test.go @@ -140,13 +140,22 @@ func TestNewConverter(t *testing.T) { B sql.Null[float32] C sql.NullInt64 D sql.NullString + + E *sql.Null[int] + F *sql.Null[float32] + G *sql.NullInt64 + H *sql.NullString } var dst sqlNullDst err := conv.Struct(map[string]any{ "a": 12, "b": 34, "c": 56, - "d": "sqlNull", + "d": "sqlNullString", + "e": 12, + "f": 34, + "g": 56, + "h": "sqlNullString", }, &dst, gconv.StructOption{}) t.AssertNil(err) t.Assert(dst, sqlNullDst{ @@ -154,6 +163,11 @@ func TestNewConverter(t *testing.T) { B: sql.Null[float32]{V: 123456, Valid: true}, C: sql.NullInt64{Int64: 123456, Valid: true}, D: sql.NullString{String: "123456", Valid: true}, + + E: &sql.Null[int]{V: 123456, Valid: true}, + F: &sql.Null[float32]{V: 123456, Valid: true}, + G: &sql.NullInt64{Int64: 123456, Valid: true}, + H: &sql.NullString{String: "123456", Valid: true}, }) }) }