Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 45 additions & 6 deletions accessors.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,18 @@ const (
// arrayAccesRegexString is the regex used to extract the array number
// from the access path
arrayAccesRegexString = `^(.+)\[([0-9]+)\]$`

// mapAccessRegexString is the regex used to extract the map key
// from the access path
mapAccessRegexString = `^([^\[]*)\[([^\]]+)\](.*)$`
)

// arrayAccesRegex is the compiled arrayAccesRegexString
var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString)

// mapAccessRegex is the compiled mapAccessRegexString
var mapAccessRegex = regexp.MustCompile(mapAccessRegexString)

// Get gets the value using the specified selector and
// returns it inside a new Obj object.
//
Expand Down Expand Up @@ -70,13 +77,45 @@ func getIndex(s string) (int, string) {
return -1, s
}

// getKey returns the key which is held in s by two brackets.
// It also returns the next selector.
func getKey(s string) (string, string) {
selSegs := strings.SplitN(s, PathSeparator, 2)
thisSel := selSegs[0]
nextSel := ""

if len(selSegs) > 1 {
nextSel = selSegs[1]
}

mapMatches := mapAccessRegex.FindStringSubmatch(s)
if len(mapMatches) > 0 {
if _, err := strconv.Atoi(mapMatches[2]); err != nil {
thisSel = mapMatches[1]
nextSel = "[" + mapMatches[2] + "]" + mapMatches[3]

if thisSel == "" {
thisSel = mapMatches[2]
nextSel = mapMatches[3]
}

if nextSel == "" {
selSegs = []string{"", ""}
} else if nextSel[0] == '.' {
nextSel = nextSel[1:]
}
}
}

return thisSel, nextSel
}

// access accesses the object using the selector and performs the
// appropriate action.
func access(current interface{}, selector string, value interface{}, isSet bool) interface{} {
selSegs := strings.SplitN(selector, PathSeparator, 2)
thisSel := selSegs[0]
index := -1
thisSel, nextSel := getKey(selector)

index := -1
if strings.Contains(thisSel, "[") {
index, thisSel = getIndex(thisSel)
}
Expand All @@ -88,7 +127,7 @@ func access(current interface{}, selector string, value interface{}, isSet bool)
switch current.(type) {
case map[string]interface{}:
curMSI := current.(map[string]interface{})
if len(selSegs) <= 1 && isSet {
if nextSel == "" && isSet {
curMSI[thisSel] = value
return nil
}
Expand All @@ -112,8 +151,8 @@ func access(current interface{}, selector string, value interface{}, isSet bool)
}
}
}
if len(selSegs) > 1 {
current = access(current, selSegs[1], value, isSet)
if nextSel != "" {
current = access(current, nextSel, value, isSet)
}
return current
}
19 changes: 19 additions & 0 deletions accessors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,25 @@ func TestAccessorsAccessGetDeepDeep(t *testing.T) {
}

assert.Equal(t, 4, m.Get("one.two.three.four").Data())
assert.Equal(t, 4, m.Get("one[two][three][four]").Data())
}

func TestAccessorsGetWithComplexKey(t *testing.T) {
m := objx.Map{
"domains": objx.Map{
"example-dot-com": objx.Map{
"apex": "example",
},
"example.com": objx.Map{
"apex": "example",
},
},
}

assert.Equal(t, "example", m.Get("domains.example-dot-com.apex").Data())

assert.Equal(t, "example", m.Get("domains[example.com].apex").Data())
assert.Equal(t, "example", m.Get("domains[example.com][apex]").Data())
}

func TestAccessorsAccessGetInsideArray(t *testing.T) {
Expand Down