Removed Test operation code and changed T to TModel

This commit is contained in:
Kirthi Krishnamraju 2015-04-20 12:50:02 -07:00
parent bf712263fc
commit 3042a62ba9
9 changed files with 259 additions and 271 deletions

View File

@ -8,14 +8,13 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
/// <summary> /// <summary>
/// Defines the operations that can be performed on a JSON patch document. /// Defines the operations that can be performed on a JSON patch document.
/// </summary> /// </summary>
/// <typeparam name="T"></typeparam> /// <typeparam name="TModel">The type of the model.</typeparam>
public interface IObjectAdapter<T> where T : class public interface IObjectAdapter<TModel> where TModel : class
{ {
void Add(Operation<T> operation, T objectToApplyTo); void Add(Operation<TModel> operation, TModel objectToApplyTo);
void Copy(Operation<T> operation, T objectToApplyTo); void Copy(Operation<TModel> operation, TModel objectToApplyTo);
void Move(Operation<T> operation, T objectToApplyTo); void Move(Operation<TModel> operation, TModel objectToApplyTo);
void Remove(Operation<T> operation, T objectToApplyTo); void Remove(Operation<TModel> operation, TModel objectToApplyTo);
void Replace(Operation<T> operation, T objectToApplyTo); void Replace(Operation<TModel> operation, TModel objectToApplyTo);
void Test(Operation<T> operation, T objectToApplyTo);
} }
} }

View File

@ -15,14 +15,14 @@ using Newtonsoft.Json.Serialization;
namespace Microsoft.AspNet.JsonPatch.Adapters namespace Microsoft.AspNet.JsonPatch.Adapters
{ {
/// <inheritdoc /> /// <inheritdoc />
public class ObjectAdapter<T> : IObjectAdapter<T> where T : class public class ObjectAdapter<TModel> : IObjectAdapter<TModel> where TModel : class
{ {
/// <summary> /// <summary>
/// Initializes a new instance of <see cref="ObjectAdapter{T}"/>. /// Initializes a new instance of <see cref="ObjectAdapter{TModel}"/>.
/// </summary> /// </summary>
/// <param name="contractResolver">The <see cref="IContractResolver"/>.</param> /// <param name="contractResolver">The <see cref="IContractResolver"/>.</param>
/// <param name="logErrorAction">The <see cref="Action"/> for logging <see cref="JsonPatchError{T}"/>.</param> /// <param name="logErrorAction">The <see cref="Action"/> for logging <see cref="JsonPatchError{TModel}"/>.</param>
public ObjectAdapter(IContractResolver contractResolver, Action<JsonPatchError<T>> logErrorAction) public ObjectAdapter(IContractResolver contractResolver, Action<JsonPatchError<TModel>> logErrorAction)
{ {
ContractResolver = contractResolver; ContractResolver = contractResolver;
LogErrorAction = logErrorAction; LogErrorAction = logErrorAction;
@ -34,9 +34,9 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
public IContractResolver ContractResolver { get; } public IContractResolver ContractResolver { get; }
/// <summary> /// <summary>
/// Action for logging <see cref="JsonPatchError{T}"/>. /// Action for logging <see cref="JsonPatchError{TModel}"/>.
/// </summary> /// </summary>
public Action<JsonPatchError<T>> LogErrorAction { get; } public Action<JsonPatchError<TModel>> LogErrorAction { get; }
/// <summary> /// <summary>
/// The "add" operation performs one of the following functions, /// The "add" operation performs one of the following functions,
@ -96,9 +96,9 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
/// ///
/// because "a" does not exist. /// because "a" does not exist.
/// </summary> /// </summary>
/// <param name="operation">The add operation</param> /// <param name="operation">The add operation.</param>
/// <param name="objectApplyTo">Object to apply the operation to</param> /// <param name="objectApplyTo">Object to apply the operation to.</param>
public void Add(Operation<T> operation, T objectToApplyTo) public void Add(Operation<TModel> operation, TModel objectToApplyTo)
{ {
Add(operation.path, operation.value, objectToApplyTo, operation); Add(operation.path, operation.value, objectToApplyTo, operation);
} }
@ -107,7 +107,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
/// Add is used by various operations (eg: add, copy, ...), yet through different operations; /// Add is used by various operations (eg: add, copy, ...), yet through different operations;
/// This method allows code reuse yet reporting the correct operation on error /// This method allows code reuse yet reporting the correct operation on error
/// </summary> /// </summary>
private void Add(string path, object value, T objectToApplyTo, Operation<T> operationToReport) private void Add(string path, object value, TModel objectToApplyTo, Operation<TModel> operationToReport)
{ {
// add, in this implementation, does not just "add" properties - that's // add, in this implementation, does not just "add" properties - that's
// technically impossible; It can however be used to add items to arrays, // technically impossible; It can however be used to add items to arrays,
@ -178,7 +178,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
} }
else else
{ {
LogError(new JsonPatchError<T>( LogError(new JsonPatchError<TModel>(
objectToApplyTo, objectToApplyTo,
operationToReport, operationToReport,
Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path))); Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path)));
@ -189,7 +189,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
} }
else else
{ {
LogError(new JsonPatchError<T>( LogError(new JsonPatchError<TModel>(
objectToApplyTo, objectToApplyTo,
operationToReport, operationToReport,
Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path))); Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path)));
@ -236,9 +236,9 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
/// The "from" location MUST NOT be a proper prefix of the "path" /// The "from" location MUST NOT be a proper prefix of the "path"
/// location; i.e., a location cannot be moved into one of its children. /// location; i.e., a location cannot be moved into one of its children.
/// </summary> /// </summary>
/// <param name="operation">The move operation</param> /// <param name="operation">The move operation.</param>
/// <param name="objectApplyTo">Object to apply the operation to</param> /// <param name="objectApplyTo">Object to apply the operation to.</param>
public void Move(Operation<T> operation, T objectToApplyTo) public void Move(Operation<TModel> operation, TModel objectToApplyTo)
{ {
// get value at from location // get value at from location
object valueAtFromLocation = null; object valueAtFromLocation = null;
@ -275,7 +275,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
if (array.Count <= positionAsInteger) if (array.Count <= positionAsInteger)
{ {
LogError(new JsonPatchError<T>( LogError(new JsonPatchError<TModel>(
objectToApplyTo, objectToApplyTo,
operation, operation,
Resources.FormatInvalidIndexForArrayProperty(operation.op, operation.from))); Resources.FormatInvalidIndexForArrayProperty(operation.op, operation.from)));
@ -287,7 +287,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
} }
else else
{ {
LogError(new JsonPatchError<T>( LogError(new JsonPatchError<TModel>(
objectToApplyTo, objectToApplyTo,
operation, operation,
Resources.FormatInvalidPathForArrayProperty(operation.op, operation.from))); Resources.FormatInvalidPathForArrayProperty(operation.op, operation.from)));
@ -321,9 +321,9 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
/// If removing an element from an array, any elements above the /// If removing an element from an array, any elements above the
/// specified index are shifted one position to the left. /// specified index are shifted one position to the left.
/// </summary> /// </summary>
/// <param name="operation">The remove operation</param> /// <param name="operation">The remove operation.</param>
/// <param name="objectApplyTo">Object to apply the operation to</param> /// <param name="objectApplyTo">Object to apply the operation to.</param>
public void Remove(Operation<T> operation, T objectToApplyTo) public void Remove(Operation<TModel> operation, TModel objectToApplyTo)
{ {
Remove(operation.path, objectToApplyTo, operation); Remove(operation.path, objectToApplyTo, operation);
} }
@ -332,7 +332,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
/// Remove is used by various operations (eg: remove, move, ...), yet through different operations; /// Remove is used by various operations (eg: remove, move, ...), yet through different operations;
/// This method allows code reuse yet reporting the correct operation on error /// This method allows code reuse yet reporting the correct operation on error
/// </summary> /// </summary>
private void Remove(string path, T objectToApplyTo, Operation<T> operationToReport) private void Remove(string path, TModel objectToApplyTo, Operation<TModel> operationToReport)
{ {
var removeFromList = false; var removeFromList = false;
var positionAsInteger = -1; var positionAsInteger = -1;
@ -388,7 +388,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
} }
else else
{ {
LogError(new JsonPatchError<T>( LogError(new JsonPatchError<TModel>(
objectToApplyTo, objectToApplyTo,
operationToReport, operationToReport,
Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path))); Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path)));
@ -399,7 +399,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
} }
else else
{ {
LogError(new JsonPatchError<T>( LogError(new JsonPatchError<TModel>(
objectToApplyTo, objectToApplyTo,
operationToReport, operationToReport,
Resources.FormatInvalidPathForArrayProperty(operationToReport.op, path))); Resources.FormatInvalidPathForArrayProperty(operationToReport.op, path)));
@ -423,133 +423,6 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
} }
} }
/// <summary>
/// The "test" operation tests that a value at the target location is
/// equal to a specified value.
///
/// The operation object MUST contain a "value" member that conveys the
/// value to be compared to the target location's value.
///
/// The target location MUST be equal to the "value" value for the
/// operation to be considered successful.
///
/// Here, "equal" means that the value at the target location and the
/// value conveyed by "value" are of the same JSON type, and that they
/// are considered equal by the following rules for that type:
///
/// o strings: are considered equal if they contain the same number of
/// Unicode characters and their code points are byte-by-byte equal.
///
/// o numbers: are considered equal if their values are numerically
/// equal.
///
/// o arrays: are considered equal if they contain the same number of
/// values, and if each value can be considered equal to the value at
/// the corresponding position in the other array, using this list of
/// type-specific rules.
///
/// o objects: are considered equal if they contain the same number of
/// members, and if each member can be considered equal to a member in
/// the other object, by comparing their keys (as strings) and their
/// values (using this list of type-specific rules).
///
/// o literals (false, true, and null): are considered equal if they are
/// the same.
///
/// Note that the comparison that is done is a logical comparison; e.g.,
/// whitespace between the member values of an array is not significant.
///
/// Also, note that ordering of the serialization of object members is
/// not significant.
///
/// Note that we divert from the rules here - we use .NET's comparison,
/// not the one above. In a future version, a "strict" setting might
/// be added (configurable), that takes into account above rules.
///
/// For example:
///
/// { "op": "test", "path": "/a/b/c", "value": "foo" }
/// </summary>
/// <param name="operation">The test operation</param>
/// <param name="objectApplyTo">Object to apply the operation to</param>
public void Test(Operation<T> operation, T objectToApplyTo)
{
// get value at path location
object valueAtPathLocation = null;
var positionInPathAsInteger = -1;
var actualPathProperty = operation.path;
positionInPathAsInteger = GetNumericEnd(operation.path);
if (positionInPathAsInteger > -1)
{
actualPathProperty = operation.path.Substring(0,
operation.path.IndexOf('/' + positionInPathAsInteger.ToString()));
}
var patchProperty = FindPropertyAndParent(objectToApplyTo, actualPathProperty);
// does property at path exist?
if (!CheckIfPropertyExists(patchProperty, objectToApplyTo, operation, operation.path))
{
return;
}
// get the property path
Type typeOfFinalPropertyAtPathLocation = null;
// is the path an array (but not a string (= char[]))? In this case,
// the path must end with "/position" or "/-", which we already determined before.
if (positionInPathAsInteger > -1)
{
if (IsNonStringArray(patchProperty.Property.PropertyType))
{
// now, get the generic type of the IList<> from Property type.
typeOfFinalPropertyAtPathLocation = GetIListType(patchProperty.Property.PropertyType);
// get value (it can be cast, we just checked that)
var array = (IList)patchProperty.Property.ValueProvider.GetValue(patchProperty.Parent);
if (array.Count <= positionInPathAsInteger)
{
LogError(new JsonPatchError<T>(
objectToApplyTo,
operation,
Resources.FormatInvalidIndexForArrayProperty(operation.op, operation.path)));
return;
}
valueAtPathLocation = array[positionInPathAsInteger];
}
else
{
LogError(new JsonPatchError<T>(
objectToApplyTo,
operation,
Resources.FormatInvalidPathForArrayProperty(operation.op, operation.path)));
return;
}
}
else
{
// no list, just get the value
valueAtPathLocation = patchProperty.Property.ValueProvider.GetValue(patchProperty.Parent);
typeOfFinalPropertyAtPathLocation = patchProperty.Property.PropertyType;
}
var conversionResultTuple = ConvertToActualType(typeOfFinalPropertyAtPathLocation, operation.value);
// Is conversion successful
if (!CheckIfPropertyCanBeSet(conversionResultTuple, objectToApplyTo, operation, operation.path))
{
return;
}
//Compare
}
/// <summary> /// <summary>
/// The "replace" operation replaces the value at the target location /// The "replace" operation replaces the value at the target location
/// with a new value. The operation object MUST contain a "value" member /// with a new value. The operation object MUST contain a "value" member
@ -568,9 +441,9 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
/// Note: even though it's the same functionally, we do not call remove + add /// Note: even though it's the same functionally, we do not call remove + add
/// for performance reasons (multiple checks of same requirements). /// for performance reasons (multiple checks of same requirements).
/// </summary> /// </summary>
/// <param name="operation">The replace operation</param> /// <param name="operation">The replace operation.</param>
/// <param name="objectApplyTo">Object to apply the operation to</param> /// <param name="objectApplyTo">Object to apply the operation to.</param>
public void Replace(Operation<T> operation, T objectToApplyTo) public void Replace(Operation<TModel> operation, TModel objectToApplyTo)
{ {
Remove(operation.path, objectToApplyTo, operation); Remove(operation.path, objectToApplyTo, operation);
Add(operation.path, operation.value, objectToApplyTo, operation); Add(operation.path, operation.value, objectToApplyTo, operation);
@ -596,9 +469,9 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
/// Note: even though it's the same functionally, we do not call add with /// Note: even though it's the same functionally, we do not call add with
/// the value specified in from for performance reasons (multiple checks of same requirements). /// the value specified in from for performance reasons (multiple checks of same requirements).
/// </summary> /// </summary>
/// <param name="operation">The copy operation</param> /// <param name="operation">The copy operation.</param>
/// <param name="objectApplyTo">Object to apply the operation to</param> /// <param name="objectApplyTo">Object to apply the operation to.</param>
public void Copy(Operation<T> operation, T objectToApplyTo) public void Copy(Operation<TModel> operation, TModel objectToApplyTo)
{ {
// get value at from location // get value at from location
object valueAtFromLocation = null; object valueAtFromLocation = null;
@ -636,7 +509,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
if (array.Count <= positionAsInteger) if (array.Count <= positionAsInteger)
{ {
LogError(new JsonPatchError<T>( LogError(new JsonPatchError<TModel>(
objectToApplyTo, objectToApplyTo,
operation, operation,
Resources.FormatInvalidIndexForArrayProperty(operation.op, operation.from))); Resources.FormatInvalidIndexForArrayProperty(operation.op, operation.from)));
@ -648,7 +521,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
} }
else else
{ {
LogError(new JsonPatchError<T>( LogError(new JsonPatchError<TModel>(
objectToApplyTo, objectToApplyTo,
operation, operation,
Resources.FormatInvalidPathForArrayProperty(operation.op, operation.from))); Resources.FormatInvalidPathForArrayProperty(operation.op, operation.from)));
@ -669,13 +542,13 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
private bool CheckIfPropertyExists( private bool CheckIfPropertyExists(
JsonPatchProperty patchProperty, JsonPatchProperty patchProperty,
T objectToApplyTo, TModel objectToApplyTo,
Operation<T> operation, Operation<TModel> operation,
string propertyPath) string propertyPath)
{ {
if (patchProperty == null) if (patchProperty == null)
{ {
LogError(new JsonPatchError<T>( LogError(new JsonPatchError<TModel>(
objectToApplyTo, objectToApplyTo,
operation, operation,
Resources.FormatPropertyDoesNotExist(propertyPath))); Resources.FormatPropertyDoesNotExist(propertyPath)));
@ -685,7 +558,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
if (patchProperty.Property.Ignored) if (patchProperty.Property.Ignored)
{ {
LogError(new JsonPatchError<T>( LogError(new JsonPatchError<TModel>(
objectToApplyTo, objectToApplyTo,
operation, operation,
Resources.FormatCannotUpdateProperty(propertyPath))); Resources.FormatCannotUpdateProperty(propertyPath)));
@ -708,13 +581,13 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
private bool CheckIfPropertyCanBeSet( private bool CheckIfPropertyCanBeSet(
ConversionResult result, ConversionResult result,
T objectToApplyTo, TModel objectToApplyTo,
Operation<T> operation, Operation<TModel> operation,
string path) string path)
{ {
if (!result.CanBeConverted) if (!result.CanBeConverted)
{ {
LogError(new JsonPatchError<T>( LogError(new JsonPatchError<TModel>(
objectToApplyTo, objectToApplyTo,
operation, operation,
Resources.FormatInvalidValueForProperty(result.ConvertedInstance, path))); Resources.FormatInvalidValueForProperty(result.ConvertedInstance, path)));
@ -725,7 +598,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
return true; return true;
} }
private void LogError(JsonPatchError<T> jsonPatchError) private void LogError(JsonPatchError<TModel> jsonPatchError)
{ {
if (LogErrorAction != null) if (LogErrorAction != null)
{ {
@ -733,7 +606,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
} }
else else
{ {
throw new JsonPatchException<T>(jsonPatchError); throw new JsonPatchException<TModel>(jsonPatchError);
} }
} }

View File

@ -6,10 +6,10 @@ using Microsoft.AspNet.JsonPatch.Operations;
namespace Microsoft.AspNet.JsonPatch.Exceptions namespace Microsoft.AspNet.JsonPatch.Exceptions
{ {
public class JsonPatchException<T> : JsonPatchException where T : class public class JsonPatchException<TModel> : JsonPatchException where TModel : class
{ {
public Operation<T> FailedOperation { get; private set; } public Operation<TModel> FailedOperation { get; private set; }
public new T AffectedObject { get; private set; } public new TModel AffectedObject { get; private set; }
private string _message = ""; private string _message = "";
public override string Message public override string Message
@ -26,14 +26,14 @@ namespace Microsoft.AspNet.JsonPatch.Exceptions
} }
public JsonPatchException(JsonPatchError<T> jsonPatchError) public JsonPatchException(JsonPatchError<TModel> jsonPatchError)
{ {
FailedOperation = jsonPatchError.Operation; FailedOperation = jsonPatchError.Operation;
_message = jsonPatchError.ErrorMessage; _message = jsonPatchError.ErrorMessage;
AffectedObject = jsonPatchError.AffectedObject; AffectedObject = jsonPatchError.AffectedObject;
} }
public JsonPatchException(JsonPatchError<T> jsonPatchError, Exception innerException) public JsonPatchException(JsonPatchError<TModel> jsonPatchError, Exception innerException)
: this(jsonPatchError) : this(jsonPatchError)
{ {
InnerException = innerException; InnerException = innerException;

View File

@ -9,7 +9,7 @@ namespace Microsoft.AspNet.JsonPatch.Helpers
{ {
internal static class ExpressionHelpers internal static class ExpressionHelpers
{ {
public static string GetPath<T, TProp>(Expression<Func<T, TProp>> expr) where T : class public static string GetPath<TModel, TProp>(Expression<Func<TModel, TProp>> expr) where TModel : class
{ {
return "/" + GetPath(expr.Body, true); return "/" + GetPath(expr.Body, true);
} }

View File

@ -18,21 +18,21 @@ namespace Microsoft.AspNet.JsonPatch
// including type data in the JsonPatchDocument serialized as JSON (to allow for correct deserialization) - that's // including type data in the JsonPatchDocument serialized as JSON (to allow for correct deserialization) - that's
// not according to RFC 6902, and would thus break cross-platform compatibility. // not according to RFC 6902, and would thus break cross-platform compatibility.
[JsonConverter(typeof(TypedJsonPatchDocumentConverter))] [JsonConverter(typeof(TypedJsonPatchDocumentConverter))]
public class JsonPatchDocument<T> : IJsonPatchDocument where T : class public class JsonPatchDocument<TModel> : IJsonPatchDocument where TModel : class
{ {
public List<Operation<T>> Operations { get; private set; } public List<Operation<TModel>> Operations { get; private set; }
[JsonIgnore] [JsonIgnore]
public IContractResolver ContractResolver { get; set; } public IContractResolver ContractResolver { get; set; }
public JsonPatchDocument() public JsonPatchDocument()
{ {
Operations = new List<Operation<T>>(); Operations = new List<Operation<TModel>>();
ContractResolver = new DefaultContractResolver(); ContractResolver = new DefaultContractResolver();
} }
// Create from list of operations // Create from list of operations
public JsonPatchDocument(List<Operation<T>> operations, IContractResolver contractResolver) public JsonPatchDocument(List<Operation<TModel>> operations, IContractResolver contractResolver)
{ {
Operations = operations; Operations = operations;
ContractResolver = contractResolver; ContractResolver = contractResolver;
@ -46,13 +46,14 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="path">path</param> /// <param name="path">path</param>
/// <param name="value">value</param> /// <param name="value">value</param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Add<TProp>(Expression<Func<T, TProp>> path, TProp value) public JsonPatchDocument<TModel> Add<TProp>(Expression<Func<TModel, TProp>> path, TProp value)
{ {
Operations.Add(new Operation<T>( Operations.Add(new Operation<TModel>(
"add", "add",
ExpressionHelpers.GetPath<T, TProp>(path).ToLower(), ExpressionHelpers.GetPath(path).ToLower(),
from: null, from: null,
value: value)); value: value));
return this; return this;
} }
@ -64,12 +65,18 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="value">value</param> /// <param name="value">value</param>
/// <param name="position">position</param> /// <param name="position">position</param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Add<TProp>(Expression<Func<T, IList<TProp>>> path, TProp value, int position) public JsonPatchDocument<TModel> Add<TProp>(
Expression<Func<TModel,
IList<TProp>>> path,
TProp value,
int position)
{ {
Operations.Add(new Operation<T>( Operations.Add(new Operation<TModel>(
"add", "add",
ExpressionHelpers.GetPath<T, IList<TProp>>(path).ToLower() + "/" + position, ExpressionHelpers.GetPath(path).ToLower() + "/" + position,
null, value)); from: null,
value: value));
return this; return this;
} }
@ -80,9 +87,14 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="path">path</param> /// <param name="path">path</param>
/// <param name="value">value</param> /// <param name="value">value</param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Add<TProp>(Expression<Func<T, IList<TProp>>> path, TProp value) public JsonPatchDocument<TModel> Add<TProp>(Expression<Func<TModel, IList<TProp>>> path, TProp value)
{ {
Operations.Add(new Operation<T>("add", ExpressionHelpers.GetPath<T, IList<TProp>>(path).ToLower() + "/-", null, value)); Operations.Add(new Operation<TModel>(
"add",
ExpressionHelpers.GetPath(path).ToLower() + "/-",
from: null,
value: value));
return this; return this;
} }
@ -93,9 +105,10 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="remove"></param> /// <param name="remove"></param>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Remove<TProp>(Expression<Func<T, TProp>> path) public JsonPatchDocument<TModel> Remove<TProp>(Expression<Func<TModel, TProp>> path)
{ {
Operations.Add(new Operation<T>("remove", ExpressionHelpers.GetPath<T, TProp>(path).ToLower(), null)); Operations.Add(new Operation<TModel>("remove", ExpressionHelpers.GetPath(path).ToLower(), from: null));
return this; return this;
} }
@ -106,9 +119,13 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="path">target location</param> /// <param name="path">target location</param>
/// <param name="position">position</param> /// <param name="position">position</param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Remove<TProp>(Expression<Func<T, IList<TProp>>> path, int position) public JsonPatchDocument<TModel> Remove<TProp>(Expression<Func<TModel, IList<TProp>>> path, int position)
{ {
Operations.Add(new Operation<T>("remove", ExpressionHelpers.GetPath<T, IList<TProp>>(path).ToLower() + "/" + position, null)); Operations.Add(new Operation<TModel>(
"remove",
ExpressionHelpers.GetPath(path).ToLower() + "/" + position,
from: null));
return this; return this;
} }
@ -118,9 +135,13 @@ namespace Microsoft.AspNet.JsonPatch
/// <typeparam name="TProp">value type</typeparam> /// <typeparam name="TProp">value type</typeparam>
/// <param name="path">target location</param> /// <param name="path">target location</param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Remove<TProp>(Expression<Func<T, IList<TProp>>> path) public JsonPatchDocument<TModel> Remove<TProp>(Expression<Func<TModel, IList<TProp>>> path)
{ {
Operations.Add(new Operation<T>("remove", ExpressionHelpers.GetPath<T, IList<TProp>>(path).ToLower() + "/-", null)); Operations.Add(new Operation<TModel>(
"remove",
ExpressionHelpers.GetPath(path).ToLower() + "/-",
from: null));
return this; return this;
} }
@ -131,9 +152,14 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="path"></param> /// <param name="path"></param>
/// <param name="value"></param> /// <param name="value"></param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Replace<TProp>(Expression<Func<T, TProp>> path, TProp value) public JsonPatchDocument<TModel> Replace<TProp>(Expression<Func<TModel, TProp>> path, TProp value)
{ {
Operations.Add(new Operation<T>("replace", ExpressionHelpers.GetPath<T, TProp>(path).ToLower(), null, value)); Operations.Add(new Operation<TModel>(
"replace",
ExpressionHelpers.GetPath(path).ToLower(),
from: null,
value: value));
return this; return this;
} }
@ -144,9 +170,16 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="path">target location</param> /// <param name="path">target location</param>
/// <param name="position">position</param> /// <param name="position">position</param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Replace<TProp>(Expression<Func<T, IList<TProp>>> path, TProp value, int position) public JsonPatchDocument<TModel> Replace<TProp>(
Expression<Func<TModel, IList<TProp>>> path,
TProp value, int position)
{ {
Operations.Add(new Operation<T>("replace", ExpressionHelpers.GetPath<T, IList<TProp>>(path).ToLower() + "/" + position, null, value)); Operations.Add(new Operation<TModel>(
"replace",
ExpressionHelpers.GetPath(path).ToLower() + "/" + position,
from: null,
value: value));
return this; return this;
} }
@ -156,9 +189,14 @@ namespace Microsoft.AspNet.JsonPatch
/// <typeparam name="TProp">value type</typeparam> /// <typeparam name="TProp">value type</typeparam>
/// <param name="path">target location</param> /// <param name="path">target location</param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Replace<TProp>(Expression<Func<T, IList<TProp>>> path, TProp value) public JsonPatchDocument<TModel> Replace<TProp>(Expression<Func<TModel, IList<TProp>>> path, TProp value)
{ {
Operations.Add(new Operation<T>("replace", ExpressionHelpers.GetPath<T, IList<TProp>>(path).ToLower() + "/-", null, value)); Operations.Add(new Operation<TModel>(
"replace",
ExpressionHelpers.GetPath(path).ToLower() + "/-",
from: null,
value: value));
return this; return this;
} }
@ -169,10 +207,15 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="from"></param> /// <param name="from"></param>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Move<TProp>(Expression<Func<T, TProp>> from, Expression<Func<T, TProp>> path) public JsonPatchDocument<TModel> Move<TProp>(
Expression<Func<TModel, TProp>> from,
Expression<Func<TModel, TProp>> path)
{ {
Operations.Add(new Operation<T>("move", ExpressionHelpers.GetPath<T, TProp>(path).ToLower() Operations.Add(new Operation<TModel>(
, ExpressionHelpers.GetPath<T, TProp>(from).ToLower())); "move",
ExpressionHelpers.GetPath(path).ToLower(),
ExpressionHelpers.GetPath(from).ToLower()));
return this; return this;
} }
@ -184,10 +227,16 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="positionFrom"></param> /// <param name="positionFrom"></param>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Move<TProp>(Expression<Func<T, IList<TProp>>> from, int positionFrom, Expression<Func<T, TProp>> path) public JsonPatchDocument<TModel> Move<TProp>(
Expression<Func<TModel, IList<TProp>>> from,
int positionFrom,
Expression<Func<TModel, TProp>> path)
{ {
Operations.Add(new Operation<T>("move", ExpressionHelpers.GetPath<T, TProp>(path).ToLower() Operations.Add(new Operation<TModel>(
, ExpressionHelpers.GetPath<T, IList<TProp>>(from).ToLower() + "/" + positionFrom)); "move",
ExpressionHelpers.GetPath(path).ToLower(),
ExpressionHelpers.GetPath(from).ToLower() + "/" + positionFrom));
return this; return this;
} }
@ -199,12 +248,16 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="positionFrom"></param> /// <param name="positionFrom"></param>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Move<TProp>(Expression<Func<T, TProp>> from, public JsonPatchDocument<TModel> Move<TProp>(
Expression<Func<T, IList<TProp>>> path, int positionTo) Expression<Func<TModel, TProp>> from,
Expression<Func<TModel, IList<TProp>>> path,
int positionTo)
{ {
Operations.Add(new Operation<T>("move", ExpressionHelpers.GetPath<T, IList<TProp>>(path).ToLower() Operations.Add(new Operation<TModel>(
+ "/" + positionTo "move",
, ExpressionHelpers.GetPath<T, TProp>(from).ToLower())); ExpressionHelpers.GetPath(path).ToLower() + "/" + positionTo,
ExpressionHelpers.GetPath(from).ToLower()));
return this; return this;
} }
@ -216,12 +269,17 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="positionFrom"></param> /// <param name="positionFrom"></param>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Move<TProp>(Expression<Func<T, IList<TProp>>> from, int positionFrom, public JsonPatchDocument<TModel> Move<TProp>(
Expression<Func<T, IList<TProp>>> path, int positionTo) Expression<Func<TModel, IList<TProp>>> from,
int positionFrom,
Expression<Func<TModel, IList<TProp>>> path,
int positionTo)
{ {
Operations.Add(new Operation<T>("move", ExpressionHelpers.GetPath<T, IList<TProp>>(path).ToLower() Operations.Add(new Operation<TModel>(
+ "/" + positionTo "move",
, ExpressionHelpers.GetPath<T, IList<TProp>>(from).ToLower() + "/" + positionFrom)); ExpressionHelpers.GetPath(path).ToLower() + "/" + positionTo,
ExpressionHelpers.GetPath(from).ToLower() + "/" + positionFrom));
return this; return this;
} }
@ -233,12 +291,16 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="positionFrom"></param> /// <param name="positionFrom"></param>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Move<TProp>(Expression<Func<T, IList<TProp>>> from, int positionFrom, public JsonPatchDocument<TModel> Move<TProp>(
Expression<Func<T, IList<TProp>>> path) Expression<Func<TModel, IList<TProp>>> from,
int positionFrom,
Expression<Func<TModel, IList<TProp>>> path)
{ {
Operations.Add(new Operation<T>("move", ExpressionHelpers.GetPath<T, IList<TProp>>(path).ToLower() Operations.Add(new Operation<TModel>(
+ "/-" "move",
, ExpressionHelpers.GetPath<T, IList<TProp>>(from).ToLower() + "/" + positionFrom)); ExpressionHelpers.GetPath(path).ToLower() + "/-",
ExpressionHelpers.GetPath(from).ToLower() + "/" + positionFrom));
return this; return this;
} }
@ -250,10 +312,15 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="positionFrom"></param> /// <param name="positionFrom"></param>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Move<TProp>(Expression<Func<T, TProp>> from, Expression<Func<T, IList<TProp>>> path) public JsonPatchDocument<TModel> Move<TProp>(
Expression<Func<TModel, TProp>> from,
Expression<Func<TModel, IList<TProp>>> path)
{ {
Operations.Add(new Operation<T>("move", ExpressionHelpers.GetPath<T, IList<TProp>>(path).ToLower() + "/-" Operations.Add(new Operation<TModel>(
, ExpressionHelpers.GetPath<T, TProp>(from).ToLower())); "move",
ExpressionHelpers.GetPath(path).ToLower() + "/-",
ExpressionHelpers.GetPath(from).ToLower()));
return this; return this;
} }
@ -264,10 +331,15 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="from"></param> /// <param name="from"></param>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Copy<TProp>(Expression<Func<T, TProp>> from, Expression<Func<T, TProp>> path) public JsonPatchDocument<TModel> Copy<TProp>(
Expression<Func<TModel, TProp>> from,
Expression<Func<TModel, TProp>> path)
{ {
Operations.Add(new Operation<T>("copy", ExpressionHelpers.GetPath<T, TProp>(path).ToLower() Operations.Add(new Operation<TModel>(
, ExpressionHelpers.GetPath<T, TProp>(from).ToLower())); "copy",
ExpressionHelpers.GetPath(path).ToLower()
, ExpressionHelpers.GetPath(from).ToLower()));
return this; return this;
} }
@ -279,10 +351,16 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="positionFrom"></param> /// <param name="positionFrom"></param>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Copy<TProp>(Expression<Func<T, IList<TProp>>> from, int positionFrom, Expression<Func<T, TProp>> path) public JsonPatchDocument<TModel> Copy<TProp>(
Expression<Func<TModel, IList<TProp>>> from,
int positionFrom,
Expression<Func<TModel, TProp>> path)
{ {
Operations.Add(new Operation<T>("copy", ExpressionHelpers.GetPath<T, TProp>(path).ToLower() Operations.Add(new Operation<TModel>(
, ExpressionHelpers.GetPath<T, IList<TProp>>(from).ToLower() + "/" + positionFrom)); "copy",
ExpressionHelpers.GetPath(path).ToLower(),
ExpressionHelpers.GetPath(from).ToLower() + "/" + positionFrom));
return this; return this;
} }
@ -294,12 +372,16 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="positionFrom"></param> /// <param name="positionFrom"></param>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Copy<TProp>(Expression<Func<T, TProp>> from, public JsonPatchDocument<TModel> Copy<TProp>(
Expression<Func<T, IList<TProp>>> path, int positionTo) Expression<Func<TModel, TProp>> from,
Expression<Func<TModel, IList<TProp>>> path,
int positionTo)
{ {
Operations.Add(new Operation<T>("copy", ExpressionHelpers.GetPath<T, IList<TProp>>(path).ToLower() Operations.Add(new Operation<TModel>(
+ "/" + positionTo "copy",
, ExpressionHelpers.GetPath<T, TProp>(from).ToLower())); ExpressionHelpers.GetPath(path).ToLower() + "/" + positionTo,
ExpressionHelpers.GetPath(from).ToLower()));
return this; return this;
} }
@ -311,12 +393,17 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="positionFrom"></param> /// <param name="positionFrom"></param>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Copy<TProp>(Expression<Func<T, IList<TProp>>> from, int positionFrom, public JsonPatchDocument<TModel> Copy<TProp>(
Expression<Func<T, IList<TProp>>> path, int positionTo) Expression<Func<TModel, IList<TProp>>> from,
int positionFrom,
Expression<Func<TModel, IList<TProp>>> path,
int positionTo)
{ {
Operations.Add(new Operation<T>("copy", ExpressionHelpers.GetPath<T, IList<TProp>>(path).ToLower() Operations.Add(new Operation<TModel>(
+ "/" + positionTo "copy",
, ExpressionHelpers.GetPath<T, IList<TProp>>(from).ToLower() + "/" + positionFrom)); ExpressionHelpers.GetPath(path).ToLower() + "/" + positionTo,
ExpressionHelpers.GetPath(from).ToLower() + "/" + positionFrom));
return this; return this;
} }
@ -328,12 +415,17 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="positionFrom"></param> /// <param name="positionFrom"></param>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Copy<TProp>(Expression<Func<T, IList<TProp>>> from, int positionFrom, public JsonPatchDocument<TModel> Copy<TProp>(
Expression<Func<T, IList<TProp>>> path) Expression<Func<TModel,
IList<TProp>>> from,
int positionFrom,
Expression<Func<TModel, IList<TProp>>> path)
{ {
Operations.Add(new Operation<T>("copy", ExpressionHelpers.GetPath<T, IList<TProp>>(path).ToLower() Operations.Add(new Operation<TModel>(
+ "/-" "copy",
, ExpressionHelpers.GetPath<T, IList<TProp>>(from).ToLower() + "/" + positionFrom)); ExpressionHelpers.GetPath(path).ToLower() + "/-",
ExpressionHelpers.GetPath(from).ToLower() + "/" + positionFrom));
return this; return this;
} }
@ -345,24 +437,29 @@ namespace Microsoft.AspNet.JsonPatch
/// <param name="positionFrom"></param> /// <param name="positionFrom"></param>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns></returns> /// <returns></returns>
public JsonPatchDocument<T> Copy<TProp>(Expression<Func<T, TProp>> from, Expression<Func<T, IList<TProp>>> path) public JsonPatchDocument<TModel> Copy<TProp>(
Expression<Func<TModel, TProp>> from,
Expression<Func<TModel, IList<TProp>>> path)
{ {
Operations.Add(new Operation<T>("copy", ExpressionHelpers.GetPath<T, IList<TProp>>(path).ToLower() + "/-" Operations.Add(new Operation<TModel>(
, ExpressionHelpers.GetPath<T, TProp>(from).ToLower())); "copy",
ExpressionHelpers.GetPath(path).ToLower() + "/-",
ExpressionHelpers.GetPath(from).ToLower()));
return this; return this;
} }
public void ApplyTo(T objectToApplyTo) public void ApplyTo(TModel objectToApplyTo)
{ {
ApplyTo(objectToApplyTo, new ObjectAdapter<T>(ContractResolver, logErrorAction: null)); ApplyTo(objectToApplyTo, new ObjectAdapter<TModel>(ContractResolver, logErrorAction: null));
} }
public void ApplyTo(T objectToApplyTo, Action<JsonPatchError<T>> logErrorAction) public void ApplyTo(TModel objectToApplyTo, Action<JsonPatchError<TModel>> logErrorAction)
{ {
ApplyTo(objectToApplyTo, new ObjectAdapter<T>(ContractResolver, logErrorAction)); ApplyTo(objectToApplyTo, new ObjectAdapter<TModel>(ContractResolver, logErrorAction));
} }
public void ApplyTo(T objectToApplyTo, IObjectAdapter<T> adapter) public void ApplyTo(TModel objectToApplyTo, IObjectAdapter<TModel> adapter)
{ {
// apply each operation in order // apply each operation in order
foreach (var op in Operations) foreach (var op in Operations)

View File

@ -9,17 +9,17 @@ namespace Microsoft.AspNet.JsonPatch
/// <summary> /// <summary>
/// Captures error message and the related entity and the operation that caused it. /// Captures error message and the related entity and the operation that caused it.
/// </summary> /// </summary>
public class JsonPatchError<T> where T : class public class JsonPatchError<TModel> where TModel : class
{ {
/// <summary> /// <summary>
/// Initializes a new instance of <see cref="JsonPatchError{T}"/>. /// Initializes a new instance of <see cref="JsonPatchError{TModel}"/>.
/// </summary> /// </summary>
/// <param name="affectedObject">The object that is affected by the error.</param> /// <param name="affectedObject">The object that is affected by the error.</param>
/// <param name="operation">The <see cref="Operation{T}"/> that caused the error.</param> /// <param name="operation">The <see cref="Operation{TModel}"/> that caused the error.</param>
/// <param name="errorMessage">The error message.</param> /// <param name="errorMessage">The error message.</param>
public JsonPatchError( public JsonPatchError(
[NotNull] T affectedObject, [NotNull] TModel affectedObject,
[NotNull] Operation<T> operation, [NotNull] Operation<TModel> operation,
[NotNull] string errorMessage) [NotNull] string errorMessage)
{ {
AffectedObject = affectedObject; AffectedObject = affectedObject;
@ -30,12 +30,12 @@ namespace Microsoft.AspNet.JsonPatch
/// <summary> /// <summary>
/// Gets the object that is affected by the error. /// Gets the object that is affected by the error.
/// </summary> /// </summary>
public T AffectedObject { get; } public TModel AffectedObject { get; }
/// <summary> /// <summary>
/// Gets the <see cref="Operation{T}"/> that caused the error. /// Gets the <see cref="Operation{TModel}"/> that caused the error.
/// </summary> /// </summary>
public Operation<T> Operation { get; } public Operation<TModel> Operation { get; }
/// <summary> /// <summary>
/// Gets the error message. /// Gets the error message.

View File

@ -1,11 +1,12 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.JsonPatch.Adapters; using Microsoft.AspNet.JsonPatch.Adapters;
namespace Microsoft.AspNet.JsonPatch.Operations namespace Microsoft.AspNet.JsonPatch.Operations
{ {
public class Operation<T> : Operation where T : class public class Operation<TModel> : Operation where TModel : class
{ {
public Operation() public Operation()
{ {
@ -24,7 +25,7 @@ namespace Microsoft.AspNet.JsonPatch.Operations
} }
public void Apply(T objectToApplyTo, IObjectAdapter<T> adapter) public void Apply(TModel objectToApplyTo, IObjectAdapter<TModel> adapter)
{ {
switch (OperationType) switch (OperationType)
{ {
@ -44,8 +45,7 @@ namespace Microsoft.AspNet.JsonPatch.Operations
adapter.Copy(this, objectToApplyTo); adapter.Copy(this, objectToApplyTo);
break; break;
case OperationType.Test: case OperationType.Test:
adapter.Test(this, objectToApplyTo); throw new NotSupportedException(Resources.TestOperationNotSupported);
break;
default: default:
break; break;
} }

View File

@ -106,6 +106,22 @@ namespace Microsoft.AspNet.JsonPatch
return string.Format(CultureInfo.CurrentCulture, GetString("PropertyDoesNotExist"), p0); return string.Format(CultureInfo.CurrentCulture, GetString("PropertyDoesNotExist"), p0);
} }
/// <summary>
/// The test operation is not supported.
/// </summary>
internal static string TestOperationNotSupported
{
get { return GetString("TestOperationNotSupported"); }
}
/// <summary>
/// The test operation is not supported.
/// </summary>
internal static string FormatTestOperationNotSupported()
{
return GetString("TestOperationNotSupported");
}
private static string GetString(string name, params string[] formatterNames) private static string GetString(string name, params string[] formatterNames)
{ {
var value = _resourceManager.GetString(name); var value = _resourceManager.GetString(name);

View File

@ -135,4 +135,7 @@
<data name="PropertyDoesNotExist" xml:space="preserve"> <data name="PropertyDoesNotExist" xml:space="preserve">
<value>Property does not exist at path '{0}'.</value> <value>Property does not exist at path '{0}'.</value>
</data> </data>
<data name="TestOperationNotSupported" xml:space="preserve">
<value>The test operation is not supported.</value>
</data>
</root> </root>