patch.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. package jsonpatch
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "strconv"
  7. "strings"
  8. )
  9. const (
  10. eRaw = iota
  11. eDoc
  12. eAry
  13. )
  14. var SupportNegativeIndices bool = true
  15. type lazyNode struct {
  16. raw *json.RawMessage
  17. doc partialDoc
  18. ary partialArray
  19. which int
  20. }
  21. type operation map[string]*json.RawMessage
  22. // Patch is an ordered collection of operations.
  23. type Patch []operation
  24. type partialDoc map[string]*lazyNode
  25. type partialArray []*lazyNode
  26. type container interface {
  27. get(key string) (*lazyNode, error)
  28. set(key string, val *lazyNode) error
  29. add(key string, val *lazyNode) error
  30. remove(key string) error
  31. }
  32. func newLazyNode(raw *json.RawMessage) *lazyNode {
  33. return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw}
  34. }
  35. func (n *lazyNode) MarshalJSON() ([]byte, error) {
  36. switch n.which {
  37. case eRaw:
  38. return json.Marshal(n.raw)
  39. case eDoc:
  40. return json.Marshal(n.doc)
  41. case eAry:
  42. return json.Marshal(n.ary)
  43. default:
  44. return nil, fmt.Errorf("Unknown type")
  45. }
  46. }
  47. func (n *lazyNode) UnmarshalJSON(data []byte) error {
  48. dest := make(json.RawMessage, len(data))
  49. copy(dest, data)
  50. n.raw = &dest
  51. n.which = eRaw
  52. return nil
  53. }
  54. func (n *lazyNode) intoDoc() (*partialDoc, error) {
  55. if n.which == eDoc {
  56. return &n.doc, nil
  57. }
  58. if n.raw == nil {
  59. return nil, fmt.Errorf("Unable to unmarshal nil pointer as partial document")
  60. }
  61. err := json.Unmarshal(*n.raw, &n.doc)
  62. if err != nil {
  63. return nil, err
  64. }
  65. n.which = eDoc
  66. return &n.doc, nil
  67. }
  68. func (n *lazyNode) intoAry() (*partialArray, error) {
  69. if n.which == eAry {
  70. return &n.ary, nil
  71. }
  72. if n.raw == nil {
  73. return nil, fmt.Errorf("Unable to unmarshal nil pointer as partial array")
  74. }
  75. err := json.Unmarshal(*n.raw, &n.ary)
  76. if err != nil {
  77. return nil, err
  78. }
  79. n.which = eAry
  80. return &n.ary, nil
  81. }
  82. func (n *lazyNode) compact() []byte {
  83. buf := &bytes.Buffer{}
  84. if n.raw == nil {
  85. return nil
  86. }
  87. err := json.Compact(buf, *n.raw)
  88. if err != nil {
  89. return *n.raw
  90. }
  91. return buf.Bytes()
  92. }
  93. func (n *lazyNode) tryDoc() bool {
  94. if n.raw == nil {
  95. return false
  96. }
  97. err := json.Unmarshal(*n.raw, &n.doc)
  98. if err != nil {
  99. return false
  100. }
  101. n.which = eDoc
  102. return true
  103. }
  104. func (n *lazyNode) tryAry() bool {
  105. if n.raw == nil {
  106. return false
  107. }
  108. err := json.Unmarshal(*n.raw, &n.ary)
  109. if err != nil {
  110. return false
  111. }
  112. n.which = eAry
  113. return true
  114. }
  115. func (n *lazyNode) equal(o *lazyNode) bool {
  116. if n.which == eRaw {
  117. if !n.tryDoc() && !n.tryAry() {
  118. if o.which != eRaw {
  119. return false
  120. }
  121. return bytes.Equal(n.compact(), o.compact())
  122. }
  123. }
  124. if n.which == eDoc {
  125. if o.which == eRaw {
  126. if !o.tryDoc() {
  127. return false
  128. }
  129. }
  130. if o.which != eDoc {
  131. return false
  132. }
  133. for k, v := range n.doc {
  134. ov, ok := o.doc[k]
  135. if !ok {
  136. return false
  137. }
  138. if v == nil && ov == nil {
  139. continue
  140. }
  141. if !v.equal(ov) {
  142. return false
  143. }
  144. }
  145. return true
  146. }
  147. if o.which != eAry && !o.tryAry() {
  148. return false
  149. }
  150. if len(n.ary) != len(o.ary) {
  151. return false
  152. }
  153. for idx, val := range n.ary {
  154. if !val.equal(o.ary[idx]) {
  155. return false
  156. }
  157. }
  158. return true
  159. }
  160. func (o operation) kind() string {
  161. if obj, ok := o["op"]; ok && obj != nil {
  162. var op string
  163. err := json.Unmarshal(*obj, &op)
  164. if err != nil {
  165. return "unknown"
  166. }
  167. return op
  168. }
  169. return "unknown"
  170. }
  171. func (o operation) path() string {
  172. if obj, ok := o["path"]; ok && obj != nil {
  173. var op string
  174. err := json.Unmarshal(*obj, &op)
  175. if err != nil {
  176. return "unknown"
  177. }
  178. return op
  179. }
  180. return "unknown"
  181. }
  182. func (o operation) from() string {
  183. if obj, ok := o["from"]; ok && obj != nil {
  184. var op string
  185. err := json.Unmarshal(*obj, &op)
  186. if err != nil {
  187. return "unknown"
  188. }
  189. return op
  190. }
  191. return "unknown"
  192. }
  193. func (o operation) value() *lazyNode {
  194. if obj, ok := o["value"]; ok {
  195. return newLazyNode(obj)
  196. }
  197. return nil
  198. }
  199. func isArray(buf []byte) bool {
  200. Loop:
  201. for _, c := range buf {
  202. switch c {
  203. case ' ':
  204. case '\n':
  205. case '\t':
  206. continue
  207. case '[':
  208. return true
  209. default:
  210. break Loop
  211. }
  212. }
  213. return false
  214. }
  215. func findObject(pd *container, path string) (container, string) {
  216. doc := *pd
  217. split := strings.Split(path, "/")
  218. if len(split) < 2 {
  219. return nil, ""
  220. }
  221. parts := split[1 : len(split)-1]
  222. key := split[len(split)-1]
  223. var err error
  224. for _, part := range parts {
  225. next, ok := doc.get(decodePatchKey(part))
  226. if next == nil || ok != nil {
  227. return nil, ""
  228. }
  229. if isArray(*next.raw) {
  230. doc, err = next.intoAry()
  231. if err != nil {
  232. return nil, ""
  233. }
  234. } else {
  235. doc, err = next.intoDoc()
  236. if err != nil {
  237. return nil, ""
  238. }
  239. }
  240. }
  241. return doc, decodePatchKey(key)
  242. }
  243. func (d *partialDoc) set(key string, val *lazyNode) error {
  244. (*d)[key] = val
  245. return nil
  246. }
  247. func (d *partialDoc) add(key string, val *lazyNode) error {
  248. (*d)[key] = val
  249. return nil
  250. }
  251. func (d *partialDoc) get(key string) (*lazyNode, error) {
  252. return (*d)[key], nil
  253. }
  254. func (d *partialDoc) remove(key string) error {
  255. _, ok := (*d)[key]
  256. if !ok {
  257. return fmt.Errorf("Unable to remove nonexistent key: %s", key)
  258. }
  259. delete(*d, key)
  260. return nil
  261. }
  262. func (d *partialArray) set(key string, val *lazyNode) error {
  263. if key == "-" {
  264. *d = append(*d, val)
  265. return nil
  266. }
  267. idx, err := strconv.Atoi(key)
  268. if err != nil {
  269. return err
  270. }
  271. sz := len(*d)
  272. if idx+1 > sz {
  273. sz = idx + 1
  274. }
  275. ary := make([]*lazyNode, sz)
  276. cur := *d
  277. copy(ary, cur)
  278. if idx >= len(ary) {
  279. return fmt.Errorf("Unable to access invalid index: %d", idx)
  280. }
  281. ary[idx] = val
  282. *d = ary
  283. return nil
  284. }
  285. func (d *partialArray) add(key string, val *lazyNode) error {
  286. if key == "-" {
  287. *d = append(*d, val)
  288. return nil
  289. }
  290. idx, err := strconv.Atoi(key)
  291. if err != nil {
  292. return err
  293. }
  294. ary := make([]*lazyNode, len(*d)+1)
  295. cur := *d
  296. if idx >= len(ary) {
  297. return fmt.Errorf("Unable to access invalid index: %d", idx)
  298. }
  299. if SupportNegativeIndices {
  300. if idx < -len(ary) {
  301. return fmt.Errorf("Unable to access invalid index: %d", idx)
  302. }
  303. if idx < 0 {
  304. idx += len(ary)
  305. }
  306. }
  307. copy(ary[0:idx], cur[0:idx])
  308. ary[idx] = val
  309. copy(ary[idx+1:], cur[idx:])
  310. *d = ary
  311. return nil
  312. }
  313. func (d *partialArray) get(key string) (*lazyNode, error) {
  314. idx, err := strconv.Atoi(key)
  315. if err != nil {
  316. return nil, err
  317. }
  318. if idx >= len(*d) {
  319. return nil, fmt.Errorf("Unable to access invalid index: %d", idx)
  320. }
  321. return (*d)[idx], nil
  322. }
  323. func (d *partialArray) remove(key string) error {
  324. idx, err := strconv.Atoi(key)
  325. if err != nil {
  326. return err
  327. }
  328. cur := *d
  329. if idx >= len(cur) {
  330. return fmt.Errorf("Unable to access invalid index: %d", idx)
  331. }
  332. if SupportNegativeIndices {
  333. if idx < -len(cur) {
  334. return fmt.Errorf("Unable to access invalid index: %d", idx)
  335. }
  336. if idx < 0 {
  337. idx += len(cur)
  338. }
  339. }
  340. ary := make([]*lazyNode, len(cur)-1)
  341. copy(ary[0:idx], cur[0:idx])
  342. copy(ary[idx:], cur[idx+1:])
  343. *d = ary
  344. return nil
  345. }
  346. func (p Patch) add(doc *container, op operation) error {
  347. path := op.path()
  348. con, key := findObject(doc, path)
  349. if con == nil {
  350. return fmt.Errorf("jsonpatch add operation does not apply: doc is missing path: \"%s\"", path)
  351. }
  352. return con.add(key, op.value())
  353. }
  354. func (p Patch) remove(doc *container, op operation) error {
  355. path := op.path()
  356. con, key := findObject(doc, path)
  357. if con == nil {
  358. return fmt.Errorf("jsonpatch remove operation does not apply: doc is missing path: \"%s\"", path)
  359. }
  360. return con.remove(key)
  361. }
  362. func (p Patch) replace(doc *container, op operation) error {
  363. path := op.path()
  364. con, key := findObject(doc, path)
  365. if con == nil {
  366. return fmt.Errorf("jsonpatch replace operation does not apply: doc is missing path: %s", path)
  367. }
  368. _, ok := con.get(key)
  369. if ok != nil {
  370. return fmt.Errorf("jsonpatch replace operation does not apply: doc is missing key: %s", path)
  371. }
  372. return con.set(key, op.value())
  373. }
  374. func (p Patch) move(doc *container, op operation) error {
  375. from := op.from()
  376. con, key := findObject(doc, from)
  377. if con == nil {
  378. return fmt.Errorf("jsonpatch move operation does not apply: doc is missing from path: %s", from)
  379. }
  380. val, err := con.get(key)
  381. if err != nil {
  382. return err
  383. }
  384. err = con.remove(key)
  385. if err != nil {
  386. return err
  387. }
  388. path := op.path()
  389. con, key = findObject(doc, path)
  390. if con == nil {
  391. return fmt.Errorf("jsonpatch move operation does not apply: doc is missing destination path: %s", path)
  392. }
  393. return con.set(key, val)
  394. }
  395. func (p Patch) test(doc *container, op operation) error {
  396. path := op.path()
  397. con, key := findObject(doc, path)
  398. if con == nil {
  399. return fmt.Errorf("jsonpatch test operation does not apply: is missing path: %s", path)
  400. }
  401. val, err := con.get(key)
  402. if err != nil {
  403. return err
  404. }
  405. if val == nil {
  406. if op.value().raw == nil {
  407. return nil
  408. }
  409. return fmt.Errorf("Testing value %s failed", path)
  410. } else if op.value() == nil {
  411. return fmt.Errorf("Testing value %s failed", path)
  412. }
  413. if val.equal(op.value()) {
  414. return nil
  415. }
  416. return fmt.Errorf("Testing value %s failed", path)
  417. }
  418. func (p Patch) copy(doc *container, op operation) error {
  419. from := op.from()
  420. con, key := findObject(doc, from)
  421. if con == nil {
  422. return fmt.Errorf("jsonpatch copy operation does not apply: doc is missing from path: %s", from)
  423. }
  424. val, err := con.get(key)
  425. if err != nil {
  426. return err
  427. }
  428. path := op.path()
  429. con, key = findObject(doc, path)
  430. if con == nil {
  431. return fmt.Errorf("jsonpatch copy operation does not apply: doc is missing destination path: %s", path)
  432. }
  433. return con.set(key, val)
  434. }
  435. // Equal indicates if 2 JSON documents have the same structural equality.
  436. func Equal(a, b []byte) bool {
  437. ra := make(json.RawMessage, len(a))
  438. copy(ra, a)
  439. la := newLazyNode(&ra)
  440. rb := make(json.RawMessage, len(b))
  441. copy(rb, b)
  442. lb := newLazyNode(&rb)
  443. return la.equal(lb)
  444. }
  445. // DecodePatch decodes the passed JSON document as an RFC 6902 patch.
  446. func DecodePatch(buf []byte) (Patch, error) {
  447. var p Patch
  448. err := json.Unmarshal(buf, &p)
  449. if err != nil {
  450. return nil, err
  451. }
  452. return p, nil
  453. }
  454. // Apply mutates a JSON document according to the patch, and returns the new
  455. // document.
  456. func (p Patch) Apply(doc []byte) ([]byte, error) {
  457. return p.ApplyIndent(doc, "")
  458. }
  459. // ApplyIndent mutates a JSON document according to the patch, and returns the new
  460. // document indented.
  461. func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) {
  462. var pd container
  463. if doc[0] == '[' {
  464. pd = &partialArray{}
  465. } else {
  466. pd = &partialDoc{}
  467. }
  468. err := json.Unmarshal(doc, pd)
  469. if err != nil {
  470. return nil, err
  471. }
  472. err = nil
  473. for _, op := range p {
  474. switch op.kind() {
  475. case "add":
  476. err = p.add(&pd, op)
  477. case "remove":
  478. err = p.remove(&pd, op)
  479. case "replace":
  480. err = p.replace(&pd, op)
  481. case "move":
  482. err = p.move(&pd, op)
  483. case "test":
  484. err = p.test(&pd, op)
  485. case "copy":
  486. err = p.copy(&pd, op)
  487. default:
  488. err = fmt.Errorf("Unexpected kind: %s", op.kind())
  489. }
  490. if err != nil {
  491. return nil, err
  492. }
  493. }
  494. if indent != "" {
  495. return json.MarshalIndent(pd, "", indent)
  496. }
  497. return json.Marshal(pd)
  498. }
  499. // From http://tools.ietf.org/html/rfc6901#section-4 :
  500. //
  501. // Evaluation of each reference token begins by decoding any escaped
  502. // character sequence. This is performed by first transforming any
  503. // occurrence of the sequence '~1' to '/', and then transforming any
  504. // occurrence of the sequence '~0' to '~'.
  505. var (
  506. rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~")
  507. )
  508. func decodePatchKey(k string) string {
  509. return rfc6901Decoder.Replace(k)
  510. }