Permalink
Browse files

Add SetSeparator OptionFunc (#35)

  • Loading branch information...
thedevsaddam authored and Saddam H committed Jan 10, 2019
1 parent 0935eb3 commit 81d5dc239268d1528a240ec72739b1a69b430b97
Showing with 47 additions and 16 deletions.
  1. +9 −8 helper.go
  2. +1 −1 helper_test.go
  3. +10 −6 jsonq.go
  4. +13 −1 option.go
  5. +14 −0 option_test.go
@@ -103,10 +103,11 @@ func sortList(list []interface{}, asc bool) []interface{} {
}

type sortMap struct {
data interface{}
key string
desc bool
errs []error
data interface{}
key string
desc bool
seperator string
errs []error
}

// Sort sorts the slice of maps
@@ -141,11 +142,11 @@ func (s *sortMap) Less(i, j int) (res bool) {

// compare nested values
if strings.Contains(s.key, ".") {
xv, errX := getNestedValue(x, s.key)
xv, errX := getNestedValue(x, s.key, s.seperator)
if errX != nil {
s.errs = append(s.errs, errX)
}
yv, errY := getNestedValue(y, s.key)
yv, errY := getNestedValue(y, s.key, s.seperator)
if errY != nil {
s.errs = append(s.errs, errY)
}
@@ -189,8 +190,8 @@ func (s *sortMap) compare(x, y interface{}) (res bool) {
}

// getNestedValue fetch nested value from node
func getNestedValue(input interface{}, node string) (interface{}, error) {
pp := strings.Split(node, ".")
func getNestedValue(input interface{}, node, seperator string) (interface{}, error) {
pp := strings.Split(node, seperator)
for _, n := range pp {
if isIndex(n) {
// find slice/array
@@ -375,7 +375,7 @@ func Test_getNestedValue(t *testing.T) {
}

for _, tc := range testCases {
out, err := getNestedValue(content, tc.query)
out, err := getNestedValue(content, tc.query, defaultSeperator)
if tc.expectError && err == nil {
t.Error("failed to catch error")
}
@@ -13,7 +13,8 @@ func New(options ...OptionFunc) *JSONQ {
jq := &JSONQ{
queryMap: loadDefaultQueryMap(),
option: option{
decoder: &DefaultDecoder{},
decoder: &DefaultDecoder{},
separator: defaultSeperator,
},
}
for _, option := range options {
@@ -27,6 +28,8 @@ func New(options ...OptionFunc) *JSONQ {
// empty represents an empty result
var empty interface{}

const defaultSeperator = "."

// query describes a query
type query struct {
key, operator string
@@ -132,7 +135,7 @@ func (j *JSONQ) Macro(operator string, fn QueryFunc) *JSONQ {
// From seeks the json content to provided node. e.g: "users.[0]" or "users.[0].name"
func (j *JSONQ) From(node string) *JSONQ {
j.node = node
v, err := getNestedValue(j.jsonContent, node)
v, err := getNestedValue(j.jsonContent, node, j.option.separator)
if err != nil {
j.addError(err)
}
@@ -285,7 +288,7 @@ func (j *JSONQ) findInMap(vm map[string]interface{}) []interface{} {
j.addError(fmt.Errorf("invalid operator %s", q.operator))
return result
}
nv, errnv := getNestedValue(vm, q.key)
nv, errnv := getNestedValue(vm, q.key, j.option.separator)
if errnv != nil {
j.addError(errnv)
andPassed = false
@@ -330,7 +333,7 @@ func (j *JSONQ) GroupBy(property string) *JSONQ {
if aa, ok := j.jsonContent.([]interface{}); ok {
for _, a := range aa {
if vm, ok := a.(map[string]interface{}); ok {
v, err := getNestedValue(vm, property)
v, err := getNestedValue(vm, property, j.option.separator)
if err != nil {
j.addError(err)
} else {
@@ -394,7 +397,7 @@ func (j *JSONQ) distinct() *JSONQ {
if aa, ok := j.jsonContent.([]interface{}); ok {
for _, a := range aa {
if vm, ok := a.(map[string]interface{}); ok {
v, err := getNestedValue(vm, j.distinctProperty)
v, err := getNestedValue(vm, j.distinctProperty, j.option.separator)
if err != nil {
j.addError(err)
} else {
@@ -422,6 +425,7 @@ func (j *JSONQ) sortBy(property string, asc bool) *JSONQ {
}

sm := &sortMap{}
sm.seperator = j.option.separator
sm.key = property
if !asc {
sm.desc = true
@@ -448,7 +452,7 @@ func (j *JSONQ) only(properties ...string) interface{} {
tmap := map[string]interface{}{}
for _, prop := range properties {
node, alias := makeAlias(prop)
rv, errV := getNestedValue(am, node)
rv, errV := getNestedValue(am, node, j.option.separator)
if errV != nil {
j.addError(errV)
continue
@@ -4,7 +4,8 @@ import "errors"

// option describes type for providing configuration options to JSONQ
type option struct {
decoder Decoder
decoder Decoder
separator string
}

// OptionFunc represents a contract for option func, it basically set options to jsonq instance options
@@ -20,3 +21,14 @@ func SetDecoder(u Decoder) OptionFunc {
return nil
}
}

// SetSeparator set custom seperator for traversing child node, default seperator is DOT (.)
func SetSeparator(s string) OptionFunc {
return func(j *JSONQ) error {
if s == "" {
return errors.New("seperator can not be empty")
}
j.option.separator = s
return nil
}
}
@@ -17,3 +17,17 @@ func TestSetDecoder_with_nil_expecting_an_error(t *testing.T) {
t.Error("failed to catch nil in SetDecoder")
}
}

func TestSetSeparator(t *testing.T) {
jq := New(SetSeparator("->"))
if jq.option.separator != "->" {
t.Error("failed to set separator as option")
}
}

func TestSetSeparator_with_nil_expecting_an_error(t *testing.T) {
jq := New(SetSeparator(""))
if jq.Error() == nil {
t.Error("failed to catch nil in SetSeparator")
}
}

0 comments on commit 81d5dc2

Please sign in to comment.