Named parameters helpers
This commit is contained in:
parent
6c6ccaf0b3
commit
e40d7a236c
|
@ -0,0 +1,66 @@
|
|||
package dbc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/localhots/gobelt/reflect2"
|
||||
)
|
||||
|
||||
type namedParams interface {
|
||||
Get(name string) (val interface{}, ok bool)
|
||||
}
|
||||
|
||||
var (
|
||||
_ namedParams = namedParamsMap{}
|
||||
_ namedParams = &namedParamsStruct{}
|
||||
)
|
||||
|
||||
func newNamedParams(val interface{}) (namedParams, error) {
|
||||
switch tval := val.(type) {
|
||||
case map[string]interface{}:
|
||||
return newNamedParamsMap(tval)
|
||||
default:
|
||||
return newNamedParamsStruct(val)
|
||||
}
|
||||
}
|
||||
|
||||
type namedParamsMap struct {
|
||||
m map[string]interface{}
|
||||
}
|
||||
|
||||
func newNamedParamsMap(m map[string]interface{}) (namedParamsMap, error) {
|
||||
return namedParamsMap{m}, nil
|
||||
}
|
||||
|
||||
func (p namedParamsMap) Get(name string) (val interface{}, ok bool) {
|
||||
val, ok = p.m[name]
|
||||
return
|
||||
}
|
||||
|
||||
type namedParamsStruct struct {
|
||||
s reflect.Value
|
||||
idx map[string]int
|
||||
}
|
||||
|
||||
func newNamedParamsStruct(s interface{}) (*namedParamsStruct, error) {
|
||||
val := reflect.ValueOf(s)
|
||||
if val.Kind() == reflect.Ptr {
|
||||
val = val.Elem()
|
||||
}
|
||||
if val.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("Unsupported named parameters type: %T", s)
|
||||
}
|
||||
return &namedParamsStruct{
|
||||
s: val,
|
||||
idx: reflect2.TagIndex(val.Type(), tagName),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *namedParamsStruct) Get(name string) (val interface{}, ok bool) {
|
||||
i, ok := p.idx[name]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return p.s.Field(i).Interface(), true
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package dbc
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNamedParamsMap(t *testing.T) {
|
||||
m, err := newNamedParamsMap(map[string]interface{}{
|
||||
"num": 1,
|
||||
"str": "foo",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create named params map: %v", err)
|
||||
}
|
||||
testNamedParams(t, m)
|
||||
}
|
||||
|
||||
func TestNamedParamsStruct(t *testing.T) {
|
||||
type dummy struct {
|
||||
Num int `db:"num"`
|
||||
Str string `db:"str"`
|
||||
}
|
||||
m, err := newNamedParamsStruct(&dummy{Num: 1, Str: "foo"})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create named params struct: %v", err)
|
||||
}
|
||||
testNamedParams(t, m)
|
||||
}
|
||||
|
||||
func testNamedParams(t *testing.T, p namedParams) {
|
||||
t.Helper()
|
||||
|
||||
v, ok := p.Get("num")
|
||||
if !ok {
|
||||
t.Error("num was not found")
|
||||
}
|
||||
if v != 1 {
|
||||
t.Errorf("Expected num to equal 1, got %d", v)
|
||||
}
|
||||
|
||||
v, ok = p.Get("str")
|
||||
if !ok {
|
||||
t.Error("num was not found")
|
||||
}
|
||||
if v != "foo" {
|
||||
t.Errorf("Expected num to equal 'foo', got %q", v)
|
||||
}
|
||||
|
||||
_, ok = p.Get("missing")
|
||||
if ok {
|
||||
t.Error("missing value reportedly found")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNamedParamsMap(b *testing.B) {
|
||||
m, err := newNamedParamsMap(map[string]interface{}{"foo": 1})
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to create named params map: %v", err)
|
||||
}
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
m.Get("foo")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNamedParamsStruct(b *testing.B) {
|
||||
type dummy struct {
|
||||
Foo int `db:"foo"`
|
||||
}
|
||||
m, err := newNamedParamsStruct(&dummy{Foo: 1})
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to create named params struct: %v", err)
|
||||
}
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
m.Get("foo")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue