// 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)) }
// 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 }
// 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 }