add Pluck function to retrieve a list of column values

This commit is contained in:
DarthPestilane 2018-07-26 17:21:16 +08:00
parent 188193dcac
commit b853758f8c
4 changed files with 175 additions and 0 deletions

View File

@ -1417,6 +1417,16 @@ func (engine *Engine) Find(beans interface{}, condiBeans ...interface{}) error {
return session.Find(beans, condiBeans...) return session.Find(beans, condiBeans...)
} }
// Pluck retrieve a list of column values.
// colName is the column name where values from
// slicePtr should be a slice which will filled by the list values
// beans is optional which represents the table, should be a *Struct
func (engine *Engine) Pluck(colName string, slicePtr interface{}, beans ...interface{}) error {
session := engine.NewSession()
defer session.Close()
return session.Pluck(colName, slicePtr, beans...)
}
// FindAndCount find the results and also return the counts // FindAndCount find the results and also return the counts
func (engine *Engine) FindAndCount(rowsSlicePtr interface{}, condiBean ...interface{}) (int64, error) { func (engine *Engine) FindAndCount(rowsSlicePtr interface{}, condiBean ...interface{}) (int64, error) {
session := engine.NewSession() session := engine.NewSession()

View File

@ -64,6 +64,7 @@ type Interface interface {
Update(bean interface{}, condiBeans ...interface{}) (int64, error) Update(bean interface{}, condiBeans ...interface{}) (int64, error)
UseBool(...string) *Session UseBool(...string) *Session
Where(interface{}, ...interface{}) *Session Where(interface{}, ...interface{}) *Session
Pluck(colName string, slicePtr interface{}, bean ...interface{}) error
} }
// EngineInterface defines the interface which Engine, EngineGroup will implementate. // EngineInterface defines the interface which Engine, EngineGroup will implementate.

61
session_pluck.go Normal file
View File

@ -0,0 +1,61 @@
package xorm
import (
"errors"
"fmt"
"reflect"
"strings"
)
// Pluck retrieve a list of column values.
// colName is the column name where values from
// slicePtr should be a slice which will filled by the list values
// beans is optional which represents the table, should be a *Struct
func (session *Session) Pluck(colName string, slicePtr interface{}, beans ...interface{}) error {
if session.isAutoClose {
defer session.Close()
}
return session.pluck(colName, slicePtr, beans...)
}
func (session *Session) pluck(colName string, slicePtr interface{}, beans ...interface{}) error {
sliceValue := reflect.Indirect(reflect.ValueOf(slicePtr))
if sliceValue.Kind() != reflect.Slice {
return errors.New("needs a pointer to a slice")
}
sliceElemType := sliceValue.Type().Elem()
rows := []map[string]interface{}{}
query := session
if session.statement.selectStr == "" {
query.Select(colName)
}
if len(beans) != 0 {
// find table
bean := beans[0]
beanValue := reflect.ValueOf(bean)
if beanValue.Kind() != reflect.Ptr || beanValue.Elem().Kind() != reflect.Struct {
return errors.New("needs a pointer to a struct")
}
session.statement.setRefValue(beanValue)
tbName := session.statement.TableName()
query.Table(tbName)
}
if err := query.Find(&rows); err != nil {
return err
}
colSegs := strings.Split(colName, ".")
col := colSegs[len(colSegs)-1] // last one
col = strings.Trim(col, "`") // unwrap column name
nSlice := reflect.New(sliceValue.Type()).Elem()
rowsLen := len(rows)
for i := 0; i < rowsLen; i++ {
if v, ok := rows[i][col]; !ok {
return fmt.Errorf("cannot find column: %s", col)
} else {
nSlice = reflect.Append(nSlice, reflect.ValueOf(v).Convert(sliceElemType))
}
}
sliceValue.Set(nSlice)
return nil
}

103
session_pluck_test.go Normal file
View File

@ -0,0 +1,103 @@
package xorm
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestPluck(t *testing.T) {
var err error
assert.NoError(t, prepareEngine())
assertSync(t, new(Userinfo))
_, err = testEngine.Insert([]Userinfo{
{
Username: "Lenny",
},
{
Username: "Jimmy",
},
{
Username: "John Wick",
},
})
assert.NoError(t, err)
var ids []int64
err = testEngine.Table("userinfo").Alias("u").Pluck("u.id", &ids)
assert.NoError(t, err)
t.Logf("%+v", ids)
err = testEngine.Table("userinfo").Alias("u").Pluck("`u`.`id`", &ids)
assert.NoError(t, err)
t.Logf("%+v", ids)
var names []string
err = testEngine.Table("userinfo").Pluck("username", &names)
assert.NoError(t, err)
t.Logf("%+v", names)
}
func TestPluck2(t *testing.T) {
var err error
assert.NoError(t, prepareEngine())
assertSync(t, new(Userinfo))
_, err = testEngine.Insert([]Userinfo{
{
Username: "Lenny",
},
{
Username: "Jimmy",
},
{
Username: "John Wick",
},
})
assert.NoError(t, err)
var names []string
err = testEngine.Pluck("username", &names, new(Userinfo))
assert.NoError(t, err)
t.Logf("%+v", names)
}
func TestPluck3(t *testing.T) {
var err error
assert.NoError(t, prepareEngine())
assertSync(t, new(Userinfo))
_, err = testEngine.Insert([]Userinfo{
{
Username: "Lenny",
},
{
Username: "Jimmy",
},
{
Username: "John Wick",
},
})
assert.NoError(t, err)
var names []string
err = testEngine.Table("userinfo").Pluck("username", &names, new(Team))
assert.NoError(t, err)
t.Logf("%+v", names)
}
func TestPluck4(t *testing.T) {
var err error
assert.NoError(t, prepareEngine())
assertSync(t, new(Userinfo))
_, err = testEngine.Insert([]Userinfo{
{
Username: "Lenny",
},
{
Username: "Jimmy",
},
{
Username: "John Wick",
},
})
assert.NoError(t, err)
var names []string
err = testEngine.Table("userinfo").Select("id, username as name").Pluck("name", &names, new(Team))
assert.NoError(t, err)
t.Logf("%+v", names)
}