private static string GetTreeName(BlittableJsonReaderObject reduceEntry, IndexDefinitionBase indexDefinition, JsonOperationContext context) { HashSet <string> groupByFields; if (indexDefinition is MapReduceIndexDefinition) { groupByFields = ((MapReduceIndexDefinition)indexDefinition).GroupByFields; } else if (indexDefinition is AutoMapReduceIndexDefinition) { groupByFields = ((AutoMapReduceIndexDefinition)indexDefinition).GroupByFields.Keys.ToHashSet(); } else { throw new InvalidOperationException("Invalid map reduce index definition: " + indexDefinition.GetType()); } foreach (var prop in reduceEntry.GetPropertyNames()) { if (groupByFields.Contains(prop)) { continue; } if (reduceEntry.Modifications == null) { reduceEntry.Modifications = new DynamicJsonValue(reduceEntry); } reduceEntry.Modifications.Remove(prop); } var reduceKey = context.ReadObject(reduceEntry, "debug: creating reduce tree name"); return(reduceKey.ToString()); }
private static DocumentCompareResult ComparePropertiesExceptStartingWithAt(BlittableJsonReaderObject current, BlittableJsonReaderObject modified, bool isMetadata = false, bool tryMergeAttachmentsConflict = false) { var resolvedAttachmetConflict = false; var properties = new HashSet <string>(current.GetPropertyNames()); foreach (var propertyName in modified.GetPropertyNames()) { properties.Add(propertyName); } foreach (var property in properties) { if (property[0] == '@') { if (isMetadata) { if (property.Equals(Constants.Documents.Metadata.Attachments, StringComparison.OrdinalIgnoreCase)) { if (tryMergeAttachmentsConflict) { if (current.TryGetMember(property, out object _) == false || modified.TryGetMember(property, out object _) == false) { // Resolve when just 1 document have attachments resolvedAttachmetConflict = true; continue; } resolvedAttachmetConflict = ShouldResolveAttachmentsConflict(current, modified); if (resolvedAttachmetConflict) { continue; } return(DocumentCompareResult.NotEqual); } } else if (property.Equals(Constants.Documents.Metadata.Collection, StringComparison.OrdinalIgnoreCase) == false) { continue; } } else if (property.Equals(Constants.Documents.Metadata.Key, StringComparison.OrdinalIgnoreCase)) { continue; } } if (current.TryGetMember(property, out object currentProperty) == false || modified.TryGetMember(property, out object modifiedPropery) == false) { return(DocumentCompareResult.NotEqual); } if (Equals(currentProperty, modifiedPropery) == false) { return(DocumentCompareResult.NotEqual); } } return(DocumentCompareResult.Equal | (resolvedAttachmetConflict ? DocumentCompareResult.ShouldRecreateDocument : DocumentCompareResult.None)); }
private static unsafe bool CompareBlittable(string fieldPath, string id, BlittableJsonReaderObject originalBlittable, BlittableJsonReaderObject newBlittable, IDictionary <string, DocumentsChanges[]> changes, List <DocumentsChanges> docChanges) { BlittableJsonReaderObject.AssertNoModifications(originalBlittable, id, assertChildren: false); BlittableJsonReaderObject.AssertNoModifications(newBlittable, id, assertChildren: false); var newBlittableProps = newBlittable.GetPropertyNames(); var oldBlittableProps = originalBlittable.GetPropertyNames(); var newFields = new HashSet <string>(newBlittableProps); newFields.ExceptWith(oldBlittableProps); var removedFields = new HashSet <string>(oldBlittableProps); removedFields.ExceptWith(newBlittableProps); using var orderedProperties = newBlittable.GetPropertiesByInsertionOrder(); foreach (var field in removedFields) { if (changes == null) { return(true); } if (field.Equals(LastModified) || field.Equals(ChangeVector) || field.Equals(Id)) { continue; } NewChange(fieldPath, field, null, null, docChanges, DocumentsChanges.ChangeType.RemovedField); } var newProp = new BlittableJsonReaderObject.PropertyDetails(); var oldProp = new BlittableJsonReaderObject.PropertyDetails(); for (int i = 0; i < orderedProperties.Size; i++) { newBlittable.GetPropertyByIndex(orderedProperties.Properties[i], ref newProp); if (newProp.Name.Equals(LastModified) || newProp.Name.Equals(Collection) || newProp.Name.Equals(ChangeVector) || newProp.Name.Equals(Id)) { continue; } if (newFields.Contains(newProp.Name)) { if (changes == null) { return(true); } NewChange(fieldPath, newProp.Name, newProp.Value, null, docChanges, DocumentsChanges.ChangeType.NewField); continue; } var oldPropId = originalBlittable.GetPropertyIndex(newProp.Name); originalBlittable.GetPropertyByIndex(oldPropId, ref oldProp); switch ((newProp.Token & BlittableJsonReaderBase.TypesMask)) { case BlittableJsonToken.Integer: case BlittableJsonToken.Boolean: case BlittableJsonToken.LazyNumber: case BlittableJsonToken.CompressedString: case BlittableJsonToken.String: if (newProp.Value.Equals(oldProp.Value) || CompareValues(oldProp, newProp) || CompareStringsWithEscapePositions(newBlittable._context, oldProp, newProp)) { break; } if (changes == null) { return(true); } NewChange(fieldPath, newProp.Name, newProp.Value, oldProp.Value, docChanges, DocumentsChanges.ChangeType.FieldChanged); break; case BlittableJsonToken.Null: if (oldProp.Value == null) { break; } if (changes == null) { return(true); } NewChange(fieldPath, newProp.Name, null, oldProp.Value, docChanges, DocumentsChanges.ChangeType.FieldChanged); break; case BlittableJsonToken.StartArray: var newArray = newProp.Value as BlittableJsonReaderArray; var oldArray = oldProp.Value as BlittableJsonReaderArray; if (newArray == null) { throw new InvalidDataException($"Invalid blittable, expected array but got {newProp.Value}"); } if (oldArray == null) { if (changes == null) { return(true); } NewChange(fieldPath, newProp.Name, newProp.Value, oldProp.Value, docChanges, DocumentsChanges.ChangeType.FieldChanged); break; } var changed = CompareBlittableArray(FieldPathCombine(fieldPath, newProp.Name), id, oldArray, newArray, changes, docChanges, newProp.Name); if (changes == null && changed) { return(true); } break; case BlittableJsonToken.StartObject: if (oldProp.Value == null || !(oldProp.Value is BlittableJsonReaderObject oldObj)) { if (changes == null) { return(true); } NewChange(fieldPath, newProp.Name, newProp.Value, oldProp.Value, docChanges, DocumentsChanges.ChangeType.FieldChanged); break; } if (!(newProp.Value is BlittableJsonReaderObject newObj)) { throw new InvalidDataException($"Invalid blittable, expected object but got {newProp.Value}"); } changed = CompareBlittable(FieldPathCombine(fieldPath, newProp.Name), id, oldObj, newObj, changes, docChanges); if (changes == null && changed) { return(true); } break; default: throw new ArgumentOutOfRangeException(); } } if ((changes == null) || (docChanges.Count <= 0)) { return(false); } changes[id] = docChanges.ToArray(); return(true); }
private static bool TrySimplifyJson(BlittableJsonReaderObject document, Type rootType) { var simplified = false; foreach (var propertyName in document.GetPropertyNames()) { var propertyType = GetPropertyType(propertyName, rootType); if (propertyType == typeof(JObject) || propertyType == typeof(JArray) || propertyType == typeof(JValue)) { // don't simplify the property if it's a JObject continue; } var propertyValue = document[propertyName]; if (propertyValue is BlittableJsonReaderArray propertyArray) { simplified |= TrySimplifyJson(propertyArray, propertyType); continue; } var propertyObject = propertyValue as BlittableJsonReaderObject; if (propertyObject == null) { continue; } if (propertyObject.TryGet(Constants.Json.Fields.Type, out string type) == false) { simplified |= TrySimplifyJson(propertyObject, propertyType); continue; } if (ShouldSimplifyJsonBasedOnType(type) == false) { continue; } simplified = true; if (document.Modifications == null) { document.Modifications = new DynamicJsonValue(document); } if (propertyObject.TryGet(Constants.Json.Fields.Values, out BlittableJsonReaderArray values) == false) { if (propertyObject.Modifications == null) { propertyObject.Modifications = new DynamicJsonValue(propertyObject); } propertyObject.Modifications.Remove(Constants.Json.Fields.Type); continue; } document.Modifications[propertyName] = values; simplified |= TrySimplifyJson(values, propertyType); } return(simplified); }
private static bool CompareBlittable(string id, BlittableJsonReaderObject originalBlittable, BlittableJsonReaderObject newBlittable, IDictionary <string, DocumentsChanges[]> changes, List <DocumentsChanges> docChanges) { BlittableJsonReaderObject.AssertNoModifications(originalBlittable, id, assertChildren: false); BlittableJsonReaderObject.AssertNoModifications(newBlittable, id, assertChildren: false); var newBlittableProps = newBlittable.GetPropertyNames(); var oldBlittableProps = originalBlittable.GetPropertyNames(); var newFields = newBlittableProps.Except(oldBlittableProps); var removedFields = oldBlittableProps.Except(newBlittableProps); var propertiesIds = newBlittable.GetPropertiesByInsertionOrder(); foreach (var field in removedFields) { if (changes == null) { return(true); } NewChange(field, null, null, docChanges, DocumentsChanges.ChangeType.RemovedField); } var newProp = new BlittableJsonReaderObject.PropertyDetails(); var oldProp = new BlittableJsonReaderObject.PropertyDetails(); foreach (var propId in propertiesIds) { newBlittable.GetPropertyByIndex(propId, ref newProp); if (newProp.Name.Equals(LastModified) || newProp.Name.Equals(Collection) || newProp.Name.Equals(ChangeVector) || newProp.Name.Equals(Id)) { continue; } if (newFields.Contains(newProp.Name)) { if (changes == null) { return(true); } NewChange(newProp.Name, newProp.Value, null, docChanges, DocumentsChanges.ChangeType.NewField); continue; } var oldPropId = originalBlittable.GetPropertyIndex(newProp.Name); originalBlittable.GetPropertyByIndex(oldPropId, ref oldProp); switch ((newProp.Token & BlittableJsonReaderBase.TypesMask)) { case BlittableJsonToken.Integer: case BlittableJsonToken.Boolean: case BlittableJsonToken.LazyNumber: case BlittableJsonToken.CompressedString: case BlittableJsonToken.String: if (newProp.Value.Equals(oldProp.Value) || ComapreValues(oldProp, newProp)) { break; } if (changes == null) { return(true); } NewChange(newProp.Name, newProp.Value, oldProp.Value, docChanges, DocumentsChanges.ChangeType.FieldChanged); break; case BlittableJsonToken.Null: if (oldProp.Value == null) { break; } if (changes == null) { return(true); } NewChange(newProp.Name, null, oldProp.Value, docChanges, DocumentsChanges.ChangeType.FieldChanged); break; case BlittableJsonToken.StartArray: var newArray = newProp.Value as BlittableJsonReaderArray; var oldArray = oldProp.Value as BlittableJsonReaderArray; if ((newArray == null) || (oldArray == null)) { throw new InvalidDataException("Invalid blittable"); } var changed = CompareBlittableArray(id, oldArray, newArray, changes, docChanges, newProp.Name); if (changed == false) { break; } if (changes == null) { return(true); } break; case BlittableJsonToken.StartObject: if (oldProp.Value == null) { if (changes == null) { return(true); } changed = true; NewChange(newProp.Name, newProp.Value, null, docChanges, DocumentsChanges.ChangeType.FieldChanged); } else { changed = CompareBlittable(id, oldProp.Value as BlittableJsonReaderObject, newProp.Value as BlittableJsonReaderObject, changes, docChanges); } if ((changes == null) && (changed)) { return(true); } break; default: throw new ArgumentOutOfRangeException(); } } if ((changes == null) || (docChanges.Count <= 0)) { return(false); } changes[id] = docChanges.ToArray(); return(true); }
public override BlittableJsonReaderObject GetUpdatedValue(JsonOperationContext context, BlittableJsonReaderObject previousValue, long index) { if (string.IsNullOrWhiteSpace(Value.Name)) { Value.Name = GenerateTaskName(previousValue); } var prevTaskId = Value.TaskId; Value.TaskId = index; string oldName = null; if (previousValue != null) { previousValue.Modifications ??= new DynamicJsonValue(); if (previousValue.TryGet(Value.Name, out object _) == false) { if (prevTaskId != 0) { foreach (var propertyName in previousValue.GetPropertyNames()) { var property = (BlittableJsonReaderObject)previousValue[propertyName]; if (property.TryGet(nameof(ServerWideBackupConfiguration.TaskId), out long taskId) == false) { throw new RachisInvalidOperationException( $"Current {nameof(ServerWideBackupConfiguration)} has no {nameof(ServerWideBackupConfiguration.TaskId)} " + $"or the {nameof(ServerWideBackupConfiguration.TaskId)} is not of the correct type. " + $"Should not happen\n {previousValue}"); } if (taskId != prevTaskId) { continue; } oldName = propertyName; break; } if (oldName == null) { throw new RachisInvalidOperationException( $"Can't find {nameof(ServerWideBackupConfiguration)} with {nameof(ServerWideBackupConfiguration.Name)} {Value.Name} or with {nameof(ServerWideBackupConfiguration.TaskId)} {prevTaskId}. " + $"If you try to create new {nameof(ServerWideBackupConfiguration)} set the {nameof(ServerWideBackupConfiguration.TaskId)} to 0." + $"If you try to update exist {nameof(ServerWideBackupConfiguration)} and change its name, request the configuration again from the server to get the current {nameof(ServerWideBackupConfiguration.TaskId)} and send the {nameof(PutServerWideBackupConfigurationCommand)} again"); } } } var modifications = new DynamicJsonValue(previousValue); if (oldName != null && oldName.Equals(Value.Name) == false) { modifications.Remove(oldName); } modifications[Value.Name] = Value.ToJson(); var blittableJsonReaderObject = context.ReadObject(previousValue, Name); return(blittableJsonReaderObject); } var djv = new DynamicJsonValue { [Value.Name] = Value.ToJson() }; return(context.ReadObject(djv, Name)); }