93 lines
1.8 KiB
Go
93 lines
1.8 KiB
Go
package dbc
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/localhots/gobelt/reflect2"
|
|
)
|
|
|
|
var namedRegexp = regexp.MustCompile("" +
|
|
"`[^`]+`|" +
|
|
`'[^']+'|` +
|
|
`"[^"]+"|` +
|
|
`@[a-zA-Z][a-zA-Z0-9_]*`)
|
|
|
|
func prepareNamedQuery(query string, p namedParams) (newQuery string, args []interface{}, err error) {
|
|
newQuery = namedRegexp.ReplaceAllStringFunc(query, func(m string) string {
|
|
if !strings.HasPrefix(m, "@") {
|
|
return m
|
|
}
|
|
val, ok := p.Get(m[1:])
|
|
if !ok {
|
|
err = fmt.Errorf("Named parameter %s was not found", m)
|
|
}
|
|
args = append(args, val)
|
|
return "?"
|
|
})
|
|
return
|
|
}
|
|
|
|
//
|
|
// Params
|
|
//
|
|
|
|
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) {
|
|
if i, ok := p.idx[name]; ok {
|
|
return p.s.Field(i).Interface(), true
|
|
}
|
|
return nil, false
|
|
}
|