1 | /* |
2 | * Copyright (c) Facebook, Inc. and its affiliates. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #pragma once |
18 | |
19 | #include <folly/Expected.h> |
20 | #include <folly/Optional.h> |
21 | #include <folly/dynamic.h> |
22 | #include <folly/json_pointer.h> |
23 | |
24 | namespace folly { |
25 | |
26 | /* |
27 | * json_patch |
28 | * |
29 | * As described in RFC 6902 "JSON Patch". |
30 | * |
31 | * Implements parsing. Application over data structures must be |
32 | * implemented separately. |
33 | */ |
34 | class json_patch { |
35 | public: |
36 | enum class parse_error_code : uint8_t { |
37 | undefined, |
38 | invalid_shape, |
39 | missing_op, |
40 | unknown_op, |
41 | malformed_op, |
42 | missing_path_attr, |
43 | malformed_path_attr, |
44 | missing_from_attr, |
45 | malformed_from_attr, |
46 | missing_value_attr, |
47 | overlapping_pointers, |
48 | }; |
49 | |
50 | /* |
51 | * If parsing JSON patch object fails we return err code along with |
52 | * pointer to part of JSON document that we could not parse |
53 | */ |
54 | struct parse_error { |
55 | // one of the above error codes |
56 | parse_error_code error_code{parse_error_code::undefined}; |
57 | // pointer to object that caused the error |
58 | dynamic const* obj{}; |
59 | }; |
60 | |
61 | enum class patch_operation_code : uint8_t { |
62 | invalid = 0, |
63 | test, |
64 | remove, |
65 | add, |
66 | replace, |
67 | move, |
68 | copy, |
69 | }; |
70 | |
71 | /* |
72 | * Single JSON patch operation. Argument may vary based on op type |
73 | */ |
74 | struct patch_operation { |
75 | patch_operation_code op_code{patch_operation_code::invalid}; |
76 | json_pointer path; |
77 | Optional<json_pointer> from; |
78 | Optional<dynamic> value; |
79 | friend bool operator==( |
80 | patch_operation const& lhs, |
81 | patch_operation const& rhs) { |
82 | return lhs.op_code == rhs.op_code && lhs.path == rhs.path && |
83 | lhs.from == rhs.from && lhs.value == rhs.value; |
84 | } |
85 | friend bool operator!=( |
86 | patch_operation const& lhs, |
87 | patch_operation const& rhs) { |
88 | return !(lhs == rhs); |
89 | } |
90 | }; |
91 | |
92 | json_patch() = default; |
93 | ~json_patch() = default; |
94 | |
95 | static folly::Expected<json_patch, parse_error> try_parse( |
96 | dynamic const& obj) noexcept; |
97 | |
98 | std::vector<patch_operation> const& ops() const; |
99 | |
100 | enum class patch_application_error_code : uint8_t { |
101 | other, |
102 | // "from" pointer did not resolve |
103 | from_not_found, |
104 | // "path" pointer did not resolve |
105 | path_not_found, |
106 | // "test" condition failed |
107 | test_failed, |
108 | }; |
109 | |
110 | struct patch_application_error { |
111 | patch_application_error_code error_code{}; |
112 | // index of the patch element (in array) that caused error |
113 | size_t index{}; |
114 | }; |
115 | |
116 | /* |
117 | * Mutate supplied object in accordance with patch operations. Leaves |
118 | * object in partially modified state if one of the operations fails. |
119 | */ |
120 | Expected<Unit, patch_application_error> apply(folly::dynamic& obj); |
121 | |
122 | private: |
123 | std::vector<patch_operation> ops_; |
124 | }; |
125 | |
126 | } // namespace folly |
127 | |