123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578 |
- package formbinder
- import (
- "fmt"
- "net/url"
- "reflect"
- "strconv"
- "time"
- )
- const tagName = "form"
- var timeFormat = []string{
- "2006-01-02",
- time.ANSIC,
- time.UnixDate,
- time.RubyDate,
- time.RFC822,
- time.RFC822Z,
- time.RFC850,
- time.RFC1123,
- time.RFC1123Z,
- time.RFC3339,
- time.RFC3339Nano,
- time.Kitchen,
- time.Stamp,
- time.StampMilli,
- time.StampMicro,
- time.StampNano,
- }
- // A pathMap holds the values of a map with its key and values correspondent
- type pathMap struct {
- ma reflect.Value
- key string
- value reflect.Value
- path string
- }
- // a pathMaps holds the values for each key
- type pathMaps []*pathMap
- // find find and get the value by the given key
- func (ma pathMaps) find(id reflect.Value, key string) *pathMap {
- for _, v := range ma {
- if v.ma == id && v.key == key {
- return v
- }
- }
- return nil
- }
- // DecodeCustomTypeFunc is a function that indicate how should to decode a custom type
- type DecodeCustomTypeFunc func([]string) (interface{}, error)
- // DecodeCustomTypeField is a function registered for a specific field of the struct passed to the Decoder
- type DecodeCustomTypeField struct {
- field reflect.Value
- fun DecodeCustomTypeFunc
- }
- // DecodeCustomType fields for custom types
- type DecodeCustomType struct {
- fun DecodeCustomTypeFunc
- fields []DecodeCustomTypeField
- }
- // Decoder the main to decode the values
- type Decoder struct {
- main reflect.Value
- formValues url.Values
- opts *DecoderOptions
- curr reflect.Value
- value string
- values []string
- path string
- field string
- bracket string
- isKey bool
- maps pathMaps
- customTypes map[reflect.Type]*DecodeCustomType
- }
- // DecoderOptions options for decoding the values
- type DecoderOptions struct {
- TagName string
- }
- // RegisterCustomType It is the method responsible for register functions for decoding custom types
- func (dec *Decoder) RegisterCustomType(fn DecodeCustomTypeFunc, types []interface{}, fields []interface{}) *Decoder {
- if dec.customTypes == nil {
- dec.customTypes = make(map[reflect.Type]*DecodeCustomType)
- }
- for i := range types {
- typ := reflect.TypeOf(types[i])
- if dec.customTypes[typ] == nil {
- dec.customTypes[typ] = new(DecodeCustomType)
- }
- if len(fields) > 0 {
- for j := range fields {
- va := reflect.ValueOf(fields[j])
- f := DecodeCustomTypeField{field: va, fun: fn}
- dec.customTypes[typ].fields = append(dec.customTypes[typ].fields, f)
- }
- } else {
- dec.customTypes[typ].fun = fn
- }
- }
- return dec
- }
- // NewDecoder creates a new instance of Decoder
- func NewDecoder(opts *DecoderOptions) *Decoder {
- dec := &Decoder{opts: opts}
- if dec.opts == nil {
- dec.opts = &DecoderOptions{}
- }
- if dec.opts.TagName == "" {
- dec.opts.TagName = tagName
- }
- return dec
- }
- // Decode decodes the url.Values into a element that must be a pointer to a type provided by argument
- func (dec *Decoder) Decode(vs url.Values, dst interface{}) error {
- main := reflect.ValueOf(dst)
- if main.Kind() != reflect.Ptr {
- return newError(fmt.Errorf("formam: the value passed for decode is not a pointer but a %v", main.Kind()))
- }
- dec.main = main.Elem()
- dec.formValues = vs
- return dec.prepare()
- }
- // Decode decodes the url.Values into a element that must be a pointer to a type provided by argument
- func Decode(vs url.Values, dst interface{}) error {
- main := reflect.ValueOf(dst)
- if main.Kind() != reflect.Ptr {
- return newError(fmt.Errorf("formam: the value passed for decode is not a pointer but a %v", main.Kind()))
- }
- dec := &Decoder{
- main: main.Elem(),
- formValues: vs,
- opts: &DecoderOptions{
- TagName: tagName,
- },
- }
- return dec.prepare()
- }
- func (dec *Decoder) prepare() error {
- // iterate over the form's values and decode it
- for k, v := range dec.formValues {
- dec.path = k
- dec.field = k
- dec.values = v
- dec.value = v[0]
- dec.curr = dec.main
- if dec.value != "" {
- if err := dec.begin(); err != nil {
- return err
- }
- }
- }
- // set values of maps
- for _, v := range dec.maps {
- key := v.ma.Type().Key()
- // check if the key implements the UnmarshalText interface
- var val reflect.Value
- if key.Kind() == reflect.Ptr {
- val = reflect.New(key.Elem())
- } else {
- val = reflect.New(key).Elem()
- }
- // decode key
- dec.path = v.path
- dec.field = v.path
- dec.values = []string{v.key}
- dec.curr = val
- dec.value = v.key
- dec.isKey = true
- if err := dec.decode(); err != nil {
- return err
- }
- // set key with its value
- v.ma.SetMapIndex(dec.curr, v.value)
- }
- dec.maps = make(pathMaps, 0)
- return nil
- }
- // begin analyzes the current path to walk through it
- func (dec *Decoder) begin() (err error) {
- inBracket := false
- valBracket := ""
- bracketClosed := false
- lastPos := 0
- tmp := dec.field
- // parse path
- for i, char := range tmp {
- if char == '[' && inBracket == false {
- // found an opening bracket
- bracketClosed = false
- inBracket = true
- dec.field = tmp[lastPos:i]
- lastPos = i + 1
- /*
- if err = dec.walk(); err != nil {
- return
- }
- */
- continue
- } else if inBracket {
- // it is inside of bracket, so get its value
- if char == ']' {
- /*
- nextChar := tmp[i+1:]
- if nextChar != "" {
- t := nextChar[:1]
- if t != "[" && t != "." {
- valBracket += string(char)
- continue
- }
- }
- */
- // found an closing bracket, so it will be recently close, so put as true the bracketClosed
- // and put as false inBracket and pass the value of bracket to dec.key
- inBracket = false
- bracketClosed = true
- dec.bracket = valBracket
- lastPos = i + 1
- if err = dec.walk(); err != nil {
- return
- }
- valBracket = ""
- } else {
- // still inside the bracket, so follow getting its value
- valBracket += string(char)
- }
- continue
- } else if !inBracket {
- // not found any bracket, so try found a field
- if char == '.' {
- // found a field, we need to know if the field is next of a closing bracket,
- // for example: [0].Field
- if bracketClosed {
- bracketClosed = false
- lastPos = i + 1
- continue
- }
- // found a field, but is not next of a closing bracket, for example: Field1.Field2
- dec.field = tmp[lastPos:i]
- //dec.field = tmp[:i]
- lastPos = i + 1
- if err = dec.walk(); err != nil {
- return
- }
- }
- continue
- }
- }
- // last field of path
- dec.field = tmp[lastPos:]
- return dec.end()
- }
- // walk traverses the current path until to the last field
- func (dec *Decoder) walk() error {
- // check if there is field, if is so, then it should be struct or map (access by .)
- if dec.field != "" {
- // check if is a struct or map
- switch dec.curr.Kind() {
- case reflect.Struct:
- if err := dec.findStructField(); err != nil {
- return err
- }
- case reflect.Map:
- dec.walkInMap(dec.field)
- }
- }
- // check if is a interface and it is not nil. This mean that the interface
- // has a struct, map or slice as value
- if dec.curr.Kind() == reflect.Interface && !dec.curr.IsNil() {
- dec.curr = dec.curr.Elem()
- }
- // check if it is a pointer
- if dec.curr.Kind() == reflect.Ptr {
- if dec.curr.IsNil() {
- dec.curr.Set(reflect.New(dec.curr.Type().Elem()))
- }
- dec.curr = dec.curr.Elem()
- }
- // check if there is access to slice/array or map (access by [])
- if dec.bracket != "" {
- switch dec.curr.Kind() {
- case reflect.Array:
- index, err := strconv.Atoi(dec.bracket)
- if err != nil {
- return newError(fmt.Errorf("formam: the index of array is not a number in the field \"%v\" of path \"%v\"", dec.field, dec.path))
- }
- dec.curr = dec.curr.Index(index)
- case reflect.Slice:
- index, err := strconv.Atoi(dec.bracket)
- if err != nil {
- return newError(fmt.Errorf("formam: the index of slice is not a number in the field \"%v\" of path \"%v\"", dec.field, dec.path))
- }
- if dec.curr.Len() <= index {
- dec.expandSlice(index + 1)
- }
- dec.curr = dec.curr.Index(index)
- case reflect.Map:
- dec.walkInMap(dec.bracket)
- default:
- return newError(fmt.Errorf("formam: the field \"%v\" in path \"%v\" has a index for array but it is a %v", dec.field, dec.path, dec.curr.Kind()))
- }
- }
- dec.field = ""
- dec.bracket = ""
- return nil
- }
- // walkMap puts in d.curr the map concrete for decode the current value
- func (dec *Decoder) walkInMap(key string) {
- n := dec.curr.Type()
- takeAndAppend := func() {
- m := reflect.New(n.Elem()).Elem()
- dec.maps = append(dec.maps, &pathMap{dec.curr, key, m, dec.path})
- dec.curr = m
- }
- if dec.curr.IsNil() {
- dec.curr.Set(reflect.MakeMap(n))
- takeAndAppend()
- } else if a := dec.maps.find(dec.curr, key); a == nil {
- takeAndAppend()
- } else {
- dec.curr = a.value
- }
- }
- // end finds the last field for decode its value correspondent
- func (dec *Decoder) end() error {
- switch dec.curr.Kind() {
- case reflect.Struct:
- if err := dec.findStructField(); err != nil {
- return err
- }
- case reflect.Map:
- // leave backward compatibility for access to maps by .
- dec.walkInMap(dec.field)
- }
- if dec.value == "" {
- return nil
- }
- return dec.decode()
- }
- // decode sets the value in the field
- func (dec *Decoder) decode() error {
- // has registered a custom type? If so, then decode by it
- if ok, err := dec.checkCustomType(); ok || err != nil {
- return err
- }
- // implements UnmarshalText interface? If so, then decode by it
- if ok, err := checkUnmarshalText(dec.curr, dec.value); ok || err != nil {
- return err
- }
- switch dec.curr.Kind() {
- case reflect.Array:
- if dec.bracket == "" {
- // not has index, so to decode all values in the array
- tmp := dec.curr
- for i, v := range dec.values {
- dec.curr = tmp.Index(i)
- dec.value = v
- if err := dec.decode(); err != nil {
- return err
- }
- }
- } else {
- // has index, so to decode value by index indicated
- index, err := strconv.Atoi(dec.bracket)
- if err != nil {
- return newError(fmt.Errorf("formam: the index of array is not a number in the field \"%v\" of path \"%v\"", dec.field, dec.path))
- }
- dec.curr = dec.curr.Index(index)
- return dec.decode()
- }
- case reflect.Slice:
- if dec.bracket == "" {
- // not has index, so to decode all values in the slice/array
- dec.expandSlice(len(dec.values))
- tmp := dec.curr
- for i, v := range dec.values {
- dec.curr = tmp.Index(i)
- dec.value = v
- if err := dec.decode(); err != nil {
- return err
- }
- }
- } else {
- // has index, so to decode value by index indicated
- index, err := strconv.Atoi(dec.bracket)
- if err != nil {
- return newError(fmt.Errorf("formam: the index of slice is not a number in the field \"%v\" of path \"%v\"", dec.field, dec.path))
- }
- if dec.curr.Len() <= index {
- dec.expandSlice(index + 1)
- }
- dec.curr = dec.curr.Index(index)
- return dec.decode()
- }
- case reflect.String:
- dec.curr.SetString(dec.value)
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- if num, err := strconv.ParseInt(dec.value, 10, 64); err != nil {
- return newError(fmt.Errorf("formam: the value of field \"%v\" in path \"%v\" should be a valid signed integer number", dec.field, dec.path))
- } else {
- dec.curr.SetInt(num)
- }
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- if num, err := strconv.ParseUint(dec.value, 10, 64); err != nil {
- return newError(fmt.Errorf("formam: the value of field \"%v\" in path \"%v\" should be a valid unsigned integer number", dec.field, dec.path))
- } else {
- dec.curr.SetUint(num)
- }
- case reflect.Float32, reflect.Float64:
- if num, err := strconv.ParseFloat(dec.value, dec.curr.Type().Bits()); err != nil {
- return newError(fmt.Errorf("formam: the value of field \"%v\" in path \"%v\" should be a valid float number", dec.field, dec.path))
- } else {
- dec.curr.SetFloat(num)
- }
- case reflect.Bool:
- switch dec.value {
- case "true", "on", "1":
- dec.curr.SetBool(true)
- case "false", "off", "0":
- dec.curr.SetBool(false)
- default:
- return newError(fmt.Errorf("formam: the value of field \"%v\" in path \"%v\" is not a valid boolean", dec.field, dec.path))
- }
- case reflect.Interface:
- dec.curr.Set(reflect.ValueOf(dec.value))
- case reflect.Ptr:
- dec.curr.Set(reflect.New(dec.curr.Type().Elem()))
- dec.curr = dec.curr.Elem()
- return dec.decode()
- case reflect.Struct:
- switch dec.curr.Interface().(type) {
- case time.Time:
- var t time.Time
- var err error
- for _, layout := range timeFormat {
- t, err = time.Parse(layout, dec.value)
- if err == nil {
- break
- }
- }
- if err != nil {
- return newError(fmt.Errorf("formam: the value of field \"%v\" in path \"%v\" is not a valid datetime", dec.field, dec.path))
- }
- dec.curr.Set(reflect.ValueOf(t))
- case url.URL:
- u, err := url.Parse(dec.value)
- if err != nil {
- return newError(fmt.Errorf("formam: the value of field \"%v\" in path \"%v\" is not a valid url", dec.field, dec.path))
- }
- dec.curr.Set(reflect.ValueOf(*u))
- default:
- /*
- if dec.isKey {
- tmp := dec.curr
- dec.field = dec.value
- if err := dec.begin(); err != nil {
- return err
- }
- dec.curr = tmp
- return nil
- }
- */
- return newError(fmt.Errorf("formam: not supported type for field \"%v\" in path \"%v\"", dec.field, dec.path))
- }
- default:
- return newError(fmt.Errorf("formam: not supported type for field \"%v\" in path \"%v\"", dec.field, dec.path))
- }
- return nil
- }
- // findField finds a field by its name, if it is not found,
- // then retry the search examining the tag "formam" of every field of struct
- func (dec *Decoder) findStructField() error {
- var anon reflect.Value
- num := dec.curr.NumField()
- for i := 0; i < num; i++ {
- field := dec.curr.Type().Field(i)
- if field.Name == dec.field {
- // check if the field's name is equal
- dec.curr = dec.curr.Field(i)
- return nil
- } else if field.Anonymous {
- // if the field is a anonymous struct, then iterate over its fields
- tmp := dec.curr
- dec.curr = dec.curr.FieldByIndex(field.Index)
- if err := dec.findStructField(); err != nil {
- dec.curr = tmp
- continue
- }
- // field in anonymous struct is found,
- // but first it should found the field in the rest of struct
- // (a field with same name in the current struct should have preference over anonymous struct)
- anon = dec.curr
- dec.curr = tmp
- } else if dec.field == field.Tag.Get(dec.opts.TagName) {
- // is not found yet, then retry by its tag name "formam"
- dec.curr = dec.curr.Field(i)
- return nil
- }
- }
- if anon.IsValid() {
- dec.curr = anon
- return nil
- }
- return newError(fmt.Errorf("formam: not found the field \"%v\" in the path \"%v\"", dec.field, dec.path))
- }
- // expandSlice expands the length and capacity of the current slice
- func (dec *Decoder) expandSlice(length int) {
- n := reflect.MakeSlice(dec.curr.Type(), length, length)
- reflect.Copy(n, dec.curr)
- dec.curr.Set(n)
- }
- // checkCustomType checks if the value to decode has a custom type registered
- func (dec *Decoder) checkCustomType() (bool, error) {
- if dec.customTypes == nil {
- return false, nil
- }
- if v, ok := dec.customTypes[dec.curr.Type()]; ok {
- if len(v.fields) > 0 {
- for i := range v.fields {
- if v.fields[i].field.Elem() == dec.curr {
- va, err := v.fields[i].fun(dec.values)
- if err != nil {
- return true, err
- }
- dec.curr.Set(reflect.ValueOf(va))
- return true, nil
- }
- }
- if v.fun != nil {
- va, err := v.fun(dec.values)
- if err != nil {
- return true, err
- }
- dec.curr.Set(reflect.ValueOf(va))
- return true, nil
- }
- } else {
- va, err := v.fun(dec.values)
- if err != nil {
- return true, err
- }
- dec.curr.Set(reflect.ValueOf(va))
- return true, nil
- }
- }
- return false, nil
- }
|