9
9
namespace Microsoft . AspNetCore . JsonPatch . Adapters
10
10
{
11
11
/// <inheritdoc />
12
- public class ObjectAdapter : IObjectAdapter
12
+ public class ObjectAdapter : IObjectAdapterWithTest
13
13
{
14
14
/// <summary>
15
15
/// Initializes a new instance of <see cref="ObjectAdapter"/>.
@@ -34,66 +34,6 @@ public ObjectAdapter(
34
34
/// </summary>
35
35
public Action < JsonPatchError > LogErrorAction { get ; }
36
36
37
- /// <summary>
38
- /// The "add" operation performs one of the following functions,
39
- /// depending upon what the target location references:
40
- ///
41
- /// o If the target location specifies an array index, a new value is
42
- /// inserted into the array at the specified index.
43
- ///
44
- /// o If the target location specifies an object member that does not
45
- /// already exist, a new member is added to the object.
46
- ///
47
- /// o If the target location specifies an object member that does exist,
48
- /// that member's value is replaced.
49
- ///
50
- /// The operation object MUST contain a "value" member whose content
51
- /// specifies the value to be added.
52
- ///
53
- /// For example:
54
- ///
55
- /// { "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] }
56
- ///
57
- /// When the operation is applied, the target location MUST reference one
58
- /// of:
59
- ///
60
- /// o The root of the target document - whereupon the specified value
61
- /// becomes the entire content of the target document.
62
- ///
63
- /// o A member to add to an existing object - whereupon the supplied
64
- /// value is added to that object at the indicated location. If the
65
- /// member already exists, it is replaced by the specified value.
66
- ///
67
- /// o An element to add to an existing array - whereupon the supplied
68
- /// value is added to the array at the indicated location. Any
69
- /// elements at or above the specified index are shifted one position
70
- /// to the right. The specified index MUST NOT be greater than the
71
- /// number of elements in the array. If the "-" character is used to
72
- /// index the end of the array (see [RFC6901]), this has the effect of
73
- /// appending the value to the array.
74
- ///
75
- /// Because this operation is designed to add to existing objects and
76
- /// arrays, its target location will often not exist. Although the
77
- /// pointer's error handling algorithm will thus be invoked, this
78
- /// specification defines the error handling behavior for "add" pointers
79
- /// to ignore that error and add the value as specified.
80
- ///
81
- /// However, the object itself or an array containing it does need to
82
- /// exist, and it remains an error for that not to be the case. For
83
- /// example, an "add" with a target location of "/a/b" starting with this
84
- /// document:
85
- ///
86
- /// { "a": { "foo": 1 } }
87
- ///
88
- /// is not an error, because "a" exists, and "b" will be added to its
89
- /// value. It is an error in this document:
90
- ///
91
- /// { "q": { "bar": 2 } }
92
- ///
93
- /// because "a" does not exist.
94
- /// </summary>
95
- /// <param name="operation">The add operation.</param>
96
- /// <param name="objectToApplyTo">Object to apply the operation to.</param>
97
37
public void Add ( Operation operation , object objectToApplyTo )
98
38
{
99
39
if ( operation == null )
@@ -153,29 +93,6 @@ private void Add(
153
93
}
154
94
}
155
95
156
- /// <summary>
157
- /// The "move" operation removes the value at a specified location and
158
- /// adds it to the target location.
159
- ///
160
- /// The operation object MUST contain a "from" member, which is a string
161
- /// containing a JSON Pointer value that references the location in the
162
- /// target document to move the value from.
163
- ///
164
- /// The "from" location MUST exist for the operation to be successful.
165
- ///
166
- /// For example:
167
- ///
168
- /// { "op": "move", "from": "/a/b/c", "path": "/a/b/d" }
169
- ///
170
- /// This operation is functionally identical to a "remove" operation on
171
- /// the "from" location, followed immediately by an "add" operation at
172
- /// the target location with the value that was just removed.
173
- ///
174
- /// The "from" location MUST NOT be a proper prefix of the "path"
175
- /// location; i.e., a location cannot be moved into one of its children.
176
- /// </summary>
177
- /// <param name="operation">The move operation.</param>
178
- /// <param name="objectToApplyTo">Object to apply the operation to.</param>
179
96
public void Move ( Operation operation , object objectToApplyTo )
180
97
{
181
98
if ( operation == null )
@@ -202,20 +119,6 @@ public void Move(Operation operation, object objectToApplyTo)
202
119
}
203
120
}
204
121
205
- /// <summary>
206
- /// The "remove" operation removes the value at the target location.
207
- ///
208
- /// The target location MUST exist for the operation to be successful.
209
- ///
210
- /// For example:
211
- ///
212
- /// { "op": "remove", "path": "/a/b/c" }
213
- ///
214
- /// If removing an element from an array, any elements above the
215
- /// specified index are shifted one position to the left.
216
- /// </summary>
217
- /// <param name="operation">The remove operation.</param>
218
- /// <param name="objectToApplyTo">Object to apply the operation to.</param>
219
122
public void Remove ( Operation operation , object objectToApplyTo )
220
123
{
221
124
if ( operation == null )
@@ -259,26 +162,6 @@ private void Remove(string path, object objectToApplyTo, Operation operationToRe
259
162
}
260
163
}
261
164
262
- /// <summary>
263
- /// The "replace" operation replaces the value at the target location
264
- /// with a new value. The operation object MUST contain a "value" member
265
- /// whose content specifies the replacement value.
266
- ///
267
- /// The target location MUST exist for the operation to be successful.
268
- ///
269
- /// For example:
270
- ///
271
- /// { "op": "replace", "path": "/a/b/c", "value": 42 }
272
- ///
273
- /// This operation is functionally identical to a "remove" operation for
274
- /// a value, followed immediately by an "add" operation at the same
275
- /// location with the replacement value.
276
- ///
277
- /// Note: even though it's the same functionally, we do not call remove + add
278
- /// for performance reasons (multiple checks of same requirements).
279
- /// </summary>
280
- /// <param name="operation">The replace operation.</param>
281
- /// <param name="objectToApplyTo">Object to apply the operation to.</param>
282
165
public void Replace ( Operation operation , object objectToApplyTo )
283
166
{
284
167
if ( operation == null )
@@ -310,28 +193,6 @@ public void Replace(Operation operation, object objectToApplyTo)
310
193
}
311
194
}
312
195
313
- /// <summary>
314
- /// The "copy" operation copies the value at a specified location to the
315
- /// target location.
316
- ///
317
- /// The operation object MUST contain a "from" member, which is a string
318
- /// containing a JSON Pointer value that references the location in the
319
- /// target document to copy the value from.
320
- ///
321
- /// The "from" location MUST exist for the operation to be successful.
322
- ///
323
- /// For example:
324
- ///
325
- /// { "op": "copy", "from": "/a/b/c", "path": "/a/b/e" }
326
- ///
327
- /// This operation is functionally identical to an "add" operation at the
328
- /// target location using the value specified in the "from" member.
329
- ///
330
- /// Note: even though it's the same functionally, we do not call add with
331
- /// the value specified in from for performance reasons (multiple checks of same requirements).
332
- /// </summary>
333
- /// <param name="operation">The copy operation.</param>
334
- /// <param name="objectToApplyTo">Object to apply the operation to.</param>
335
196
public void Copy ( Operation operation , object objectToApplyTo )
336
197
{
337
198
if ( operation == null )
@@ -365,6 +226,37 @@ public void Copy(Operation operation, object objectToApplyTo)
365
226
}
366
227
}
367
228
229
+ public void Test ( Operation operation , object objectToApplyTo )
230
+ {
231
+ if ( operation == null )
232
+ {
233
+ throw new ArgumentNullException ( nameof ( operation ) ) ;
234
+ }
235
+
236
+ if ( objectToApplyTo == null )
237
+ {
238
+ throw new ArgumentNullException ( nameof ( objectToApplyTo ) ) ;
239
+ }
240
+
241
+ var parsedPath = new ParsedPath ( operation . path ) ;
242
+ var visitor = new ObjectVisitor ( parsedPath , ContractResolver ) ;
243
+
244
+ var target = objectToApplyTo ;
245
+ if ( ! visitor . TryVisit ( ref target , out var adapter , out var errorMessage ) )
246
+ {
247
+ var error = CreatePathNotFoundError ( objectToApplyTo , operation . path , operation , errorMessage ) ;
248
+ ErrorReporter ( error ) ;
249
+ return ;
250
+ }
251
+
252
+ if ( ! adapter . TryTest ( target , parsedPath . LastSegment , ContractResolver , operation . value , out errorMessage ) )
253
+ {
254
+ var error = CreateOperationFailedError ( objectToApplyTo , operation . path , operation , errorMessage ) ;
255
+ ErrorReporter ( error ) ;
256
+ return ;
257
+ }
258
+ }
259
+
368
260
private bool TryGetValue (
369
261
string fromLocation ,
370
262
object objectToGetValueFrom ,
0 commit comments