private void ModifyValue(PatchRequest patchCmd, string propName, JProperty property) { EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property == null) throw new InvalidOperationException("Cannot modify value from '" + propName + "' because it was not found"); var nestedCommands = patchCmd.Nested; if (nestedCommands == null) throw new InvalidOperationException("Cannot understand modified value from '" + propName + "' because could not find nested array of commands"); switch (property.Value.Type) { case JTokenType.Object: foreach (var cmd in nestedCommands) { var nestedDoc = property.Value.Value<JObject>(); new JsonPatcher(nestedDoc).Apply(cmd); } break; case JTokenType.Array: var position = patchCmd.Position; if (position == null) throw new InvalidOperationException("Cannot modify value from '" + propName + "' because position element does not exists or not an integer"); var value = property.Value.Value<JArray>()[position]; foreach (var cmd in nestedCommands) { new JsonPatcher(value.Value<JObject>()).Apply(cmd); } break; default: throw new InvalidOperationException("Can't understand how to deal with: " + property.Value.Type); } }
public void CanConvertToAndFromJsonWithNestedPatchRequests() { var patch = new PatchRequest { Name = "Comments", Type = PatchCommandType.Modify, Position = 0, Nested = new[] { new PatchRequest { Name = "AuthorId", Type = PatchCommandType.Set, Value = "authors/456" }, new PatchRequest { Name = "AuthorName", Type = PatchCommandType.Set, Value = "Tolkien" }, } }; var jsonPatch = patch.ToJson(); var backToPatch = PatchRequest.FromJson(jsonPatch); Assert.Equal(patch.Name, backToPatch.Name); Assert.Equal(patch.Nested.Length, backToPatch.Nested.Length); }
private void CopyProperty(PatchRequest patchCmd, string propName, JProperty property) { EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property == null) throw new InvalidOperationException("Cannot copy value from '" + propName + "' because it was not found"); document[patchCmd.Value.Value<string>()] = property.Value; }
public JObject Apply(PatchRequest[] patch) { foreach (var patchCmd in patch) { Apply(patchCmd); } return document; }
public JArray UpdateByIndex(string indexName, IndexQuery queryToUpdate, PatchRequest[] patchRequests, bool allowStale) { return PerformBulkOperation(indexName, queryToUpdate, allowStale, (docId, tx) => { var patchResult = database.ApplyPatch(docId, null, patchRequests, tx); return new { Document = docId, Result = patchResult }; }); }
private void RenameProperty(PatchRequest patchCmd, string propName, JProperty property) { EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property == null) return; document[patchCmd.Value.Value<string>()] = property.Value; document.Remove(propName); }
private void AddProperty(PatchRequest patchCmd, string propName, JProperty property) { EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property == null) { property = new JProperty(propName); document.Add(property); } property.Value = patchCmd.Value; }
private void AddValue(PatchRequest patchCmd, string propName, JProperty property) { EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property == null) { property = new JProperty(propName, new JArray()); document.Add(property); } var array = property.Value as JArray; if (array == null) throw new InvalidOperationException("Cannot insert value to '" + propName + "' because it is not an array"); array.Add(patchCmd.Value); }
private void AddValue(PatchRequest patchCmd, string propName, RavenJToken token) { EnsurePreviousValueMatchCurrentValue(patchCmd, token); if (token == null) { token = new RavenJArray(); document[propName] = token; } var array = GetArray(token, propName); array = new RavenJArray(array); document[propName] = array; array.Add(patchCmd.Value); }
public void CanConvertToAndFromJsonWithEmptyNestedPatchRequests() { var patch = new PatchRequest { Name = "Comments", Type = PatchCommandType.Modify, Position = 0, Nested = new PatchRequest[] { } }; var jsonPatch = patch.ToJson(); var backToPatch = PatchRequest.FromJson(jsonPatch); Assert.Equal(patch.Name, backToPatch.Name); Assert.Equal(patch.Nested.Length, backToPatch.Nested.Length); }
private void RemoveValue(PatchRequest patchCmd, string propName, RavenJToken token) { EnsurePreviousValueMatchCurrentValue(patchCmd, token); if (token == null) { token = new RavenJArray(); document[propName] = token; } var array = GetArray(token, propName); if (array.IsSnapshot) { array = new RavenJArray(array); document[propName] = array; } var position = patchCmd.Position; var value = patchCmd.Value; if (position == null && (value == null || value.Type == JTokenType.Null)) { throw new InvalidOperationException("Cannot remove value from '" + propName + "' because position element does not exists or not an integer and no value was present"); } if (position != null && value != null && value.Type != JTokenType.Null) { throw new InvalidOperationException("Cannot remove value from '" + propName + "' because both a position and a value are set"); } if (position != null && (position.Value < 0 || position.Value >= array.Length)) { throw new IndexOutOfRangeException("Cannot remove value from '" + propName + "' because position element is out of bound bounds"); } if (value != null && value.Type != JTokenType.Null) { foreach (var ravenJToken in array.Where(x => RavenJToken.DeepEquals(x, value)).ToList()) { array.Remove(ravenJToken); } return; } if (position != null) { array.RemoveAt(position.Value); } }
private void ModifyValue(PatchRequest patchCmd, string propName) { var property = document.Property(propName); EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property == null) { throw new InvalidOperationException("Cannot modify value from '" + propName + "' because it was not found"); } var nestedCommands = patchCmd.Nested; if (nestedCommands == null) { throw new InvalidOperationException("Cannot understand modified value from '" + propName + "' because could not find nested array of commands"); } switch (property.Value.Type) { case JTokenType.Object: foreach (var cmd in nestedCommands) { var nestedDoc = property.Value.Value <JObject>(); new JsonPatcher(nestedDoc).Apply(cmd); } break; case JTokenType.Array: var position = patchCmd.Position; if (position == null) { throw new InvalidOperationException("Cannot modify value from '" + propName + "' because position element does not exists or not an integer"); } var value = property.Value.Value <JArray>()[position]; foreach (var cmd in nestedCommands) { new JsonPatcher(value.Value <JObject>()).Apply(cmd); } break; default: throw new InvalidOperationException("Can't understand how to deal with: " + property.Value.Type); } }
private void AddValue(PatchRequest patchCmd, string propName, JProperty property) { EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property == null) { property = new JProperty(propName, new JArray()); document.Add(property); } var array = property.Value as JArray; if (array == null) { throw new InvalidOperationException("Cannot insert value to '" + propName + "' because it is not an array"); } array.Add(patchCmd.Value); }
private void RemoveValue(PatchRequest patchCmd, string propName, RavenJToken token) { EnsurePreviousValueMatchCurrentValue(patchCmd, token); if (token == null) { token = new RavenJArray(); document[propName] = token; } var array = GetArray(token, propName); var position = patchCmd.Position; var value = patchCmd.Value; if (position == null && (value == null || value.Type == JTokenType.Null)) { throw new InvalidOperationException("Cannot remove value from '" + propName + "' because position element does not exists or not an integer and no value was present"); } if (position != null && value != null && value.Type != JTokenType.Null) { throw new InvalidOperationException("Cannot remove value from '" + propName + "' because both a position and a value are set"); } if (position != null && (position.Value < 0 || position.Value >= array.Length)) { throw new IndexOutOfRangeException("Cannot remove value from '" + propName + "' because position element is out of bound bounds"); } if (value != null && value.Type != JTokenType.Null) { var equalityComparer = new RavenJTokenEqualityComparer(); var singleOrDefault = array.FirstOrDefault(x => equalityComparer.Equals(x, value)); if (singleOrDefault == null) { return; } array.Remove(singleOrDefault); return; } if (position != null) { array.RemoveAt(position.Value); } }
private void Apply(PatchRequest patchCmd) { if (patchCmd.Type == null) { throw new InvalidOperationException("Patch property must have a type property"); } if (patchCmd.Name == null) { throw new InvalidOperationException("Patch property must have a name property"); } switch (patchCmd.Type.ToLowerInvariant()) { case "set": AddProperty(patchCmd, patchCmd.Name); break; case "unset": RemoveProperty(patchCmd, patchCmd.Name); break; case "add": AddValue(patchCmd, patchCmd.Name); break; case "insert": InsertValue(patchCmd, patchCmd.Name); break; case "remove": RemoveValue(patchCmd, patchCmd.Name); break; case "modify": ModifyValue(patchCmd, patchCmd.Name); break; case "inc": IncrementProperty(patchCmd, patchCmd.Name); break; default: throw new ArgumentException("Cannot understand command: " + patchCmd.Type); } }
private void RemoveValue(PatchRequest patchCmd, string propName, JProperty property) { EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property == null) { property = new JProperty(propName, new JArray()); document.Add(property); } var array = property.Value as JArray; if (array == null) { throw new InvalidOperationException("Cannot remove value from '" + propName + "' because it is not an array"); } var position = patchCmd.Position; var value = patchCmd.Value; if (position == null && value == null) { throw new InvalidOperationException("Cannot remove value from '" + propName + "' because position element does not exists or not an integer and no value was present"); } if (position != null && value != null) { throw new InvalidOperationException("Cannot remove value from '" + propName + "' because both a position and a value are set"); } if (position < 0 || position >= array.Count) { throw new IndexOutOfRangeException("Cannot remove value from '" + propName + "' because position element is out of bound bounds"); } if (value != null) { var equalityComparer = new JTokenEqualityComparer(); var singleOrDefault = array.FirstOrDefault(x => equalityComparer.Equals(x, value)); if (singleOrDefault == null) { return; } array.Remove(singleOrDefault); return; } array.RemoveAt(position.Value); }
private void Apply(PatchRequest patchCmd) { if (patchCmd.Name == null) throw new InvalidOperationException("Patch property must have a name property"); foreach (var token in document.SelectTokenWithRavenSyntaxReturningFlatStructure( patchCmd.Name )) { JProperty property = null; if (token != null) property = token.Parent as JProperty; switch (patchCmd.Type) { case PatchCommandType.Set: AddProperty(patchCmd, patchCmd.Name, property); break; case PatchCommandType.Unset: RemoveProperty(patchCmd, patchCmd.Name, property); break; case PatchCommandType.Add: AddValue(patchCmd, patchCmd.Name, property); break; case PatchCommandType.Insert: InsertValue(patchCmd, patchCmd.Name, property); break; case PatchCommandType.Remove: RemoveValue(patchCmd, patchCmd.Name, property); break; case PatchCommandType.Modify: ModifyValue(patchCmd, patchCmd.Name, property); break; case PatchCommandType.Inc: IncrementProperty(patchCmd, patchCmd.Name, property); break; case PatchCommandType.Copy: CopyProperty(patchCmd, patchCmd.Name, property); break; case PatchCommandType.Rename: RenameProperty(patchCmd, patchCmd.Name, property); break; default: throw new ArgumentException("Cannot understand command: " + patchCmd.Type); } } }
private static void EnsurePreviousValueMatchCurrentValue(PatchRequest patchCmd, JProperty property) { var prevVal = patchCmd.PrevVal; if (prevVal == null) return; switch (prevVal.Type) { case JTokenType.Undefined: if (property != null) throw new ConcurrencyException(); break; default: if(property == null) throw new ConcurrencyException(); var equalityComparer = new JTokenEqualityComparer(); if (equalityComparer.Equals(property.Value, prevVal) == false) throw new ConcurrencyException(); break; } }
private void IncrementProperty(PatchRequest patchCmd, string propName, JProperty property) { if (patchCmd.Value.Type != JTokenType.Integer) { throw new InvalidOperationException("Cannot increment when value is not an integer"); } EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property == null) { property = new JProperty(propName, patchCmd.Value); document.Add(property); return; } if (property.Value == null || property.Value.Type == JTokenType.Null) { property.Value = patchCmd.Value; } else { property.Value = JToken.FromObject(property.Value.Value <int>() + patchCmd.Value.Value <int>()); } }
private void Apply(PatchRequest patchCmd) { if (patchCmd.Type == null) throw new InvalidOperationException("Patch property must have a type property"); if (patchCmd.Name == null) throw new InvalidOperationException("Patch property must have a name property"); var token = document.SelectToken(patchCmd.Name); JProperty property = null; if (token != null) property = token.Parent as JProperty; switch (patchCmd.Type.ToLowerInvariant()) { case "set": AddProperty(patchCmd, patchCmd.Name, property); break; case "unset": RemoveProperty(patchCmd, patchCmd.Name, property); break; case "add": AddValue(patchCmd, patchCmd.Name, property); break; case "insert": InsertValue(patchCmd, patchCmd.Name, property); break; case "remove": RemoveValue(patchCmd, patchCmd.Name, property); break; case "modify": ModifyValue(patchCmd, patchCmd.Name, property); break; case "inc": IncrementProperty(patchCmd, patchCmd.Name, property); break; default: throw new ArgumentException("Cannot understand command: " + patchCmd.Type); } }
private void RemoveValue(PatchRequest patchCmd, string propName) { var property = document.Property(propName); EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property == null) { property = new JProperty(propName, new JArray()); document.Add(property); } var array = property.Value as JArray; if (array == null) throw new InvalidOperationException("Cannot remove value from '" + propName + "' because it is not an array"); var position = patchCmd.Position; if (position == null) throw new InvalidOperationException("Cannot remove value from '" + propName + "' because position element does not exists or not an integer"); if (position < 0 || position >= array.Count) throw new IndexOutOfRangeException("Cannot remove value from '" + propName + "' because position element is out of bound bounds"); array.RemoveAt(position.Value); }
private void RemoveProperty(PatchRequest patchCmd, string propName) { var property = document.Property(propName); EnsurePreviousValueMatchCurrentValue(patchCmd, property); EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property != null) property.Remove(); }
private void IncrementProperty(PatchRequest patchCmd, string propName) { if(patchCmd.Value.Type != JTokenType.Integer) throw new InvalidOperationException("Cannot increment when value is not an integer"); var property = document.Property(propName); EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property == null) { property = new JProperty(propName); document.Add(property); } if (property.Value == null || property.Value.Type == JTokenType.Null) property.Value = patchCmd.Value; else property.Value = JToken.FromObject(property.Value.Value<int>() + patchCmd.Value.Value<int>()); }
private void SetProperty(PatchRequest patchCmd, string propName, RavenJToken property) { EnsurePreviousValueMatchCurrentValue(patchCmd, property); document[propName] = patchCmd.Value; }
private void RemoveProperty(PatchRequest patchCmd, string propName, JProperty property) { EnsurePreviousValueMatchCurrentValue(patchCmd, property); EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property != null) property.Remove(); }
private void RemoveValue(PatchRequest patchCmd, string propName, JProperty property) { EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property == null) { property = new JProperty(propName, new JArray()); document.Add(property); } var array = GetArray(property, propName); var position = patchCmd.Position; var value = patchCmd.Value; if (position == null && value == null) throw new InvalidOperationException("Cannot remove value from '" + propName + "' because position element does not exists or not an integer and no value was present"); if (position != null && value != null) throw new InvalidOperationException("Cannot remove value from '" + propName + "' because both a position and a value are set"); if (position < 0 || position >= array.Count) throw new IndexOutOfRangeException("Cannot remove value from '" + propName + "' because position element is out of bound bounds"); if (value != null) { var equalityComparer = new JTokenEqualityComparer(); var singleOrDefault = array.FirstOrDefault(x => equalityComparer.Equals(x, value)); if (singleOrDefault == null) return; array.Remove(singleOrDefault); return; } array.RemoveAt(position.Value); }
private void ModifyValue(PatchRequest patchCmd, string propName, JProperty property) { EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property == null) throw new InvalidOperationException("Cannot modify value from '" + propName + "' because it was not found"); var nestedCommands = patchCmd.Nested; if (nestedCommands == null) throw new InvalidOperationException("Cannot understand modified value from '" + propName + "' because could not find nested array of commands"); var arrayOrValue = TryGetArray(property) ?? property.Value; switch (arrayOrValue.Type) { case JTokenType.Object: foreach (var cmd in nestedCommands) { var nestedDoc = property.Value.Value<JObject>(); new JsonPatcher(nestedDoc).Apply(cmd); } break; case JTokenType.Array: var position = patchCmd.Position; var allPositionsIsSelected = patchCmd.AllPositions.HasValue ? patchCmd.AllPositions.Value : false; if (position == null && !allPositionsIsSelected) throw new InvalidOperationException("Cannot modify value from '" + propName + "' because position element does not exists or not an integer and allPositions is not set"); var valueList = new List<JToken>(); if (allPositionsIsSelected) { valueList.AddRange(arrayOrValue); } else { valueList.Add(arrayOrValue[position]); } foreach (var value in valueList) { foreach (var cmd in nestedCommands) { new JsonPatcher(value.Value<JObject>()).Apply(cmd); } } break; default: throw new InvalidOperationException("Can't understand how to deal with: " + property.Value.Type); } }
public PatchResult ApplyPatch(string docId, Guid? etag, PatchRequest[] patchDoc, TransactionInformation transactionInformation) { var result = PatchResult.Patched; TransactionalStorage.Batch(actions => { var doc = actions.Documents.DocumentByKey(docId, transactionInformation); if (doc == null) { result = PatchResult.DocumentDoesNotExists; } else if (etag != null && doc.Etag != etag.Value) { throw new ConcurrencyException("Could not patch document '" + docId+ "' because non current etag was used") { ActualETag = doc.Etag, ExpectedETag = etag.Value, }; } else { var jsonDoc = doc.ToJson(); new JsonPatcher(jsonDoc).Apply(patchDoc); Put(doc.Key, doc.Etag, jsonDoc, doc.Metadata, transactionInformation); result = PatchResult.Patched; } workContext.ShouldNotifyAboutWork(); }); return result; }
private void AddValue(PatchRequest patchCmd, string propName, JProperty property) { EnsurePreviousValueMatchCurrentValue(patchCmd, property); if (property == null) { property = new JProperty(propName, new JArray()); document.Add(property); } var array = GetArray(property, propName); array.Add(patchCmd.Value); }