Improve json transformation utility package
This commit is contained in:
parent
fecc1c94b8
commit
b5a15a85ae
3 changed files with 1349 additions and 397 deletions
|
@ -16,53 +16,19 @@ package data
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ugorji/go/codec"
|
||||
"github.com/abcum/surreal/util/pack"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
var (
|
||||
// ErrOutOfBounds - Index out of bounds.
|
||||
ErrOutOfBounds = errors.New("out of bounds")
|
||||
|
||||
// ErrNotObj - The target is not an object type.
|
||||
ErrNotObj = errors.New("not an object")
|
||||
|
||||
// ErrNotArray - The target is not an array type.
|
||||
ErrNotArray = errors.New("not an array")
|
||||
|
||||
// ErrNotUnique - The target is not an array type.
|
||||
ErrNotUnique = errors.New("not a unique array item")
|
||||
|
||||
// ErrPathCollision - Creating a path failed because an element collided with an existing value.
|
||||
ErrPathCollision = errors.New("encountered value collision whilst building path")
|
||||
|
||||
// ErrInvalidInputObj - The input value was not a map[string]interface{}.
|
||||
ErrInvalidInputObj = errors.New("invalid input object")
|
||||
|
||||
// ErrInvalidInputText - The input data could not be parsed.
|
||||
ErrInvalidInputText = errors.New("input text could not be parsed")
|
||||
|
||||
// ErrInvalidPath - The filepath was not valid.
|
||||
ErrInvalidPath = errors.New("invalid file path")
|
||||
|
||||
// ErrInvalidBuffer - The input buffer contained an invalid JSON string
|
||||
ErrInvalidBuffer = errors.New("input buffer contained invalid JSON")
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
// Doc holds a reference to the core data object, or a selected path.
|
||||
type Doc struct {
|
||||
data interface{}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
// New creates a new data object.
|
||||
func New() *Doc {
|
||||
return &Doc{map[string]interface{}{}}
|
||||
|
@ -73,107 +39,34 @@ func Consume(input interface{}) *Doc {
|
|||
return &Doc{input}
|
||||
}
|
||||
|
||||
// NewFromJSON converts a JSON byte slice into a data object.
|
||||
func NewFromJSON(input []byte) *Doc {
|
||||
|
||||
doc := New()
|
||||
|
||||
var opt codec.JsonHandle
|
||||
opt.MapType = reflect.TypeOf(map[string]interface{}(nil))
|
||||
|
||||
codec.NewDecoderBytes(input, &opt).Decode(doc.data)
|
||||
|
||||
return doc
|
||||
|
||||
}
|
||||
|
||||
// NewFromCBOR converts a CBOR byte slice into a data object.
|
||||
func NewFromCBOR(input []byte) *Doc {
|
||||
|
||||
doc := New()
|
||||
|
||||
var opt codec.CborHandle
|
||||
opt.MapType = reflect.TypeOf(map[string]interface{}(nil))
|
||||
opt.SetInterfaceExt(reflect.TypeOf(time.Time{}), 1, extTime{})
|
||||
|
||||
codec.NewDecoderBytes(input, &opt).Decode(doc.data)
|
||||
|
||||
return doc
|
||||
|
||||
}
|
||||
|
||||
// NewFromPACK converts a MsgPack byte slice into a data object.
|
||||
func NewFromPACK(input []byte) *Doc {
|
||||
|
||||
doc := New()
|
||||
|
||||
var opt codec.MsgpackHandle
|
||||
opt.WriteExt = true
|
||||
opt.RawToString = true
|
||||
opt.MapType = reflect.TypeOf(map[string]interface{}(nil))
|
||||
opt.SetBytesExt(reflect.TypeOf(time.Time{}), 1, extTime{})
|
||||
|
||||
codec.NewDecoderBytes(input, &opt).Decode(doc.data)
|
||||
|
||||
return doc
|
||||
|
||||
}
|
||||
|
||||
// Data returns the internal data object as an interface.
|
||||
func (d *Doc) Data() interface{} {
|
||||
return d.data
|
||||
}
|
||||
|
||||
// Reset resets and empties the internal data object.
|
||||
func (d *Doc) Reset() {
|
||||
d.data = nil
|
||||
// Data returns the internal data object as an interface.
|
||||
func (d *Doc) Copy() (i interface{}) {
|
||||
return pack.Copy(d.data)
|
||||
}
|
||||
|
||||
// ToJSON converts the data object to a JSON byte slice.
|
||||
func (d *Doc) ToJSON() (data []byte) {
|
||||
|
||||
var opt codec.JsonHandle
|
||||
opt.Canonical = true
|
||||
opt.AsSymbols = codec.AsSymbolDefault
|
||||
|
||||
codec.NewEncoderBytes(&data, &opt).Encode(d.data)
|
||||
// JSON converts the data object to a JSON byte slice.
|
||||
func (d *Doc) JSON() (data []byte) {
|
||||
return pack.ToJSON(d.data)
|
||||
}
|
||||
|
||||
// Encode encodes the data object to a byte slice.
|
||||
func (d *Doc) Encode() (dst []byte) {
|
||||
dst = pack.ToPACK(d.data)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// ToCBOR converts the data object to a CBOR byte slice.
|
||||
func (d *Doc) ToCBOR() (data []byte) {
|
||||
|
||||
var opt codec.CborHandle
|
||||
opt.Canonical = true
|
||||
opt.AsSymbols = codec.AsSymbolDefault
|
||||
opt.SetInterfaceExt(reflect.TypeOf(time.Time{}), 1, extTime{})
|
||||
|
||||
codec.NewEncoderBytes(&data, &opt).Encode(d.data)
|
||||
|
||||
return
|
||||
|
||||
// Decode decodes the byte slice into a data object.
|
||||
func (d *Doc) Decode(src []byte) *Doc {
|
||||
pack.FromPACK(src, d.data)
|
||||
return d
|
||||
}
|
||||
|
||||
// ToPACK converts the data object to a MsgPack byte slice.
|
||||
func (d *Doc) ToPACK() (data []byte) {
|
||||
|
||||
var opt codec.MsgpackHandle
|
||||
opt.WriteExt = true
|
||||
opt.Canonical = true
|
||||
opt.AsSymbols = codec.AsSymbolDefault
|
||||
opt.SetBytesExt(reflect.TypeOf(time.Time{}), 1, extTime{})
|
||||
|
||||
codec.NewEncoderBytes(&data, &opt).Encode(d.data)
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
// d.path("this", "is", "a.string", "and.something", "else")
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
func (d *Doc) path(path ...string) (paths []string) {
|
||||
for _, p := range path {
|
||||
|
@ -182,115 +75,233 @@ func (d *Doc) path(path ...string) (paths []string) {
|
|||
return
|
||||
}
|
||||
|
||||
// Search - Attempt to find and return an object within the JSON structure by specifying the hierarchy
|
||||
// of field names to locate the target. If the search encounters an array and has not reached the end
|
||||
// target then it will iterate each object of the array for the target and return all of the results in
|
||||
// a JSON array.
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
// Exists - Checks whether a path exists.
|
||||
func (d *Doc) Exists(path ...string) bool {
|
||||
|
||||
path = d.path(path...)
|
||||
|
||||
var object interface{}
|
||||
|
||||
object = d.data
|
||||
for target := 0; target < len(path); target++ {
|
||||
if mmap, ok := object.(map[string]interface{}); ok {
|
||||
object, ok = mmap[path[target]]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
// Reset empties and resets the data at the specified path.
|
||||
func (d *Doc) Reset(path ...string) (*Doc, error) {
|
||||
return d.Set(nil, path...)
|
||||
}
|
||||
|
||||
// Index - Attempt to find and return an object with a JSON array by specifying the index of the
|
||||
// target.
|
||||
func (d *Doc) Index(index int) *Doc {
|
||||
if array, ok := d.Data().([]interface{}); ok {
|
||||
if index >= len(array) {
|
||||
return &Doc{nil}
|
||||
}
|
||||
return &Doc{array[index]}
|
||||
}
|
||||
return &Doc{nil}
|
||||
// Array sets the specified path to an array.
|
||||
func (d *Doc) Array(path ...string) (*Doc, error) {
|
||||
return d.Set([]interface{}{}, path...)
|
||||
}
|
||||
|
||||
// Children - Return a slice of all the children of the array. This also works for objects, however,
|
||||
// the children returned for an object will NOT be in order and you lose the names of the returned
|
||||
// objects this way.
|
||||
func (d *Doc) Children() ([]*Doc, error) {
|
||||
if array, ok := d.Data().([]interface{}); ok {
|
||||
children := make([]*Doc, len(array))
|
||||
for i := 0; i < len(array); i++ {
|
||||
children[i] = &Doc{array[i]}
|
||||
}
|
||||
return children, nil
|
||||
}
|
||||
return nil, ErrNotArray
|
||||
// Object sets the specified path to an object.
|
||||
func (d *Doc) Object(path ...string) (*Doc, error) {
|
||||
return d.Set(map[string]interface{}{}, path...)
|
||||
}
|
||||
|
||||
// ChildrenMap - Return a map of all the children of an object.
|
||||
func (d *Doc) ChildrenMap() (map[string]*Doc, error) {
|
||||
if mmap, ok := d.Data().(map[string]interface{}); ok {
|
||||
children := map[string]*Doc{}
|
||||
for name, obj := range mmap {
|
||||
children[name] = &Doc{obj}
|
||||
}
|
||||
return children, nil
|
||||
}
|
||||
return nil, ErrNotObj
|
||||
}
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
// Search - Attempt to find and return an object within the JSON structure by specifying the hierarchy
|
||||
// of field names to locate the target. If the search encounters an array and has not reached the end
|
||||
// target then it will iterate each object of the array for the target and return all of the results in
|
||||
// a JSON array.
|
||||
func (d *Doc) Get(path ...string) *Doc {
|
||||
|
||||
path = d.path(path...)
|
||||
|
||||
var object interface{}
|
||||
|
||||
object = d.data
|
||||
for target := 0; target < len(path); target++ {
|
||||
if mmap, ok := object.(map[string]interface{}); ok {
|
||||
object = mmap[path[target]]
|
||||
} else if marray, ok := object.([]interface{}); ok {
|
||||
tmpArray := []interface{}{}
|
||||
for _, val := range marray {
|
||||
tmp := &Doc{val}
|
||||
res := tmp.Get(path[target:]...).Data()
|
||||
if res != nil {
|
||||
tmpArray = append(tmpArray, res)
|
||||
}
|
||||
}
|
||||
if len(tmpArray) == 0 {
|
||||
return &Doc{nil}
|
||||
}
|
||||
return &Doc{tmpArray}
|
||||
} else {
|
||||
return &Doc{nil}
|
||||
}
|
||||
}
|
||||
return &Doc{object}
|
||||
}
|
||||
|
||||
// Set the value at the specified path if it does not exist.
|
||||
// New sets the value at the specified path if it does not exist.
|
||||
func (d *Doc) New(value interface{}, path ...string) (*Doc, error) {
|
||||
if !d.Exists(path...) {
|
||||
return d.Set(value, path...)
|
||||
}
|
||||
return nil, nil
|
||||
return d.Get(path...), nil
|
||||
}
|
||||
|
||||
// Set the value at the specified path.
|
||||
// Iff sets the value at the specified path if it is not nil, or deleted it.
|
||||
func (d *Doc) Iff(value interface{}, path ...string) (*Doc, error) {
|
||||
if value != nil {
|
||||
return d.Set(value, path...)
|
||||
}
|
||||
return &Doc{nil}, d.Del(path...)
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
// Exists checks whether the specified path exists.
|
||||
func (d *Doc) Exists(path ...string) bool {
|
||||
|
||||
path = d.path(path...)
|
||||
|
||||
// If the value found at the current
|
||||
// path part is undefined, then just
|
||||
// return false immediately
|
||||
|
||||
if d.data == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Define the temporary object so
|
||||
// that we can loop over and traverse
|
||||
// down the path parts of the data
|
||||
|
||||
object := d.data
|
||||
|
||||
// Loop over each part of the path
|
||||
// whilst detecting if the data at
|
||||
// the current path is an {} or []
|
||||
|
||||
for k, p := range path {
|
||||
|
||||
// If the value found at the current
|
||||
// path part is an object, then move
|
||||
// to the next part of the path
|
||||
|
||||
if m, ok := object.(map[string]interface{}); ok {
|
||||
if object, ok = m[p]; !ok {
|
||||
return false
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// If the value found at the current
|
||||
// path part is an array, then perform
|
||||
// the query on the specified items
|
||||
|
||||
if a, ok := object.([]interface{}); ok {
|
||||
|
||||
var i int
|
||||
var e error
|
||||
|
||||
if p == "*" {
|
||||
e = errors.New("")
|
||||
} else if p == "first" {
|
||||
i = 0
|
||||
} else if p == "last" {
|
||||
i = len(a) - 1
|
||||
} else {
|
||||
i, e = strconv.Atoi(p)
|
||||
}
|
||||
|
||||
// If the path part is a numeric index
|
||||
// then run the query on the specified
|
||||
// index of the current data array
|
||||
|
||||
if e == nil {
|
||||
if 0 == len(a) || i >= len(a) {
|
||||
return false
|
||||
}
|
||||
return Consume(a[i]).Exists(path[k+1:]...)
|
||||
}
|
||||
|
||||
// If the path part is an asterisk
|
||||
// then run the query on all of the
|
||||
// items in the current data array
|
||||
|
||||
if p == "*" {
|
||||
|
||||
for _, v := range a {
|
||||
if Consume(v).Exists(path[k+1:]...) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
// Get gets the value or values at a specified path.
|
||||
func (d *Doc) Get(path ...string) *Doc {
|
||||
|
||||
path = d.path(path...)
|
||||
|
||||
// If the value found at the current
|
||||
// path part is undefined, then just
|
||||
// return false immediately
|
||||
|
||||
if d.data == nil {
|
||||
return &Doc{nil}
|
||||
}
|
||||
|
||||
// Define the temporary object so
|
||||
// that we can loop over and traverse
|
||||
// down the path parts of the data
|
||||
|
||||
object := d.data
|
||||
|
||||
// Loop over each part of the path
|
||||
// whilst detecting if the data at
|
||||
// the current path is an {} or []
|
||||
|
||||
for k, p := range path {
|
||||
|
||||
// If the value found at the current
|
||||
// path part is an object, then move
|
||||
// to the next part of the path
|
||||
|
||||
if m, ok := object.(map[string]interface{}); ok {
|
||||
object = m[p]
|
||||
continue
|
||||
}
|
||||
|
||||
// If the value found at the current
|
||||
// path part is an array, then perform
|
||||
// the query on the specified items
|
||||
|
||||
if a, ok := object.([]interface{}); ok {
|
||||
|
||||
var i int
|
||||
var e error
|
||||
|
||||
if p == "*" {
|
||||
e = errors.New("")
|
||||
} else if p == "first" {
|
||||
i = 0
|
||||
} else if p == "last" {
|
||||
i = len(a) - 1
|
||||
} else if p == "length" {
|
||||
return &Doc{len(a)}
|
||||
} else {
|
||||
i, e = strconv.Atoi(p)
|
||||
}
|
||||
|
||||
// If the path part is a numeric index
|
||||
// then run the query on the specified
|
||||
// index of the current data array
|
||||
|
||||
if e == nil {
|
||||
if 0 == len(a) || i >= len(a) {
|
||||
return &Doc{nil}
|
||||
}
|
||||
return Consume(a[i]).Get(path[k+1:]...)
|
||||
}
|
||||
|
||||
// If the path part is an asterisk
|
||||
// then run the query on all of the
|
||||
// items in the current data array
|
||||
|
||||
if p == "*" {
|
||||
|
||||
out := []interface{}{}
|
||||
|
||||
for _, v := range a {
|
||||
res := Consume(v).Get(path[k+1:]...)
|
||||
if res.data != nil {
|
||||
out = append(out, res.data)
|
||||
}
|
||||
}
|
||||
|
||||
return &Doc{out}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return &Doc{nil}
|
||||
|
||||
}
|
||||
|
||||
return &Doc{object}
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
// Set sets the value or values at a specified path.
|
||||
func (d *Doc) Set(value interface{}, path ...string) (*Doc, error) {
|
||||
|
||||
path = d.path(path...)
|
||||
|
@ -299,158 +310,372 @@ func (d *Doc) Set(value interface{}, path ...string) (*Doc, error) {
|
|||
d.data = value
|
||||
return d, nil
|
||||
}
|
||||
var object interface{}
|
||||
|
||||
// If the value found at the current
|
||||
// path part is undefined, then ensure
|
||||
// that it is an object
|
||||
|
||||
if d.data == nil {
|
||||
d.data = map[string]interface{}{}
|
||||
}
|
||||
object = d.data
|
||||
for target := 0; target < len(path); target++ {
|
||||
if mmap, ok := object.(map[string]interface{}); ok {
|
||||
if target == len(path)-1 {
|
||||
mmap[path[target]] = value
|
||||
} else if mmap[path[target]] == nil {
|
||||
mmap[path[target]] = map[string]interface{}{}
|
||||
|
||||
// Define the temporary object so
|
||||
// that we can loop over and traverse
|
||||
// down the path parts of the data
|
||||
|
||||
object := d.data
|
||||
|
||||
// Loop over each part of the path
|
||||
// whilst detecting if the data at
|
||||
// the current path is an {} or []
|
||||
|
||||
for k, p := range path {
|
||||
|
||||
// If the value found at the current
|
||||
// path part is an object, then move
|
||||
// to the next part of the path
|
||||
|
||||
if m, ok := object.(map[string]interface{}); ok {
|
||||
if k == len(path)-1 {
|
||||
m[p] = value
|
||||
} else if m[p] == nil {
|
||||
m[p] = map[string]interface{}{}
|
||||
}
|
||||
object = mmap[path[target]]
|
||||
} else {
|
||||
return &Doc{nil}, ErrPathCollision
|
||||
object = m[p]
|
||||
}
|
||||
|
||||
// If the value found at the current
|
||||
// path part is an array, then perform
|
||||
// the query on the specified items
|
||||
|
||||
if a, ok := object.([]interface{}); ok {
|
||||
|
||||
var i int
|
||||
var e error
|
||||
|
||||
if p == "*" {
|
||||
e = errors.New("")
|
||||
} else if p == "first" {
|
||||
i = 0
|
||||
} else if p == "last" {
|
||||
i = len(a) - 1
|
||||
} else {
|
||||
i, e = strconv.Atoi(p)
|
||||
}
|
||||
|
||||
// If the path part is a numeric index
|
||||
// then run the query on the specified
|
||||
// index of the current data array
|
||||
|
||||
if e == nil {
|
||||
|
||||
if 0 == len(a) || i >= len(a) {
|
||||
return &Doc{nil}, fmt.Errorf("No item with index %d in array, using path %s", i, path)
|
||||
}
|
||||
|
||||
if k == len(path)-1 {
|
||||
a[i] = value
|
||||
object = a[i]
|
||||
} else {
|
||||
return Consume(a[i]).Set(value, path[k+1:]...)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If the path part is an asterisk
|
||||
// then run the query on all of the
|
||||
// items in the current data array
|
||||
|
||||
if p == "*" {
|
||||
|
||||
out := []interface{}{}
|
||||
|
||||
for i, _ := range a {
|
||||
|
||||
if k == len(path)-1 {
|
||||
a[i] = value
|
||||
out = append(out, a[i])
|
||||
} else {
|
||||
res, _ := Consume(a[i]).Set(value, path[k+1:]...)
|
||||
if res.data != nil {
|
||||
out = append(out, res.data)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return &Doc{out}, nil
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return &Doc{object}, nil
|
||||
|
||||
}
|
||||
|
||||
// Del - Delete an element at a JSON path, an error is returned if the element does not exist.
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
// Del deletes the value or values at a specified path.
|
||||
func (d *Doc) Del(path ...string) error {
|
||||
|
||||
path = d.path(path...)
|
||||
|
||||
var object interface{}
|
||||
// If the value found at the current
|
||||
// path part is undefined, then return
|
||||
// a not an object error
|
||||
|
||||
if d.data == nil {
|
||||
return ErrNotObj
|
||||
return fmt.Errorf("Item is not an object")
|
||||
}
|
||||
object = d.data
|
||||
for target := 0; target < len(path); target++ {
|
||||
if mmap, ok := object.(map[string]interface{}); ok {
|
||||
if target == len(path)-1 {
|
||||
delete(mmap, path[target])
|
||||
} else if mmap[path[target]] == nil {
|
||||
return ErrNotObj
|
||||
|
||||
// Define the temporary object so
|
||||
// that we can loop over and traverse
|
||||
// down the path parts of the data
|
||||
|
||||
object := d.data
|
||||
|
||||
// Loop over each part of the path
|
||||
// whilst detecting if the data at
|
||||
// the current path is an {} or []
|
||||
|
||||
for k, p := range path {
|
||||
|
||||
// If the value found at the current
|
||||
// path part is an object, then move
|
||||
// to the next part of the path
|
||||
|
||||
if m, ok := object.(map[string]interface{}); ok {
|
||||
if k == len(path)-1 {
|
||||
delete(m, p)
|
||||
} else if m[p] == nil {
|
||||
return fmt.Errorf("Item at path %s is not an object", path)
|
||||
}
|
||||
object = mmap[path[target]]
|
||||
} else {
|
||||
return ErrNotObj
|
||||
object = m[p]
|
||||
}
|
||||
|
||||
// If the value found at the current
|
||||
// path part is an array, then perform
|
||||
// the query on the specified items
|
||||
|
||||
if a, ok := object.([]interface{}); ok {
|
||||
|
||||
var i int
|
||||
var e error
|
||||
|
||||
if p == "*" {
|
||||
e = errors.New("")
|
||||
} else if p == "first" {
|
||||
i = 0
|
||||
} else if p == "last" {
|
||||
i = len(a) - 1
|
||||
} else {
|
||||
i, e = strconv.Atoi(p)
|
||||
}
|
||||
|
||||
// If the path part is a numeric index
|
||||
// then run the query on the specified
|
||||
// index of the current data array
|
||||
|
||||
if e == nil {
|
||||
|
||||
if 0 == len(a) || i >= len(a) {
|
||||
return fmt.Errorf("No item with index %d in array, using path %s", i, path)
|
||||
}
|
||||
|
||||
if k == len(path)-1 {
|
||||
copy(a[i:], a[i+1:])
|
||||
a[len(a)-1] = nil
|
||||
a = a[:len(a)-1]
|
||||
d.Set(a, path[:len(path)-1]...)
|
||||
} else {
|
||||
return Consume(a[i]).Del(path[k+1:]...)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If the path part is an asterisk
|
||||
// then run the query on all of the
|
||||
// items in the current data array
|
||||
|
||||
if p == "*" {
|
||||
|
||||
for i := len(a) - 1; i >= 0; i-- {
|
||||
|
||||
if k == len(path)-1 {
|
||||
copy(a[i:], a[i+1:])
|
||||
a[len(a)-1] = nil
|
||||
a = a[:len(a)-1]
|
||||
d.Set(a, path[:len(path)-1]...)
|
||||
} else {
|
||||
Consume(a[i]).Del(path[k+1:]...)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// SetIndex - Set a value of an array element based on the index.
|
||||
func (d *Doc) SetIndex(value interface{}, index int) (*Doc, error) {
|
||||
if array, ok := d.Data().([]interface{}); ok {
|
||||
if index >= len(array) {
|
||||
return &Doc{nil}, ErrOutOfBounds
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
// ArrayDel appends an item or an array of items to an array at the specified path.
|
||||
func (d *Doc) ArrayAdd(value interface{}, path ...string) (*Doc, error) {
|
||||
|
||||
a, ok := d.Get(path...).Data().([]interface{})
|
||||
if !ok {
|
||||
return &Doc{nil}, fmt.Errorf("Not an array")
|
||||
}
|
||||
|
||||
if values, ok := value.([]interface{}); ok {
|
||||
outer:
|
||||
for _, value := range values {
|
||||
for _, v := range a {
|
||||
if reflect.DeepEqual(v, value) {
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
a = append(a, value)
|
||||
}
|
||||
array[index] = value
|
||||
return &Doc{array[index]}, nil
|
||||
}
|
||||
return &Doc{nil}, ErrNotArray
|
||||
}
|
||||
|
||||
// Array - Create a new JSON array at a path. Returns an error if the path contains a collision with
|
||||
// a non object type.
|
||||
func (d *Doc) Array(path ...string) (*Doc, error) {
|
||||
return d.Set([]interface{}{}, path...)
|
||||
}
|
||||
|
||||
// Object - Create a new JSON object at a path. Returns an error if the path contains a collision with
|
||||
// a non object type.
|
||||
func (d *Doc) Object(path ...string) (*Doc, error) {
|
||||
return d.Set(map[string]interface{}{}, path...)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
// ArrayAdd - Append a unique value onto a JSON array.
|
||||
func (d *Doc) ArrayAdd(value interface{}, path ...string) error {
|
||||
array, ok := d.Get(path...).Data().([]interface{})
|
||||
if !ok {
|
||||
return ErrNotArray
|
||||
}
|
||||
for _, item := range array {
|
||||
if reflect.DeepEqual(item, value) {
|
||||
return ErrNotUnique
|
||||
}
|
||||
}
|
||||
array = append(array, value)
|
||||
_, err := d.Set(array, path...)
|
||||
return err
|
||||
}
|
||||
|
||||
// ArrayDel - Append a unique value onto a JSON array.
|
||||
func (d *Doc) ArrayDel(value interface{}, path ...string) error {
|
||||
array, ok := d.Get(path...).Data().([]interface{})
|
||||
if !ok {
|
||||
return ErrNotArray
|
||||
}
|
||||
for i, item := range array {
|
||||
if reflect.DeepEqual(item, value) {
|
||||
array = append(array[:i], array[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
_, err := d.Set(array, path...)
|
||||
return err
|
||||
}
|
||||
|
||||
// ArrayAppend - Append a value onto a JSON array.
|
||||
func (d *Doc) ArrayAppend(value interface{}, path ...string) error {
|
||||
array, ok := d.Get(path...).Data().([]interface{})
|
||||
if !ok {
|
||||
return ErrNotArray
|
||||
}
|
||||
array = append(array, value)
|
||||
_, err := d.Set(array, path...)
|
||||
return err
|
||||
}
|
||||
|
||||
// ArrayRemove - Remove an element from a JSON array.
|
||||
func (d *Doc) ArrayRemove(index int, path ...string) error {
|
||||
if index < 0 {
|
||||
return ErrOutOfBounds
|
||||
}
|
||||
array, ok := d.Get(path...).Data().([]interface{})
|
||||
if !ok {
|
||||
return ErrNotArray
|
||||
}
|
||||
if index < len(array) {
|
||||
array = append(array[:index], array[index+1:]...)
|
||||
} else {
|
||||
return ErrOutOfBounds
|
||||
for _, v := range a {
|
||||
if reflect.DeepEqual(v, value) {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
a = append(a, value)
|
||||
}
|
||||
_, err := d.Set(array, path...)
|
||||
return err
|
||||
|
||||
return d.Set(a, path...)
|
||||
|
||||
}
|
||||
|
||||
// ArrayElement - Access an element from a JSON array.
|
||||
func (d *Doc) ArrayElement(index int, path ...string) (*Doc, error) {
|
||||
if index < 0 {
|
||||
return &Doc{nil}, ErrOutOfBounds
|
||||
}
|
||||
array, ok := d.Get(path...).Data().([]interface{})
|
||||
// ArrayDel deletes an item or an array of items from an array at the specified path.
|
||||
func (d *Doc) ArrayDel(value interface{}, path ...string) (*Doc, error) {
|
||||
|
||||
a, ok := d.Get(path...).Data().([]interface{})
|
||||
if !ok {
|
||||
return &Doc{nil}, ErrNotArray
|
||||
return &Doc{nil}, fmt.Errorf("Not an array")
|
||||
}
|
||||
if index < len(array) {
|
||||
return &Doc{array[index]}, nil
|
||||
|
||||
if values, ok := value.([]interface{}); ok {
|
||||
for _, value := range values {
|
||||
for i := len(a) - 1; i >= 0; i-- {
|
||||
v := a[i]
|
||||
if reflect.DeepEqual(v, value) {
|
||||
copy(a[i:], a[i+1:])
|
||||
a[len(a)-1] = nil
|
||||
a = a[:len(a)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := len(a) - 1; i >= 0; i-- {
|
||||
v := a[i]
|
||||
if reflect.DeepEqual(v, value) {
|
||||
copy(a[i:], a[i+1:])
|
||||
a[len(a)-1] = nil
|
||||
a = a[:len(a)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
return &Doc{nil}, ErrOutOfBounds
|
||||
|
||||
return d.Set(a, path...)
|
||||
|
||||
}
|
||||
|
||||
// ArrayCount - Count the number of elements in a JSON array.
|
||||
func (d *Doc) ArrayCount(path ...string) (int, error) {
|
||||
if array, ok := d.Get(path...).Data().([]interface{}); ok {
|
||||
return len(array), nil
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
// Contains checks whether the value exists within the array at the specified path.
|
||||
func (d *Doc) Contains(value interface{}, path ...string) bool {
|
||||
|
||||
a, ok := d.Get(path...).Data().([]interface{})
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return 0, ErrNotArray
|
||||
|
||||
for _, v := range a {
|
||||
if reflect.DeepEqual(v, value) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
// Inc increments an item, or appends an item to an array at the specified path.
|
||||
func (d *Doc) Inc(value interface{}, path ...string) (*Doc, error) {
|
||||
|
||||
switch cur := d.Get(path...).Data().(type) {
|
||||
case nil:
|
||||
switch inc := value.(type) {
|
||||
case int64:
|
||||
return d.Set(0+inc, path...)
|
||||
case float64:
|
||||
return d.Set(0+inc, path...)
|
||||
}
|
||||
case int64:
|
||||
switch inc := value.(type) {
|
||||
case int64:
|
||||
return d.Set(cur+inc, path...)
|
||||
case float64:
|
||||
return d.Set(float64(cur)+inc, path...)
|
||||
}
|
||||
case float64:
|
||||
switch inc := value.(type) {
|
||||
case int64:
|
||||
return d.Set(cur+float64(inc), path...)
|
||||
case float64:
|
||||
return d.Set(cur+inc, path...)
|
||||
}
|
||||
case []interface{}:
|
||||
return d.ArrayAdd(value, path...)
|
||||
}
|
||||
|
||||
return &Doc{nil}, fmt.Errorf("Not possible to increment.")
|
||||
|
||||
}
|
||||
|
||||
// Dec decrements an item, or removes an item from an array at the specified path.
|
||||
func (d *Doc) Dec(value interface{}, path ...string) (*Doc, error) {
|
||||
|
||||
switch cur := d.Get(path...).Data().(type) {
|
||||
case nil:
|
||||
switch inc := value.(type) {
|
||||
case int64:
|
||||
return d.Set(0-inc, path...)
|
||||
case float64:
|
||||
return d.Set(0-inc, path...)
|
||||
}
|
||||
case int64:
|
||||
switch inc := value.(type) {
|
||||
case int64:
|
||||
return d.Set(cur-inc, path...)
|
||||
case float64:
|
||||
return d.Set(float64(cur)-inc, path...)
|
||||
}
|
||||
case float64:
|
||||
switch inc := value.(type) {
|
||||
case int64:
|
||||
return d.Set(cur-float64(inc), path...)
|
||||
case float64:
|
||||
return d.Set(cur-inc, path...)
|
||||
}
|
||||
case []interface{}:
|
||||
return d.ArrayDel(value, path...)
|
||||
}
|
||||
|
||||
return &Doc{nil}, fmt.Errorf("Not possible to decrement.")
|
||||
|
||||
}
|
||||
|
|
783
util/data/data_test.go
Normal file
783
util/data/data_test.go
Normal file
|
@ -0,0 +1,783 @@
|
|||
// Copyright © 2016 Abcum Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package data
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestConversion(t *testing.T) {
|
||||
|
||||
Convey("Can encode and decode", t, func() {
|
||||
doc := Consume(map[string]interface{}{
|
||||
"bool": true,
|
||||
"time": time.Now().UTC(),
|
||||
})
|
||||
enc := doc.Encode()
|
||||
dec := doc.Decode(enc)
|
||||
So(doc, ShouldResemble, dec)
|
||||
So(doc.JSON(), ShouldResemble, dec.JSON())
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestOperations(t *testing.T) {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Ability to set and del nil
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Convey("Can get nil", t, func() {
|
||||
doc := Consume(nil)
|
||||
So(doc, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Exists("nil"), ShouldBeFalse)
|
||||
So(doc.Get("nil").Data(), ShouldEqual, nil)
|
||||
})
|
||||
|
||||
Convey("Can set nil", t, func() {
|
||||
doc := Consume(nil)
|
||||
set, err := doc.Set("OK", "nil")
|
||||
So(err, ShouldBeNil)
|
||||
So(doc, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(set.Data(), ShouldResemble, "OK")
|
||||
So(doc.Get("nil").Data(), ShouldEqual, "OK")
|
||||
})
|
||||
|
||||
Convey("Can't del nil", t, func() {
|
||||
doc := Consume(nil)
|
||||
err := doc.Del("nil")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Ability to attempt new()
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Convey("Can attempt to use New()", t, func() {
|
||||
doc := New()
|
||||
one, err := doc.New("OK", "item")
|
||||
So(err, ShouldBeNil)
|
||||
So(one.Data(), ShouldEqual, "OK")
|
||||
So(doc.Exists("item"), ShouldBeTrue)
|
||||
So(doc.Get("item").Data(), ShouldEqual, "OK")
|
||||
two, err := doc.New("NOT OK", "item")
|
||||
So(err, ShouldBeNil)
|
||||
So(two.Data(), ShouldEqual, "OK")
|
||||
So(doc.Exists("item"), ShouldBeTrue)
|
||||
So(doc.Get("item").Data(), ShouldEqual, "OK")
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Ability to attempt iff()
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Convey("Can attempt to use Iff()", t, func() {
|
||||
doc := New()
|
||||
one, err := doc.Iff("OK", "item")
|
||||
So(err, ShouldBeNil)
|
||||
So(one.Data(), ShouldEqual, "OK")
|
||||
So(doc.Exists("item"), ShouldBeTrue)
|
||||
So(doc.Get("item").Data(), ShouldEqual, "OK")
|
||||
two, err := doc.Iff(nil, "item")
|
||||
So(err, ShouldBeNil)
|
||||
So(two.Data(), ShouldEqual, nil)
|
||||
So(doc.Exists("item"), ShouldBeFalse)
|
||||
So(doc.Get("item").Data(), ShouldEqual, nil)
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Ability to set and get array
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Convey("Can set base array", t, func() {
|
||||
doc := New()
|
||||
obj, err := doc.Array("array")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("array").Data(), ShouldResemble, []interface{}{})
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Ability to set and get object
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Convey("Can set base object", t, func() {
|
||||
doc := New()
|
||||
obj, err := doc.Object("object")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("object").Data(), ShouldResemble, map[string]interface{}{})
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Ability to set and get basic types
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Convey("Can set and get basic number", t, func() {
|
||||
doc := New()
|
||||
obj, err := doc.Set(1, "number")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("number").Data(), ShouldResemble, 1)
|
||||
})
|
||||
|
||||
Convey("Can set and get basic string", t, func() {
|
||||
doc := New()
|
||||
obj, err := doc.Set("a", "string")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("string").Data(), ShouldResemble, "a")
|
||||
})
|
||||
|
||||
Convey("Can set and get basic array", t, func() {
|
||||
doc := New()
|
||||
obj, err := doc.Set([]interface{}{1, 2, 3}, "array")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("array").Data(), ShouldResemble, []interface{}{1, 2, 3})
|
||||
})
|
||||
|
||||
Convey("Can set and get basic object", t, func() {
|
||||
doc := New()
|
||||
obj, err := doc.Set(map[string]interface{}{"test": true}, "object")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("object").Data(), ShouldResemble, map[string]interface{}{"test": true})
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Ability to set and get basic embedded types
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Convey("Can set and get basic embedded number", t, func() {
|
||||
doc := New()
|
||||
obj, err := doc.Set(1, "sub.number")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("sub.number").Data(), ShouldResemble, 1)
|
||||
})
|
||||
|
||||
Convey("Can set and get basic embedded string", t, func() {
|
||||
doc := New()
|
||||
obj, err := doc.Set("a", "sub.string")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("sub.string").Data(), ShouldResemble, "a")
|
||||
})
|
||||
|
||||
Convey("Can set and get basic embedded array", t, func() {
|
||||
doc := New()
|
||||
obj, err := doc.Set([]interface{}{1, 2, 3}, "sub.array")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("sub.array").Data(), ShouldResemble, []interface{}{1, 2, 3})
|
||||
})
|
||||
|
||||
Convey("Can set and get basic embedded object", t, func() {
|
||||
doc := New()
|
||||
obj, err := doc.Set(map[string]interface{}{"test": true}, "sub.object")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("sub.object").Data(), ShouldResemble, map[string]interface{}{"test": true})
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Ability to inc and dec basic types
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Convey("Can inc basic number", t, func() {
|
||||
doc := New()
|
||||
obj, err := doc.Inc(int64(100), "number")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("number").Data(), ShouldResemble, int64(100))
|
||||
})
|
||||
|
||||
Convey("Can dec basic number", t, func() {
|
||||
doc := New()
|
||||
obj, err := doc.Dec(int64(100), "number")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("number").Data(), ShouldResemble, int64(-100))
|
||||
})
|
||||
|
||||
Convey("Can inc basic double", t, func() {
|
||||
doc := New()
|
||||
obj, err := doc.Inc(float64(100), "double")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("double").Data(), ShouldResemble, float64(100))
|
||||
})
|
||||
|
||||
Convey("Can dec basic double", t, func() {
|
||||
doc := New()
|
||||
obj, err := doc.Dec(float64(100), "double")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("double").Data(), ShouldResemble, float64(-100))
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
doc := New()
|
||||
|
||||
obj := map[string]interface{}{
|
||||
"bool": true,
|
||||
"number": 10,
|
||||
"string": "s",
|
||||
"tags": []interface{}{
|
||||
"Hot",
|
||||
},
|
||||
"object": map[string]interface{}{
|
||||
"enabled": false,
|
||||
},
|
||||
"arrays": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"one": "one",
|
||||
"selected": map[string]interface{}{
|
||||
"city": "London",
|
||||
},
|
||||
"addresses": []interface{}{
|
||||
map[string]interface{}{
|
||||
"city": "London",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"city": "New York",
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": 2,
|
||||
"two": "two",
|
||||
"selected": map[string]interface{}{
|
||||
"city": "Tonbridge",
|
||||
},
|
||||
"addresses": []interface{}{
|
||||
map[string]interface{}{
|
||||
"city": "Paris",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"city": "Tonbridge",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can't del undefined", t, func() {
|
||||
err := doc.Del("the.item")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Can set object", t, func() {
|
||||
def, err := doc.Set(obj, "the.item")
|
||||
So(err, ShouldBeNil)
|
||||
So(def, ShouldHaveSameTypeAs, &Doc{})
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Does unset item exist", t, func() {
|
||||
So(doc.Exists("the.none"), ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Does item exist", t, func() {
|
||||
So(doc.Exists("the.item"), ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Does array item exist", t, func() {
|
||||
So(doc.Exists("the.item.arrays.0.id"), ShouldBeTrue)
|
||||
So(doc.Exists("the.item.arrays.first.id"), ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Does array item exist", t, func() {
|
||||
So(doc.Exists("the.item.arrays.1.id"), ShouldBeTrue)
|
||||
So(doc.Exists("the.item.arrays.last.id"), ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Does out of bounds array item exist", t, func() {
|
||||
So(doc.Exists("the.item.arrays.5.id"), ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Does unset array item exist", t, func() {
|
||||
So(doc.Exists("the.item.arrays.0.none"), ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Does incorrectly embedded array item exist", t, func() {
|
||||
So(doc.Exists("the.item.arrays.0.id.arggghh"), ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Does incorrectly embedded object item exist", t, func() {
|
||||
So(doc.Exists("the.item.object.enabled.arggghh"), ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Does multi array item exist", t, func() {
|
||||
So(doc.Exists("the.item.arrays.*.id"), ShouldBeTrue)
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can get unset item", t, func() {
|
||||
So(doc.Get("the.item.none").Data(), ShouldResemble, nil)
|
||||
So(doc.Get("the.item.none.arggghh").Data(), ShouldResemble, nil)
|
||||
})
|
||||
|
||||
Convey("Can set unset item", t, func() {
|
||||
set, err := doc.Set("OK", "the.item.none")
|
||||
So(err, ShouldBeNil)
|
||||
So(set.Data(), ShouldResemble, "OK")
|
||||
So(doc.Get("the.item.none").Data(), ShouldResemble, "OK")
|
||||
})
|
||||
|
||||
Convey("Can del unset item", t, func() {
|
||||
err := doc.Del("the.item.none")
|
||||
So(err, ShouldBeNil)
|
||||
So(doc.Get("the.item.none").Data(), ShouldResemble, nil)
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can get basic bool", t, func() {
|
||||
So(doc.Get("the.item.bool").Data(), ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Can set basic bool", t, func() {
|
||||
set, err := doc.Set(false, "the.item.bool")
|
||||
So(err, ShouldBeNil)
|
||||
So(set.Data(), ShouldBeFalse)
|
||||
So(doc.Get("the.item.bool").Data(), ShouldBeFalse)
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can get basic number", t, func() {
|
||||
So(doc.Get("the.item.number").Data(), ShouldResemble, 10)
|
||||
})
|
||||
|
||||
Convey("Can set basic number", t, func() {
|
||||
set, err := doc.Set(20, "the.item.number")
|
||||
So(err, ShouldBeNil)
|
||||
So(set.Data(), ShouldResemble, 20)
|
||||
So(doc.Get("the.item.number").Data(), ShouldResemble, 20)
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can get basic string", t, func() {
|
||||
So(doc.Get("the.item.string").Data(), ShouldResemble, "s")
|
||||
})
|
||||
|
||||
Convey("Can set basic string", t, func() {
|
||||
set, err := doc.Set("t", "the.item.string")
|
||||
So(err, ShouldBeNil)
|
||||
So(set.Data(), ShouldResemble, "t")
|
||||
So(doc.Get("the.item.string").Data(), ShouldResemble, "t")
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can inc += 1", t, func() {
|
||||
obj, err := doc.Inc(int64(1), "the.item.tester")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("the.item.tester").Data(), ShouldResemble, int64(1))
|
||||
})
|
||||
|
||||
Convey("Can inc += 4", t, func() {
|
||||
obj, err := doc.Inc(int64(4), "the.item.tester")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("the.item.tester").Data(), ShouldResemble, int64(5))
|
||||
})
|
||||
|
||||
Convey("Can inc += 3.87659", t, func() {
|
||||
obj, err := doc.Inc(float64(3.87659), "the.item.tester")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("the.item.tester").Data(), ShouldResemble, float64(8.87659))
|
||||
})
|
||||
|
||||
Convey("Can inc += 1.12341", t, func() {
|
||||
obj, err := doc.Inc(float64(1.12341), "the.item.tester")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("the.item.tester").Data(), ShouldResemble, float64(10))
|
||||
})
|
||||
|
||||
Convey("Can inc += 5", t, func() {
|
||||
obj, err := doc.Inc(int64(5), "the.item.tester")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("the.item.tester").Data(), ShouldResemble, float64(15))
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can reset tester", t, func() {
|
||||
obj, err := doc.Set(int64(15), "the.item.tester")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("the.item.tester").Data(), ShouldResemble, int64(15))
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can dec -= 5", t, func() {
|
||||
obj, err := doc.Dec(int64(5), "the.item.tester")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("the.item.tester").Data(), ShouldResemble, int64(10))
|
||||
})
|
||||
|
||||
Convey("Can dec -= 1.12341", t, func() {
|
||||
obj, err := doc.Dec(float64(1.12341), "the.item.tester")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("the.item.tester").Data(), ShouldResemble, float64(8.87659))
|
||||
})
|
||||
|
||||
Convey("Can dec -= 3.87659", t, func() {
|
||||
obj, err := doc.Dec(float64(3.87659), "the.item.tester")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("the.item.tester").Data(), ShouldResemble, float64(5))
|
||||
})
|
||||
|
||||
Convey("Can dec -= 4", t, func() {
|
||||
obj, err := doc.Dec(int64(4), "the.item.tester")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("the.item.tester").Data(), ShouldResemble, float64(1))
|
||||
})
|
||||
|
||||
Convey("Can dec -= 1", t, func() {
|
||||
obj, err := doc.Dec(int64(1), "the.item.tester")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("the.item.tester").Data(), ShouldResemble, float64(0))
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can reset bool", t, func() {
|
||||
obj, err := doc.Set(true, "the.item.bool")
|
||||
So(err, ShouldBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("the.item.bool").Data(), ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Can't inc non incable item", t, func() {
|
||||
obj, err := doc.Inc(int64(1), "the.item.bool")
|
||||
So(err, ShouldNotBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("the.item.bool").Data(), ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Can't dec non decable item", t, func() {
|
||||
obj, err := doc.Dec(int64(1), "the.item.bool")
|
||||
So(err, ShouldNotBeNil)
|
||||
So(obj, ShouldHaveSameTypeAs, &Doc{})
|
||||
So(doc.Get("the.item.bool").Data(), ShouldBeTrue)
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can get array", t, func() {
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Hot"})
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 1)
|
||||
})
|
||||
|
||||
Convey("Can set array", t, func() {
|
||||
set, err := doc.Set([]interface{}{"Hot", "Humid", "Sticky", "Warm"}, "the.item.tags")
|
||||
So(err, ShouldBeNil)
|
||||
So(set.Data(), ShouldResemble, []interface{}{"Hot", "Humid", "Sticky", "Warm"})
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Hot", "Humid", "Sticky", "Warm"})
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 4)
|
||||
})
|
||||
|
||||
Convey("Can see if array contains valid", t, func() {
|
||||
So(doc.Contains("Hot", "the.item.tags"), ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Can see if array contains invalid", t, func() {
|
||||
So(doc.Contains("Cold", "the.item.tags"), ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Can add single to array", t, func() {
|
||||
_, err := doc.Inc("Sunny", "the.item.tags")
|
||||
So(err, ShouldBeNil)
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Hot", "Humid", "Sticky", "Warm", "Sunny"})
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 5)
|
||||
})
|
||||
|
||||
Convey("Can add duplicate to array", t, func() {
|
||||
_, err := doc.Inc("Sunny", "the.item.tags")
|
||||
So(err, ShouldBeNil)
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Hot", "Humid", "Sticky", "Warm", "Sunny"})
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 5)
|
||||
})
|
||||
|
||||
Convey("Can add multiple to array", t, func() {
|
||||
_, err := doc.Inc([]interface{}{"Sunny", "Snowy", "Icy"}, "the.item.tags")
|
||||
So(err, ShouldBeNil)
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Hot", "Humid", "Sticky", "Warm", "Sunny", "Snowy", "Icy"})
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 7)
|
||||
})
|
||||
|
||||
Convey("Can del single from array", t, func() {
|
||||
_, err := doc.Dec("Sunny", "the.item.tags")
|
||||
So(err, ShouldBeNil)
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Hot", "Humid", "Sticky", "Warm", "Snowy", "Icy"})
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 6)
|
||||
})
|
||||
|
||||
Convey("Can del multiple from array", t, func() {
|
||||
_, err := doc.Dec([]interface{}{"Snowy", "Icy"}, "the.item.tags")
|
||||
So(err, ShouldBeNil)
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Hot", "Humid", "Sticky", "Warm"})
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 4)
|
||||
})
|
||||
|
||||
Convey("Can get array → *", t, func() {
|
||||
So(doc.Get("the.item.tags.*").Data(), ShouldResemble, []interface{}{"Hot", "Humid", "Sticky", "Warm"})
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 4)
|
||||
})
|
||||
|
||||
Convey("Can del array → 2", t, func() {
|
||||
err := doc.Del("the.item.tags.2")
|
||||
So(err, ShouldBeNil)
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Hot", "Humid", "Warm"})
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 3)
|
||||
})
|
||||
|
||||
Convey("Can't del array → 5", t, func() {
|
||||
err := doc.Del("the.item.tags.5")
|
||||
So(err, ShouldNotBeNil)
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Hot", "Humid", "Warm"})
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 3)
|
||||
})
|
||||
|
||||
Convey("Can set array → 0", t, func() {
|
||||
set, err := doc.Set("Tepid", "the.item.tags.0")
|
||||
So(err, ShouldBeNil)
|
||||
So(set.Data(), ShouldResemble, "Tepid")
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Tepid", "Humid", "Warm"})
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 3)
|
||||
})
|
||||
|
||||
Convey("Can't set array → 5", t, func() {
|
||||
set, err := doc.Set("Other", "the.item.tags.5")
|
||||
So(err, ShouldNotBeNil)
|
||||
So(set.Data(), ShouldResemble, nil)
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Tepid", "Humid", "Warm"})
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 3)
|
||||
})
|
||||
|
||||
Convey("Can set array → first", t, func() {
|
||||
set, err := doc.Set("Test1", "the.item.tags.first")
|
||||
So(err, ShouldBeNil)
|
||||
So(set.Data(), ShouldResemble, "Test1")
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Test1", "Humid", "Warm"})
|
||||
So(doc.Get("the.item.tags.0").Data(), ShouldResemble, doc.Get("the.item.tags.first").Data())
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 3)
|
||||
})
|
||||
|
||||
Convey("Can set array → last", t, func() {
|
||||
set, err := doc.Set("Test2", "the.item.tags.last")
|
||||
So(err, ShouldBeNil)
|
||||
So(set.Data(), ShouldResemble, "Test2")
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Test1", "Humid", "Test2"})
|
||||
So(doc.Get("the.item.tags.2").Data(), ShouldResemble, doc.Get("the.item.tags.last").Data())
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 3)
|
||||
})
|
||||
|
||||
Convey("Can del array → first", t, func() {
|
||||
err := doc.Del("the.item.tags.first")
|
||||
So(err, ShouldBeNil)
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Humid", "Test2"})
|
||||
So(doc.Get("the.item.tags.0").Data(), ShouldResemble, doc.Get("the.item.tags.first").Data())
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 2)
|
||||
})
|
||||
|
||||
Convey("Can del array → last", t, func() {
|
||||
err := doc.Del("the.item.tags.last")
|
||||
So(err, ShouldBeNil)
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Humid"})
|
||||
So(doc.Get("the.item.tags.0").Data(), ShouldResemble, doc.Get("the.item.tags.last").Data())
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 1)
|
||||
})
|
||||
|
||||
Convey("Can set array → *", t, func() {
|
||||
set, err := doc.Set("Unknown", "the.item.tags.*")
|
||||
So(err, ShouldBeNil)
|
||||
So(set.Data(), ShouldResemble, []interface{}{"Unknown"})
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{"Unknown"})
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 1)
|
||||
})
|
||||
|
||||
Convey("Can del array → *", t, func() {
|
||||
err := doc.Del("the.item.tags.*")
|
||||
So(err, ShouldBeNil)
|
||||
So(doc.Get("the.item.tags").Data(), ShouldResemble, []interface{}{})
|
||||
So(doc.Get("the.item.tags.length").Data(), ShouldResemble, 0)
|
||||
})
|
||||
|
||||
Convey("Can del array", t, func() {
|
||||
err := doc.Del("the.item.tags")
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("Can't add to not array", t, func() {
|
||||
_, err := doc.ArrayAdd("None", "the.item.tags")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Can't del from not array", t, func() {
|
||||
_, err := doc.ArrayDel("None", "the.item.tags")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Can't see if array contains", t, func() {
|
||||
So(doc.Contains("None", "the.item.tags"), ShouldBeFalse)
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can get object → key", t, func() {
|
||||
So(doc.Get("the.item.object.enabled").Data(), ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Can set object → key", t, func() {
|
||||
set, err := doc.Set(true, "the.item.object.enabled")
|
||||
So(err, ShouldBeNil)
|
||||
So(set.Data(), ShouldBeTrue)
|
||||
So(doc.Get("the.item.object.enabled").Data(), ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Can del object → key", t, func() {
|
||||
err := doc.Del("the.item.object.enabled")
|
||||
So(err, ShouldBeNil)
|
||||
So(doc.Exists("the.item.object.enabled"), ShouldBeFalse)
|
||||
So(doc.Get("the.item.object.enabled").Data(), ShouldResemble, nil)
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can get array → * → key", t, func() {
|
||||
So(doc.Get("the.item.arrays.*.id").Data(), ShouldResemble, []interface{}{1, 2})
|
||||
})
|
||||
|
||||
Convey("Can set array → * → key", t, func() {
|
||||
set, err := doc.Set("ID", "the.item.arrays.*.id")
|
||||
So(err, ShouldBeNil)
|
||||
So(set.Data(), ShouldResemble, []interface{}{"ID", "ID"})
|
||||
So(doc.Get("the.item.arrays.*.id").Data(), ShouldResemble, []interface{}{"ID", "ID"})
|
||||
})
|
||||
|
||||
Convey("Can set array → 0 → key", t, func() {
|
||||
set, err := doc.Set("ID1", "the.item.arrays.0.id")
|
||||
So(err, ShouldBeNil)
|
||||
So(set.Data(), ShouldResemble, "ID1")
|
||||
So(doc.Get("the.item.arrays.0.id").Data(), ShouldResemble, "ID1")
|
||||
So(doc.Get("the.item.arrays.*.id").Data(), ShouldResemble, []interface{}{"ID1", "ID"})
|
||||
})
|
||||
|
||||
Convey("Can set array → 1 → key", t, func() {
|
||||
set, err := doc.Set("ID2", "the.item.arrays.1.id")
|
||||
So(err, ShouldBeNil)
|
||||
So(set.Data(), ShouldResemble, "ID2")
|
||||
So(doc.Get("the.item.arrays.1.id").Data(), ShouldResemble, "ID2")
|
||||
So(doc.Get("the.item.arrays.*.id").Data(), ShouldResemble, []interface{}{"ID1", "ID2"})
|
||||
})
|
||||
|
||||
Convey("Can del array → 0 → key", t, func() {
|
||||
err := doc.Del("the.item.arrays.0.id")
|
||||
So(err, ShouldBeNil)
|
||||
So(doc.Get("the.item.arrays.0.id").Data(), ShouldResemble, nil)
|
||||
So(doc.Get("the.item.arrays.*.id").Data(), ShouldResemble, []interface{}{"ID2"})
|
||||
})
|
||||
|
||||
Convey("Can del array → * → key", t, func() {
|
||||
err := doc.Del("the.item.arrays.*.id")
|
||||
So(err, ShouldBeNil)
|
||||
So(doc.Get("the.item.arrays.0.id").Data(), ShouldResemble, nil)
|
||||
So(doc.Get("the.item.arrays.*.id").Data(), ShouldResemble, []interface{}{})
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can get object → key", t, func() {
|
||||
So(doc.Get("the.item.arrays.*.one").Data(), ShouldResemble, []interface{}{"one"})
|
||||
})
|
||||
|
||||
Convey("Can get object → key", t, func() {
|
||||
So(doc.Get("the.item.arrays.*.two").Data(), ShouldResemble, []interface{}{"two"})
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can get array → * → object → !", t, func() {
|
||||
So(doc.Get("the.item.arrays.*.selected.none").Data(), ShouldResemble, []interface{}{})
|
||||
})
|
||||
|
||||
Convey("Can set array → * → object → !", t, func() {
|
||||
set, err := doc.Set("OK", "the.item.arrays.*.selected.none")
|
||||
So(err, ShouldBeNil)
|
||||
So(set.Data(), ShouldResemble, []interface{}{"OK", "OK"})
|
||||
So(doc.Get("the.item.arrays.*.selected.none").Data(), ShouldResemble, []interface{}{"OK", "OK"})
|
||||
})
|
||||
|
||||
Convey("Can get array → * → object → key", t, func() {
|
||||
So(doc.Get("the.item.arrays.*.selected.city").Data(), ShouldResemble, []interface{}{"London", "Tonbridge"})
|
||||
})
|
||||
|
||||
Convey("Can get array → 0 → arrays → 0 → key", t, func() {
|
||||
So(doc.Get("the.item.arrays.0.addresses.0.city").Data(), ShouldResemble, "London")
|
||||
})
|
||||
|
||||
Convey("Can get array → * → arrays → 0 → key", t, func() {
|
||||
So(doc.Get("the.item.arrays.*.addresses.0.city").Data(), ShouldResemble, []interface{}{"London", "Paris"})
|
||||
})
|
||||
|
||||
Convey("Can get array → * → arrays → * → key", t, func() {
|
||||
So(doc.Get("the.item.arrays.*.addresses.*.city").Data(), ShouldResemble, []interface{}{[]interface{}{"London", "New York"}, []interface{}{"Paris", "Tonbridge"}})
|
||||
})
|
||||
|
||||
Convey("Can get array → ! → arrays → 0 → key", t, func() {
|
||||
So(doc.Get("the.item.arrays.5.addresses.0.city").Data(), ShouldResemble, nil)
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can copy object", t, func() {
|
||||
So(doc.Copy(), ShouldResemble, doc.Data())
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
Convey("Can reset object", t, func() {
|
||||
_, err := doc.Reset()
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
// Copyright © 2016 Abcum Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package data
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type extTime struct{}
|
||||
|
||||
func (x extTime) ReadExt(dst interface{}, src []byte) {
|
||||
dst.(*time.Time).UnmarshalBinary(src)
|
||||
}
|
||||
|
||||
func (x extTime) WriteExt(src interface{}) (dst []byte) {
|
||||
switch obj := src.(type) {
|
||||
case time.Time:
|
||||
dst, _ = obj.MarshalBinary()
|
||||
case *time.Time:
|
||||
dst, _ = obj.MarshalBinary()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (x extTime) UpdateExt(dest interface{}, v interface{}) {
|
||||
tt := dest.(*time.Time)
|
||||
switch v2 := v.(type) {
|
||||
case int64:
|
||||
*tt = time.Unix(0, v2).UTC()
|
||||
case uint64:
|
||||
*tt = time.Unix(0, int64(v2)).UTC()
|
||||
}
|
||||
}
|
||||
|
||||
func (x extTime) ConvertExt(v interface{}) interface{} {
|
||||
switch v2 := v.(type) {
|
||||
case time.Time:
|
||||
return v2.UTC().UnixNano()
|
||||
case *time.Time:
|
||||
return v2.UTC().UnixNano()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue