fix(database/gdb): Fix GetArray return type and add Bools method (#4452)

Change the return type of the GetArray method to Array for consistency
in data structure. Introduce a new Bools method to convert Vars to a
slice of bools, along with corresponding test cases to validate the
functionality.

```go
// 改进前
res, _ := db.Model(table).Fields("id").Array()
ids := make([]int64, 0, len(res))
for _, v := range res {
ids = append(ids, v.Int64())
}
g.Dump(ids)
// 改进后
res, _ := db.Model(table).Fields("id").Array()
ids := res.Int64s()
g.Dump(ids)
```
This commit is contained in:
hailaz
2025-09-28 17:08:37 +08:00
committed by GitHub
parent f172e61585
commit f565a347c4
7 changed files with 74 additions and 7 deletions

View File

@ -15,14 +15,25 @@ type Vars []*Var
// Strings converts and returns `vs` as []string.
func (vs Vars) Strings() (s []string) {
s = make([]string, 0, len(vs))
for _, v := range vs {
s = append(s, v.String())
}
return s
}
// Bools converts and returns `vs` as []bool.
func (vs Vars) Bools() (s []bool) {
s = make([]bool, 0, len(vs))
for _, v := range vs {
s = append(s, v.Bool())
}
return s
}
// Interfaces converts and returns `vs` as []any.
func (vs Vars) Interfaces() (s []any) {
s = make([]any, 0, len(vs))
for _, v := range vs {
s = append(s, v.Val())
}
@ -31,6 +42,7 @@ func (vs Vars) Interfaces() (s []any) {
// Float32s converts and returns `vs` as []float32.
func (vs Vars) Float32s() (s []float32) {
s = make([]float32, 0, len(vs))
for _, v := range vs {
s = append(s, v.Float32())
}
@ -39,6 +51,7 @@ func (vs Vars) Float32s() (s []float32) {
// Float64s converts and returns `vs` as []float64.
func (vs Vars) Float64s() (s []float64) {
s = make([]float64, 0, len(vs))
for _, v := range vs {
s = append(s, v.Float64())
}
@ -47,6 +60,7 @@ func (vs Vars) Float64s() (s []float64) {
// Ints converts and returns `vs` as []Int.
func (vs Vars) Ints() (s []int) {
s = make([]int, 0, len(vs))
for _, v := range vs {
s = append(s, v.Int())
}
@ -55,6 +69,7 @@ func (vs Vars) Ints() (s []int) {
// Int8s converts and returns `vs` as []int8.
func (vs Vars) Int8s() (s []int8) {
s = make([]int8, 0, len(vs))
for _, v := range vs {
s = append(s, v.Int8())
}
@ -63,6 +78,7 @@ func (vs Vars) Int8s() (s []int8) {
// Int16s converts and returns `vs` as []int16.
func (vs Vars) Int16s() (s []int16) {
s = make([]int16, 0, len(vs))
for _, v := range vs {
s = append(s, v.Int16())
}
@ -71,6 +87,7 @@ func (vs Vars) Int16s() (s []int16) {
// Int32s converts and returns `vs` as []int32.
func (vs Vars) Int32s() (s []int32) {
s = make([]int32, 0, len(vs))
for _, v := range vs {
s = append(s, v.Int32())
}
@ -79,6 +96,7 @@ func (vs Vars) Int32s() (s []int32) {
// Int64s converts and returns `vs` as []int64.
func (vs Vars) Int64s() (s []int64) {
s = make([]int64, 0, len(vs))
for _, v := range vs {
s = append(s, v.Int64())
}
@ -87,6 +105,7 @@ func (vs Vars) Int64s() (s []int64) {
// Uints converts and returns `vs` as []uint.
func (vs Vars) Uints() (s []uint) {
s = make([]uint, 0, len(vs))
for _, v := range vs {
s = append(s, v.Uint())
}
@ -95,6 +114,7 @@ func (vs Vars) Uints() (s []uint) {
// Uint8s converts and returns `vs` as []uint8.
func (vs Vars) Uint8s() (s []uint8) {
s = make([]uint8, 0, len(vs))
for _, v := range vs {
s = append(s, v.Uint8())
}
@ -103,6 +123,7 @@ func (vs Vars) Uint8s() (s []uint8) {
// Uint16s converts and returns `vs` as []uint16.
func (vs Vars) Uint16s() (s []uint16) {
s = make([]uint16, 0, len(vs))
for _, v := range vs {
s = append(s, v.Uint16())
}
@ -111,6 +132,7 @@ func (vs Vars) Uint16s() (s []uint16) {
// Uint32s converts and returns `vs` as []uint32.
func (vs Vars) Uint32s() (s []uint32) {
s = make([]uint32, 0, len(vs))
for _, v := range vs {
s = append(s, v.Uint32())
}
@ -119,6 +141,7 @@ func (vs Vars) Uint32s() (s []uint32) {
// Uint64s converts and returns `vs` as []uint64.
func (vs Vars) Uint64s() (s []uint64) {
s = make([]uint64, 0, len(vs))
for _, v := range vs {
s = append(s, v.Uint64())
}

View File

@ -22,6 +22,7 @@ func TestVars(t *testing.T) {
gvar.New(3),
}
t.AssertEQ(vs.Strings(), []string{"1", "2", "3"})
t.AssertEQ(vs.Bools(), []bool{true, true, true})
t.AssertEQ(vs.Interfaces(), []any{1, 2, 3})
t.AssertEQ(vs.Float32s(), []float32{1, 2, 3})
t.AssertEQ(vs.Float64s(), []float64{1, 2, 3})
@ -38,6 +39,46 @@ func TestVars(t *testing.T) {
})
}
func TestVars_Bools(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
// Test with various boolean-like values
var vs = gvar.Vars{
gvar.New(true),
gvar.New(false),
gvar.New(1),
gvar.New(0),
gvar.New("true"),
gvar.New("false"),
gvar.New("1"),
gvar.New("0"),
}
expected := []bool{true, false, true, false, true, false, true, false}
t.AssertEQ(vs.Bools(), expected)
})
}
func TestVars_Empty(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
// Test with empty Vars
var vs = gvar.Vars{}
t.AssertEQ(vs.Strings(), []string{})
t.AssertEQ(vs.Bools(), []bool{})
t.AssertEQ(vs.Interfaces(), []any{})
t.AssertEQ(vs.Ints(), []int{})
t.AssertEQ(vs.Float64s(), []float64{})
})
}
func TestVars_SingleElement(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
// Test with single element
var vs = gvar.Vars{gvar.New(42)}
t.AssertEQ(vs.Strings(), []string{"42"})
t.AssertEQ(vs.Bools(), []bool{true})
t.AssertEQ(vs.Ints(), []int{42})
})
}
func TestVars_Scan(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
type User struct {

View File

@ -181,7 +181,7 @@ type DB interface {
// 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 ...any) ([]Value, error)
GetArray(ctx context.Context, sql string, args ...any) (Array, error)
// GetCount executes a COUNT query and returns the result as an integer.
// It's a convenience method for counting rows.
@ -673,6 +673,9 @@ type (
// Value is the field value type.
Value = *gvar.Var
// Array is the field value array type.
Array = gvar.Vars
// Record is the row record of the table.
Record map[string]Value

View File

@ -175,7 +175,7 @@ func (c *Core) GetOne(ctx context.Context, sql string, args ...any) (Record, err
// 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 ...any) ([]Value, error) {
func (c *Core) GetArray(ctx context.Context, sql string, args ...any) (Array, error) {
all, err := c.db.DoSelect(ctx, nil, sql, args...)
if err != nil {
return nil, err

View File

@ -126,7 +126,7 @@ func (m *Model) One(where ...any) (Record, error) {
// If the optional parameter `fieldsAndWhere` is given, the fieldsAndWhere[0] is the selected fields
// and fieldsAndWhere[1:] is treated as where condition fields.
// Also see Model.Fields and Model.Where functions.
func (m *Model) Array(fieldsAndWhere ...any) ([]Value, error) {
func (m *Model) Array(fieldsAndWhere ...any) (Array, error) {
if len(fieldsAndWhere) > 0 {
if len(fieldsAndWhere) > 2 {
return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1], fieldsAndWhere[2:]...).Array()

View File

@ -76,8 +76,8 @@ func (r Result) List() 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))
func (r Result) Array(field ...string) Array {
array := make(Array, len(r))
if len(r) == 0 {
return array
}

View File

@ -89,7 +89,7 @@ func Database(name ...string) gdb.DB {
}
}
if len(cg) > 0 {
if gdb.GetConfig(group) == nil {
if gcg, _ := gdb.GetConfigGroup(group); gcg == nil {
intlog.Printf(ctx, "add configuration for group: %s, %#v", g, cg)
if err := gdb.SetConfigGroup(g, cg); err != nil {
panic(err)
@ -108,7 +108,7 @@ func Database(name ...string) gdb.DB {
cg = append(cg, *node)
}
if len(cg) > 0 {
if gdb.GetConfig(group) == nil {
if gcg, _ := gdb.GetConfigGroup(group); gcg == nil {
intlog.Printf(ctx, "add configuration for group: %s, %#v", gdb.DefaultGroupName, cg)
if err := gdb.SetConfigGroup(gdb.DefaultGroupName, cg); err != nil {
panic(err)