patch.go 10 KB

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