Skip to content

Commit 4d0b0d0

Browse files
joeybloggsjoeybloggs
authored andcommitted
Merge branch 'encoder'
2 parents 3e7505c + 562ffbd commit 4d0b0d0

File tree

13 files changed

+2239
-194
lines changed

13 files changed

+2239
-194
lines changed

README.md

Lines changed: 120 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
Package form
22
============
33
<img align="right" src="https://raw.githubusercontent.com/go-playground/form/master/logo.jpg">
4-
![Project status](https://img.shields.io/badge/version-1.3.0-green.svg)
4+
![Project status](https://img.shields.io/badge/version-1.4.0-green.svg)
55
[![Build Status](https://semaphoreci.com/api/v1/joeybloggs/form/branches/master/badge.svg)](https://semaphoreci.com/joeybloggs/form)
66
[![Coverage Status](https://coveralls.io/repos/github/go-playground/form/badge.svg?branch=master)](https://coveralls.io/github/go-playground/form?branch=master)
77
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/form)](https://goreportcard.com/report/github.com/go-playground/form)
88
[![GoDoc](https://godoc.org/github.com/go-playground/form?status.svg)](https://godoc.org/github.com/go-playground/form)
99
![License](https://img.shields.io/dub/l/vibe-d.svg)
1010

11-
Package form parses url.Values and fills a struct with values, creating objects as necessary.
11+
Package form Decodes url.Values into struct values and Encodes strut values into url.Values.
1212

1313
It has the following features:
1414

@@ -76,8 +76,10 @@ Usage
7676
</form>
7777
```
7878

79-
Example
79+
Examples
8080
-------
81+
82+
Decoding
8183
```go
8284
package main
8385

@@ -145,14 +147,82 @@ func parseForm() url.Values {
145147
}
146148
```
147149

150+
Encoding
151+
```go
152+
package main
153+
154+
import (
155+
"fmt"
156+
"log"
157+
158+
"github.com/go-playground/form"
159+
)
160+
161+
// Address contains address information
162+
type Address struct {
163+
Name string
164+
Phone string
165+
}
166+
167+
// User contains user information
168+
type User struct {
169+
Name string
170+
Age uint8
171+
Gender string
172+
Address []Address
173+
Active bool `form:"active"`
174+
MapExample map[string]string
175+
NestedMap map[string]map[string]string
176+
NestedArray [][]string
177+
}
178+
179+
// use a single instance of Encoder, it caches struct info
180+
var encoder *form.Encoder
181+
182+
func main() {
183+
encoder = form.NewEncoder()
184+
185+
user := User{
186+
Name: "joeybloggs",
187+
Age: 3,
188+
Gender: "Male",
189+
Address: []Address{
190+
{Name: "26 Here Blvd.", Phone: "9(999)999-9999"},
191+
{Name: "26 There Blvd.", Phone: "1(111)111-1111"},
192+
},
193+
Active: true,
194+
MapExample: map[string]string{"key": "value"},
195+
NestedMap: map[string]map[string]string{"key": {"key": "value"}},
196+
NestedArray: [][]string{{"value"}},
197+
}
198+
199+
// must pass a pointer
200+
values, err := encoder.Encode(&user)
201+
if err != nil {
202+
log.Panic(err)
203+
}
204+
205+
fmt.Printf("%#v\n", values)
206+
}
207+
```
208+
148209
Registering Custom Types
149210
--------------
211+
212+
Decoder
150213
```go
151214
decoder.RegisterCustomTypeFunc(func(vals []string) (interface{}, error) {
152215
return time.Parse("2006-01-02", vals[0])
153216
}, time.Time{})
154217
```
155218

219+
Encoder
220+
```go
221+
encoder.RegisterCustomTypeFunc(func(x interface{}) ([]string, error) {
222+
return []string{x.(time.Time).Format("2006-01-02")}, nil
223+
}, time.Time{})
224+
```
225+
156226
Ignoring Fields
157227
--------------
158228
you can tell form to ignore fields using `-` in the tag
@@ -162,26 +232,62 @@ type MyStruct struct {
162232
}
163233
```
164234

235+
Notes
236+
------
237+
To maximize compatibility with other systems the Encoder attempts
238+
to avoid using array indexes in url.Values if at all possible.
239+
240+
eg.
241+
```go
242+
// A struct field of
243+
Field []string{"1", "2", "3"}
244+
245+
// will be output a url.Value as
246+
"Field": []string{"1", "2", "3"}
247+
248+
and not
249+
"Field[0]": []string{"1"}
250+
"Field[1]": []string{"2"}
251+
"Field[2]": []string{"3"}
252+
253+
// however there are times where it is unavoidable, like with pointers
254+
i := int(1)
255+
Field []*string{nil, nil, &i}
256+
257+
// to avoid index 1 and 2 must use index
258+
"Field[2]": []string{"1"}
259+
```
260+
165261
Benchmarks
166262
------
167263
###### Run on MacBook Pro (Retina, 15-inch, Late 2013) 2.6 GHz Intel Core i7 16 GB 1600 MHz DDR3 using Go version go1.6.2 darwin/amd64
168264

169-
NOTE: the 1 allocation and B/op in the first 4 is actually the struct allocating when passing it in, so primitives are actually zero allocation.
265+
NOTE: the 1 allocation and B/op in the first 4 decodes is actually the struct allocating when passing it in, so primitives are actually zero allocation.
170266

171267
```go
172268
go test -bench=. -benchmem=true
173269

174270
PASS
175-
BenchmarkSimpleUserStruct-8 5000000 299 ns/op 64 B/op 1 allocs/op
176-
BenchmarkSimpleUserStructParallel-8 20000000 110 ns/op 64 B/op 1 allocs/op
177-
BenchmarkPrimitivesStructAllPrimitivesTypes-8 2000000 956 ns/op 96 B/op 1 allocs/op
178-
BenchmarkPrimitivesStructAllPrimitivesTypesParallel-8 5000000 285 ns/op 96 B/op 1 allocs/op
179-
BenchmarkComplexArrayStructAllTypes-8 100000 20706 ns/op 6776 B/op 159 allocs/op
180-
BenchmarkComplexArrayStructAllTypesParallel-8 200000 6158 ns/op 6776 B/op 159 allocs/op
181-
BenchmarkComplexMapStructAllTypes-8 50000 35548 ns/op 20966 B/op 245 allocs/op
182-
BenchmarkComplexMapStructAllTypesParallel-8 200000 11984 ns/op 20966 B/op 245 allocs/op
183-
BenchmarkArrayMapNestedStruct-8 200000 5617 ns/op 2064 B/op 37 allocs/op
184-
BenchmarkArrayMapNestedStructParallel-8 1000000 2032 ns/op 2064 B/op 37 allocs/op
271+
BenchmarkSimpleUserDecodeStruct-8 5000000 293 ns/op 64 B/op 1 allocs/op
272+
BenchmarkSimpleUserDecodeStructParallel-8 20000000 112 ns/op 64 B/op 1 allocs/op
273+
BenchmarkSimpleUserEncodeStruct-8 2000000 808 ns/op 466 B/op 7 allocs/op
274+
BenchmarkSimpleUserEncodeStructParallel-8 5000000 278 ns/op 466 B/op 7 allocs/op
275+
BenchmarkPrimitivesDecodeStructAllPrimitivesTypes-8 2000000 965 ns/op 96 B/op 1 allocs/op
276+
BenchmarkPrimitivesDecodeStructAllPrimitivesTypesParallel-8 5000000 284 ns/op 96 B/op 1 allocs/op
277+
BenchmarkPrimitivesEncodeStructAllPrimitivesTypes-8 300000 4349 ns/op 2913 B/op 32 allocs/op
278+
BenchmarkPrimitivesEncodeStructAllPrimitivesTypesParallel-8 1000000 1469 ns/op 2913 B/op 32 allocs/op
279+
BenchmarkComplexArrayDecodeStructAllTypes-8 100000 20608 ns/op 6776 B/op 159 allocs/op
280+
BenchmarkComplexArrayDecodeStructAllTypesParallel-8 200000 6265 ns/op 6776 B/op 159 allocs/op
281+
BenchmarkComplexArrayEncodeStructAllTypes-8 100000 17198 ns/op 7192 B/op 154 allocs/op
282+
BenchmarkComplexArrayEncodeStructAllTypesParallel-8 300000 5157 ns/op 7191 B/op 154 allocs/op
283+
BenchmarkComplexMapDecodeStructAllTypes-8 50000 34637 ns/op 20869 B/op 241 allocs/op
284+
BenchmarkComplexMapDecodeStructAllTypesParallel-8 100000 12095 ns/op 20870 B/op 241 allocs/op
285+
BenchmarkComplexMapEncodeStructAllTypes-8 100000 18193 ns/op 7095 B/op 177 allocs/op
286+
BenchmarkComplexMapEncodeStructAllTypesParallel-8 300000 5651 ns/op 7096 B/op 177 allocs/op
287+
BenchmarkDecodeNestedStruct-8 300000 5537 ns/op 2064 B/op 37 allocs/op
288+
BenchmarkDecodeNestedStructParallel-8 1000000 1932 ns/op 2064 B/op 37 allocs/op
289+
BenchmarkEncodeNestedStruct-8 500000 2956 ns/op 848 B/op 26 allocs/op
290+
BenchmarkEncodeNestedStructParallel-8 1000000 1168 ns/op 848 B/op 26 allocs/op
185291
```
186292

187293
Competitor benchmarks can be found [here](https://github.com/go-playground/form/blob/master/benchmarks/benchmarks.md)

benchmarks/benchmarks.md

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,26 @@
22

33
### go-playground/form
44
```go
5-
BenchmarkSimpleUserStruct-8 5000000 299 ns/op 64 B/op 1 allocs/op
6-
BenchmarkSimpleUserStructParallel-8 20000000 110 ns/op 64 B/op 1 allocs/op
7-
BenchmarkPrimitivesStructAllPrimitivesTypes-8 2000000 956 ns/op 96 B/op 1 allocs/op
8-
BenchmarkPrimitivesStructAllPrimitivesTypesParallel-8 5000000 285 ns/op 96 B/op 1 allocs/op
9-
BenchmarkComplexArrayStructAllTypes-8 100000 20706 ns/op 6776 B/op 159 allocs/op
10-
BenchmarkComplexArrayStructAllTypesParallel-8 200000 6158 ns/op 6776 B/op 159 allocs/op
11-
BenchmarkComplexMapStructAllTypes-8 50000 35548 ns/op 20966 B/op 245 allocs/op
12-
BenchmarkComplexMapStructAllTypesParallel-8 200000 11984 ns/op 20966 B/op 245 allocs/op
13-
BenchmarkArrayMapNestedStruct-8 200000 5617 ns/op 2064 B/op 37 allocs/op
14-
BenchmarkArrayMapNestedStructParallel-8 1000000 2032 ns/op 2064 B/op 37 allocs/op
5+
BenchmarkSimpleUserDecodeStruct-8 5000000 293 ns/op 64 B/op 1 allocs/op
6+
BenchmarkSimpleUserDecodeStructParallel-8 20000000 112 ns/op 64 B/op 1 allocs/op
7+
BenchmarkSimpleUserEncodeStruct-8 2000000 808 ns/op 466 B/op 7 allocs/op
8+
BenchmarkSimpleUserEncodeStructParallel-8 5000000 278 ns/op 466 B/op 7 allocs/op
9+
BenchmarkPrimitivesDecodeStructAllPrimitivesTypes-8 2000000 965 ns/op 96 B/op 1 allocs/op
10+
BenchmarkPrimitivesDecodeStructAllPrimitivesTypesParallel-8 5000000 284 ns/op 96 B/op 1 allocs/op
11+
BenchmarkPrimitivesEncodeStructAllPrimitivesTypes-8 300000 4349 ns/op 2913 B/op 32 allocs/op
12+
BenchmarkPrimitivesEncodeStructAllPrimitivesTypesParallel-8 1000000 1469 ns/op 2913 B/op 32 allocs/op
13+
BenchmarkComplexArrayDecodeStructAllTypes-8 100000 20608 ns/op 6776 B/op 159 allocs/op
14+
BenchmarkComplexArrayDecodeStructAllTypesParallel-8 200000 6265 ns/op 6776 B/op 159 allocs/op
15+
BenchmarkComplexArrayEncodeStructAllTypes-8 100000 17198 ns/op 7192 B/op 154 allocs/op
16+
BenchmarkComplexArrayEncodeStructAllTypesParallel-8 300000 5157 ns/op 7191 B/op 154 allocs/op
17+
BenchmarkComplexMapDecodeStructAllTypes-8 50000 34637 ns/op 20869 B/op 241 allocs/op
18+
BenchmarkComplexMapDecodeStructAllTypesParallel-8 100000 12095 ns/op 20870 B/op 241 allocs/op
19+
BenchmarkComplexMapEncodeStructAllTypes-8 100000 18193 ns/op 7095 B/op 177 allocs/op
20+
BenchmarkComplexMapEncodeStructAllTypesParallel-8 300000 5651 ns/op 7096 B/op 177 allocs/op
21+
BenchmarkDecodeNestedStruct-8 300000 5537 ns/op 2064 B/op 37 allocs/op
22+
BenchmarkDecodeNestedStructParallel-8 1000000 1932 ns/op 2064 B/op 37 allocs/op
23+
BenchmarkEncodeNestedStruct-8 500000 2956 ns/op 848 B/op 26 allocs/op
24+
BenchmarkEncodeNestedStructParallel-8 1000000 1168 ns/op 848 B/op 26 allocs/op
1525
```
1626

1727
### gorilla/schema
@@ -30,6 +40,7 @@ BenchmarkComplexMapStructAllTypesGorillaParallel-8 0 0
3040
gorilla_scheme_test.go:121: Gorilla does not support map parsing at this time
3141
BenchmarkArrayMapNestedStructGorilla-8 200000 10393 ns/op 2269 B/op 73 allocs/op
3242
BenchmarkArrayMapNestedStructGorillaParallel-8 500000 3484 ns/op 2269 B/op 73 allocs/op
43+
No Encoder Support At This Time
3344
```
3445

3546
### monoculum/formam
@@ -48,4 +59,5 @@ BenchmarkArrayMapNestedStructFormam-8 --- FAIL: Benchmark
4859
formam_test.go:174: formam: not supported type for field "Value" in path "NestedPtrArray[1].Value"
4960
BenchmarkArrayMapNestedStructFormamParallel-8 --- FAIL: BenchmarkArrayMapNestedStructFormamParallel-8
5061
formam_test.go:189: formam: not supported type for field "Value" in path "NestedPtrArray[0].Value"
62+
No Encoder Support At This Time
5163
```

0 commit comments

Comments
 (0)