formidable/internal/jsonpointer/set.go

68 lines
1.3 KiB
Go

package jsonpointer
import (
"strconv"
"github.com/pkg/errors"
)
func set(doc interface{}, tokens []string, value interface{}) (interface{}, error) {
if len(tokens) == 0 {
return value, nil
}
currentToken := tokens[0]
switch typedDoc := doc.(type) {
case map[string]interface{}:
nestedDoc, exists := typedDoc[currentToken]
if !exists {
return nil, errors.Wrapf(ErrNotFound, "pointer '%s' not found on document", tokensToString(tokens))
}
nestedDoc, err := set(nestedDoc, tokens[1:], value)
if err != nil {
return nil, errors.WithStack(err)
}
typedDoc[currentToken] = nestedDoc
return typedDoc, nil
case []interface{}:
var (
index uint64
nestedDoc interface{}
err error
)
if currentToken == NonExistentMemberToken {
typedDoc = append(typedDoc, value)
index = uint64(len(typedDoc) - 1)
} else {
index, err = strconv.ParseUint(currentToken, 10, 64)
if err != nil {
return nil, errors.WithStack(err)
}
if len(typedDoc) <= int(index) {
return nil, errors.WithStack(ErrOutOfBounds)
}
nestedDoc = typedDoc[index]
}
nestedDoc, err = set(nestedDoc, tokens[1:], value)
if err != nil {
return nil, errors.WithStack(err)
}
typedDoc[index] = nestedDoc
return typedDoc, nil
default:
return nil, errors.Wrapf(ErrUnexpectedType, "unexpected type '%T'", typedDoc)
}
}