Exemplo n.º 1
0
// Copy deep-copies the value pointed to by p in from to the location pointed to by at.
func (p pointer) Copy(from interface{}, at pointer) (interface{}, error) {
	val, err := p.Get(from)
	if err != nil {
		return from, err
	}
	return at.Put(from, utils.Clone(val))
}
Exemplo n.º 2
0
// Apply applies rawPatch (which must be a []byte containing a valid
// JSON Patch) to base, yielding result.  If err is returned, the
// returned int is the index of the operation that failed.  If the
// error is that rawPatch is not a valid JSON Patch, loc will be 0,
//
// base must be the result of unmarshaling JSON to interface{}, and
// will not be modified.
func Apply(base interface{}, rawPatch []byte) (result interface{}, err error, loc int) {
	p, err := newPatch(rawPatch)
	if err != nil {
		return nil, err, 0
	}
	result = utils.Clone(base)
	for i, op := range p {
		result, err = op.Apply(result)
		if err != nil {
			return result, err, i
		}
	}
	return result, nil, 0
}
Exemplo n.º 3
0
// This generator does not create copy or move patch ops, and I don't
// care enough to optimize it to do so.  Ditto for slice handling.
// There is a lot of optimization that could be done here, but it can get complex real quick.
func basicGen(base, target interface{}, paranoid bool, ptr pointer) patch {
	res := make(patch, 0)
	if reflect.TypeOf(base) != reflect.TypeOf(target) {
		if paranoid {
			res = append(res, operation{"test", ptr, nil, utils.Clone(base)})
		}
		res = append(res, operation{"replace", ptr, nil, utils.Clone(target)})
		return res
	}
	switch baseVal := base.(type) {
	case map[string]interface{}:
		targetVal := target.(map[string]interface{})
		handled := make(map[string]struct{})
		// Handle removed and changed first.
		for k, oldVal := range baseVal {
			newPtr := ptr.Append(k)
			newVal, ok := targetVal[k]
			if !ok {
				// Generate a remove op
				if paranoid {
					res = append(res, operation{"test", newPtr, nil, utils.Clone(oldVal)})
				}
				res = append(res, operation{"remove", newPtr, nil, nil})
			} else {
				subPatch := basicGen(oldVal, newVal, paranoid, newPtr)
				res = append(res, subPatch...)
			}
			handled[k] = struct{}{}
		}
		// Now, handle additions
		for k, newVal := range targetVal {
			if _, ok := handled[k]; ok {
				continue
			}
			res = append(res, operation{"add", ptr.Append(k), nil, utils.Clone(newVal)})
		}
	// case []interface{}:
	// Eventually, add code to handle slices more
	// efficiently.  For now, through, be dumb.
	default:
		if !reflect.DeepEqual(base, target) {
			if paranoid {
				res = append(res, operation{"test", ptr, nil, utils.Clone(base)})
			}
			res = append(res, operation{"replace", ptr, nil, utils.Clone(target)})
		}
	}
	return res
}