Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Microsoft.Azure.Cosmos/src/Patch/PatchConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static class PropertyNames
public const string OperationType = "op";
public const string Path = "path";
public const string Value = "value";
public const string From = "from";
}

public static class PatchSpecAttributes
Expand All @@ -28,6 +29,7 @@ public static class OperationTypeNames
public const string Replace = "replace";
public const string Set = "set";
public const string Increment = "incr";
public const string Move = "move";
}

public static string ToEnumMemberString(this PatchOperationType patchOperationType)
Expand All @@ -44,6 +46,8 @@ public static string ToEnumMemberString(this PatchOperationType patchOperationTy
return PatchConstants.OperationTypeNames.Set;
case PatchOperationType.Increment:
return PatchConstants.OperationTypeNames.Increment;
case PatchOperationType.Move:
return PatchConstants.OperationTypeNames.Move;
default:
throw new ArgumentException($"Unknown Patch operation type '{patchOperationType}'.");
}
Expand Down
22 changes: 22 additions & 0 deletions Microsoft.Azure.Cosmos/src/Patch/PatchOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ public abstract class PatchOperation
[JsonProperty(PropertyName = PatchConstants.PropertyNames.Path)]
public abstract string Path { get; }

/// <summary>
/// Source location reference (used in case of move)
/// </summary>
[JsonProperty(PropertyName = PatchConstants.PropertyNames.From)]
public virtual string From { get; set; } = null;

/// <summary>
/// Serializes the value parameter, if specified for the PatchOperation.
/// </summary>
Expand Down Expand Up @@ -134,5 +140,21 @@ public static PatchOperation Increment(
path,
value);
}

/// <summary>
/// Create <see cref="PatchOperation"/> to move an object/value.
/// </summary>
/// <param name="from">The source location of the object/value.</param>
/// <param name="path">Target location reference.</param>
/// <returns>PatchOperation instance for specified input.</returns>
public static PatchOperation Move(
string from,
string path)
{
return new PatchOperationCore<string>(
PatchOperationType.Move,
path,
from);
}
}
}
43 changes: 30 additions & 13 deletions Microsoft.Azure.Cosmos/src/Patch/PatchOperationCore{T}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,40 @@ namespace Microsoft.Azure.Cosmos
internal sealed class PatchOperationCore<T> : PatchOperation<T>
{
/// <summary>
/// Initializes a new instance of the <see cref="PatchOperationCore{T}"/> class.
/// </summary>
/// <param name="operationType">Specifies the type of Patch operation.</param>
/// <param name="path">Specifies the path to target location.</param>
/// <param name="value">Specifies the value to be used.</param>
        /// Initializes a new instance of the <see cref="PatchOperationCore{T}"/> class.
        /// </summary>
        /// <param name="operationType">Specifies the type of Patch operation.</param>
        /// <param name="path">Specifies the path to target location.</param>
        /// <param name="value">Specifies the value to be used. In case of move operations it will be a string specifying the source
        /// location.</param>
public PatchOperationCore(
PatchOperationType operationType,
string path,
T value)
PatchOperationType operationType,
string path,
T value)
{
this.OperationType = operationType;
this.Path = string.IsNullOrWhiteSpace(path)
? throw new ArgumentNullException(nameof(path))
: path;
this.Value = value;
if (operationType == PatchOperationType.Move)
{
this.Path = string.IsNullOrWhiteSpace(path)
? throw new ArgumentNullException(nameof(path))
: path;
if (!(value is String valueAsString))
{
throw new ArgumentException(
$"Parameter {nameof(value)} must be of type String for patch operation type {nameof(PatchOperationType.Move)}");
}
this.From = string.IsNullOrWhiteSpace(valueAsString)
? throw new ArgumentNullException(nameof(value))
: valueAsString;
}
else
{
this.Path = string.IsNullOrWhiteSpace(path)
? throw new ArgumentNullException(nameof(path))
: path;
this.Value = value;
}
}

public override T Value { get; }

public override PatchOperationType OperationType { get; }
Expand Down
8 changes: 7 additions & 1 deletion Microsoft.Azure.Cosmos/src/Patch/PatchOperationType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Microsoft.Azure.Cosmos
using Newtonsoft.Json.Converters;

/// <summary>
/// Type of Patch operation.
/// Describes the list of Patch supported operation types.
/// </summary>
/// <remarks>
/// For more information, see <see href="https://docs.microsoft.com/azure/cosmos-db/partial-document-update#supported-operations">Partial document update in Azure Cosmos DB: Supported operations</see>
Expand Down Expand Up @@ -47,5 +47,11 @@ public enum PatchOperationType
/// </summary>
[EnumMember(Value = PatchConstants.OperationTypeNames.Increment)]
Increment,

/// <summary>
/// Operation to move a object/value.
/// </summary>
[EnumMember(Value = PatchConstants.OperationTypeNames.Move)]
Move,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,12 @@ public override void WriteJson(
writer.WritePropertyName(PatchConstants.PropertyNames.Path);
writer.WriteValue(operation.Path);

if (operation.TrySerializeValueParameter(this.userSerializer, out Stream valueStream))
if (operation.OperationType == PatchOperationType.Move)
{
writer.WritePropertyName(PatchConstants.PropertyNames.From);
writer.WriteValue(operation.From);
}
else if (operation.TrySerializeValueParameter(this.userSerializer, out Stream valueStream))
{
string valueParam;
using (valueStream)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,8 @@ public async Task BatchCustomSerializerUsedForPatchAsync()
DateTime patchDate = new DateTime(2020, 07, 01, 01, 02, 03);
List<PatchOperation> patchOperations = new List<PatchOperation>()
{
PatchOperation.Add("/date", patchDate)
PatchOperation.Add("/date", patchDate),
PatchOperation.Move("/date", "/TodayDate")
};

BatchCore batch = (BatchCore)new BatchCore((ContainerInlineCore)customSerializationContainer, BatchTestBase.GetPartitionKey(this.PartitionKey1))
Expand All @@ -719,7 +720,8 @@ public async Task BatchCustomSerializerUsedForPatchAsync()

Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.IsNotNull(response.Resource);
Assert.IsTrue(dateJson.Contains(response.Resource["date"].ToString()));
Assert.IsNull(response.Resource["date"]);
Assert.IsTrue(dateJson.Contains(response.Resource["TodayDate"].ToString()));
}

private async Task<TransactionalBatchResponse> RunCrudAsync(bool isStream, bool isSchematized, bool useEpk, Container container)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1984,7 +1984,6 @@ public async Task ItemPatchSuccessTest()

patchOperations.Clear();
patchOperations.Add(PatchOperation.Add("/children/0/cost", 1));
//patchOperations.Add(PatchOperation.Set("/random", value));
// with content response
response = await containerInternal.PatchItemAsync<ToDoActivity>(
id: testItem.id,
Expand All @@ -2006,6 +2005,22 @@ public async Task ItemPatchSuccessTest()
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.IsNotNull(response.Resource);
Assert.AreEqual(null, response.Resource.children[0].id);

patchOperations.Clear();
patchOperations.Add(PatchOperation.Add("/children/1/description","Child#1"));
patchOperations.Add(PatchOperation.Move("/children/0/description", "/description"));
patchOperations.Add(PatchOperation.Move("/children/1/description", "/children/0/description"));
// with content response
response = await containerInternal.PatchItemAsync<ToDoActivity>(
id: testItem.id,
partitionKey: new Cosmos.PartitionKey(testItem.pk),
patchOperations: patchOperations);

Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.IsNotNull(response.Resource);
Assert.AreEqual("testSet", response.Resource.description);
Assert.AreEqual("Child#1", response.Resource.children[0].description);
Assert.IsNull(response.Resource.children[1].description);
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5682,6 +5682,11 @@
"Attributes": [],
"MethodInfo": "Microsoft.Azure.Cosmos.PatchOperation Increment(System.String, Int64);IsAbstract:False;IsStatic:True;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
},
"Microsoft.Azure.Cosmos.PatchOperation Move(System.String, System.String)": {
"Type": "Method",
"Attributes": [],
"MethodInfo": "Microsoft.Azure.Cosmos.PatchOperation Move(System.String, System.String);IsAbstract:False;IsStatic:True;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
},
"Microsoft.Azure.Cosmos.PatchOperation Remove(System.String)": {
"Type": "Method",
"Attributes": [],
Expand Down Expand Up @@ -5709,6 +5714,20 @@
],
"MethodInfo": "Microsoft.Azure.Cosmos.PatchOperationType OperationType;CanRead:True;CanWrite:False;Microsoft.Azure.Cosmos.PatchOperationType get_OperationType();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
},
"System.String From[Newtonsoft.Json.JsonPropertyAttribute(PropertyName = \"from\")]": {
"Type": "Property",
"Attributes": [
"JsonPropertyAttribute"
],
"MethodInfo": "System.String From;CanRead:True;CanWrite:True;System.String get_From();IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;Void set_From(System.String);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
},
"System.String get_From()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
"Type": "Method",
"Attributes": [
"CompilerGeneratedAttribute"
],
"MethodInfo": "System.String get_From();IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
},
"System.String get_Path()": {
"Type": "Method",
"Attributes": [],
Expand All @@ -5720,6 +5739,13 @@
"JsonPropertyAttribute"
],
"MethodInfo": "System.String Path;CanRead:True;CanWrite:False;System.String get_Path();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
},
"Void set_From(System.String)[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
"Type": "Method",
"Attributes": [
"CompilerGeneratedAttribute"
],
"MethodInfo": "Void set_From(System.String);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
}
},
"NestedTypes": {}
Expand Down Expand Up @@ -5764,6 +5790,13 @@
],
"MethodInfo": "Microsoft.Azure.Cosmos.PatchOperationType Increment;IsInitOnly:False;IsStatic:True;"
},
"Microsoft.Azure.Cosmos.PatchOperationType Move[System.Runtime.Serialization.EnumMemberAttribute(Value = \"move\")]": {
"Type": "Field",
"Attributes": [
"EnumMemberAttribute"
],
"MethodInfo": "Microsoft.Azure.Cosmos.PatchOperationType Move;IsInitOnly:False;IsStatic:True;"
},
"Microsoft.Azure.Cosmos.PatchOperationType Remove[System.Runtime.Serialization.EnumMemberAttribute(Value = \"remove\")]": {
"Type": "Field",
"Attributes": [
Expand Down