3
0

Improve paging cursor enc/dec

This commit is contained in:
Denis Arh 2020-10-20 10:34:44 +02:00
parent 9a21226163
commit 8cee9740ae
2 changed files with 97 additions and 2 deletions

View File

@ -35,6 +35,10 @@ type (
desc []bool
Reverse bool
}
pagingCursorValue struct {
v interface{}
}
)
func NewPaging(limit uint, cursor string) (p Paging, err error) {
@ -68,6 +72,7 @@ func (p *PagingCursor) Values() []interface{} {
return p.values
}
// Stirng to implement Stringer and to get human-readable representation of the cursor
func (p *PagingCursor) String() string {
var o = "<"
@ -84,6 +89,7 @@ func (p *PagingCursor) String() string {
return o + ">"
}
// MarshalJSON serializes cursor struct as JSON and encodes it as base64 + adds quotes to be treated as JSON string
func (p *PagingCursor) MarshalJSON() ([]byte, error) {
buf, err := json.Marshal(struct {
K []string
@ -117,7 +123,7 @@ func (p *PagingCursor) UnmarshalJSON(in []byte) error {
var (
aux struct {
K []string
V []interface{}
V []pagingCursorValue
D []bool
R bool
}
@ -128,10 +134,15 @@ func (p *PagingCursor) UnmarshalJSON(in []byte) error {
}
p.keys = aux.K
p.values = aux.V
p.desc = aux.D
p.Reverse = aux.R
// json.Unmarshal treats uint64 in values ([]interface{}) as float64 and we don't like that.
p.values = make([]interface{}, len(aux.V))
for i, v := range aux.V {
p.values[i] = v.v
}
return nil
}
@ -166,3 +177,23 @@ func parseCursor(in string) (p *PagingCursor, err error) {
return p, nil
}
// Making sure uint64 other int* values are properly unmarshaled
func (v *pagingCursorValue) UnmarshalJSON(in []byte) (err error) {
var (
u uint64
i int64
)
if err = json.Unmarshal(in, &u); err == nil {
v.v = u
return
}
if err = json.Unmarshal(in, &i); err == nil {
v.v = i
return
}
return json.Unmarshal(in, &v.v)
}

View File

@ -0,0 +1,64 @@
package filter
import (
"fmt"
"github.com/stretchr/testify/require"
"testing"
)
func Test_cursorEncDec(t *testing.T) {
var (
req = require.New(t)
id = uint64(201244712307261628)
enc string
cur = &PagingCursor{}
dec = &PagingCursor{}
)
{
cur.Set("uint64", id, true)
cur.Set("string", "foo", true)
req.Len(cur.values, 2)
req.Equal(id, cur.values[0])
req.Equal(fmt.Sprintf("<uint64: %d, string: foo, forward>", id), cur.String())
}
{
enc = cur.Encode()
req.NotEmpty(enc)
}
{
req.NoError(dec.Decode(enc[1 : len(enc)-1]))
req.Len(dec.values, 2)
req.Equal(id, dec.values[0])
req.Equal("foo", dec.values[1])
req.Equal(fmt.Sprintf("<uint64: %d, string: foo, forward>", id), cur.String())
}
}
func Test_cursorValueUnmarshal(t *testing.T) {
var (
req = require.New(t)
pcv = &pagingCursorValue{}
)
req.NoError(pcv.UnmarshalJSON([]byte("201244712307261628")))
req.Equal(pcv.v, uint64(201244712307261628))
req.NoError(pcv.UnmarshalJSON([]byte("42")))
req.Equal(pcv.v, uint64(42))
req.NoError(pcv.UnmarshalJSON([]byte("-42")))
req.Equal(pcv.v, int64(-42))
req.NoError(pcv.UnmarshalJSON([]byte("true")))
req.Equal(pcv.v, true)
req.NoError(pcv.UnmarshalJSON([]byte("42.42")))
req.Equal(pcv.v, 42.42)
req.NoError(pcv.UnmarshalJSON([]byte(`"foo"`)))
req.Equal(pcv.v, "foo")
}