public UpdateDefinition <BsonDocument> BuildUpdatesForSave(UpdateDefinition <BsonDocument> update, TrackableDictionaryTracker <TKey, TValue> tracker, params object[] keyValues) { var keyNamespace = DocumentHelper.ToDotPathWithTrailer(keyValues); foreach (var change in tracker.ChangeMap) { switch (change.Value.Operation) { case TrackableDictionaryOperation.Add: case TrackableDictionaryOperation.Modify: update = update == null ? Builders <BsonDocument> .Update.Set(keyNamespace + change.Key, change.Value.NewValue) : update.Set(keyNamespace + change.Key, change.Value.NewValue); break; case TrackableDictionaryOperation.Remove: update = update == null ? Builders <BsonDocument> .Update.Unset(keyNamespace + change.Key) : update.Unset(keyNamespace + change.Key); break; } } return(update); }
public static TrackableDictionaryTracker <TKey, TValue> Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { var count = reader.ReadArrayHeader(); TrackableDictionaryTracker <TKey, TValue> tracker = new TrackableDictionaryTracker <TKey, TValue>(); for (var i = 0; i < count; i++) { var operation = reader.ReadInt32(); var key = MessagePackSerializer.Deserialize <TKey>(ref reader, options); var value = MessagePackSerializer.Deserialize <TValue>(ref reader, options); switch (operation) { case (int)TrackableDictionaryOperation.Add: tracker.TrackAdd(key, value); break; case (int)TrackableDictionaryOperation.Remove: tracker.TrackRemove(key, value); break; case (int)TrackableDictionaryOperation.Modify: tracker.TrackModify(key, default(TValue), value); break; } } return(tracker); }
public void TestDictionary_RollbackToTracker_Work() { var dict = CreateTestDictionaryWithTracker(); dict[1] = "OneModified"; dict.Remove(2); dict[4] = "FourAdded"; var tracker2 = new TrackableDictionaryTracker <int, string>(); dict.Tracker.ApplyTo(tracker2); dict.Tracker.RollbackTo(tracker2); var dict2 = CreateTestDictionary(); tracker2.ApplyTo(dict2); Assert.Equal( new KeyValuePair <int, string>[] { new KeyValuePair <int, string>(1, "One"), new KeyValuePair <int, string>(2, "Two"), new KeyValuePair <int, string>(3, "Three") }, dict2.OrderBy(kv => kv.Key)); }
public static void Serialize(ref MessagePackWriter writer, TrackableDictionaryTracker <TKey, TValue> value, MessagePackSerializerOptions options) { var tracker = value; writer.WriteArrayHeader(tracker.ChangeMap.Count); foreach (var item in tracker.ChangeMap) { switch (item.Value.Operation) { case TrackableDictionaryOperation.Add: writer.Write((int)item.Value.Operation); MessagePackSerializer.Serialize(ref writer, item.Key, options); MessagePackSerializer.Serialize(ref writer, item.Value.NewValue, options); break; case TrackableDictionaryOperation.Remove: writer.Write((int)item.Value.Operation); MessagePackSerializer.Serialize(ref writer, item.Key, options); MessagePackSerializer.Serialize(ref writer, default(TValue), options); break; case TrackableDictionaryOperation.Modify: writer.Write((int)item.Value.Operation); MessagePackSerializer.Serialize(ref writer, item.Key, options); MessagePackSerializer.Serialize(ref writer, item.Value.NewValue, options); break; } } }
public void Test_DictionaryTracker_Serialize() { var tracker = new TrackableDictionaryTracker <int, string>(); tracker.TrackAdd(1, "One"); AssertTrackerSerialize(tracker); }
public async Task <int> SaveAsync(DbConnection connection, TrackableDictionaryTracker <TKey, TValue> tracker, params object[] keyValues) { if (tracker.HasChange == false) { return(0); } var sql = BuildSqlForSave(tracker, keyValues); using (var command = _sqlProvider.CreateDbCommand(sql, connection)) { return(await command.ExecuteNonQueryAsync()); } }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType != JsonToken.StartObject) { return(null); } var tracker = new TrackableDictionaryTracker <TKey, TValue>(); reader.Read(); while (true) { if (reader.TokenType != JsonToken.PropertyName) { break; } var str = (string)reader.Value; reader.Read(); var key = JsonConvert.DeserializeObject <TKey>(str.Substring(1)); TValue obj; switch (str[0]) { case '+': obj = serializer.Deserialize <TValue>(reader); reader.Read(); tracker.TrackAdd(key, obj); break; case '-': reader.Read(); tracker.TrackRemove(key, default(TValue)); break; case '=': obj = serializer.Deserialize <TValue>(reader); reader.Read(); tracker.TrackModify(key, default(TValue), obj); break; } } return(tracker); }
public async Task SaveAsync(IDatabase db, TrackableDictionaryTracker <TKey, TValue> tracker, RedisKey key) { var updates = tracker.ChangeMap.Where(i => i.Value.Operation == TrackableDictionaryOperation.Add || i.Value.Operation == TrackableDictionaryOperation.Modify) .Select(i => new HashEntry(_keyToRedisValue(i.Key), _valueToRedisValue(i.Value.NewValue))).ToArray(); var removeKeys = tracker.RemoveKeys.Select(_keyToRedisValue).ToArray(); if (updates.Length > 0) { await db.HashSetAsync(key, updates); } if (removeKeys.Length > 0) { await db.HashDeleteAsync(key, removeKeys); } }
public static TrackableDictionaryTrackerSurrogate <TKey, TValue> Convert( TrackableDictionaryTracker <TKey, TValue> tracker) { if (tracker == null) { return(null); } var surrogate = new TrackableDictionaryTrackerSurrogate <TKey, TValue>(); foreach (var item in tracker.ChangeMap) { surrogate.ChangeList.Add(new Change { Operation = item.Value.Operation, Key = item.Key, NewValue = item.Value.NewValue, }); } return(surrogate); }
public Task <UpdateResult> SaveAsync(IMongoCollection <BsonDocument> collection, TrackableDictionaryTracker <TKey, TValue> tracker, params object[] keyValues) { if (keyValues.Length == 0) { throw new ArgumentException("At least 1 keyValue required."); } if (tracker.HasChange == false) { return(Task.FromResult((UpdateResult)null)); } return(collection.UpdateOneAsync( Builders <BsonDocument> .Filter.Eq("_id", keyValues[0]), BuildUpdatesForSave(null, tracker, keyValues.Skip(1).ToArray()), new UpdateOptions { IsUpsert = true })); }
public static TrackableDictionaryTracker <TKey, TValue> Convert( TrackableDictionaryTrackerSurrogate <TKey, TValue> surrogate) { if (surrogate == null) { return(null); } var tracker = new TrackableDictionaryTracker <TKey, TValue>(); foreach (var change in surrogate.ChangeList) { tracker.ChangeMap.Add( change.Key, new TrackableDictionaryTracker <TKey, TValue> .Change { Operation = change.Operation, NewValue = change.NewValue }); } return(tracker); }
public void Serialize(ref MessagePackWriter writer, TrackableDictionaryTracker <TKey, TValue> value, MessagePackSerializerOptions options) { TrackableDictionaryTrackerMessagePackFormatter <TKey, TValue> .Serialize(ref writer, value, options); }
public string BuildSqlForSave(TrackableDictionaryTracker <TKey, TValue> tracker, params object[] keyValues) { if (keyValues.Length != _headKeyColumns.Length) { throw new ArgumentException("Number of keyValues should be same with the number of head columns"); } var sqlAdd = new StringBuilder(); var sqlModify = new StringBuilder(); var removeIds = new List <TKey>(); // generate sql command for each changes var insertCount = 0; foreach (var i in tracker.ChangeMap) { var v = i.Value.NewValue; switch (i.Value.Operation) { case TrackableDictionaryOperation.Add: if (insertCount == 0) { sqlAdd.Append("INSERT INTO ").Append(_tableEscapedName); sqlAdd.Append(" (").Append(_allColumnString).Append(") VALUES\n"); } else { sqlAdd.Append(",\n"); } sqlAdd.Append(" ("); for (var k = 0; k < _headKeyColumns.Length; k++) { sqlAdd.Append(_headKeyColumns[k].ConvertToSqlValue(keyValues[k])); sqlAdd.Append(","); } sqlAdd.Append(_keyColumn.ConvertToSqlValue(i.Key)); foreach (var col in _valueColumns) { sqlAdd.Append(",").Append(col.ExtractToSqlValue(v)); } sqlAdd.Append(")"); insertCount += 1; if (insertCount >= 1000) { sqlAdd.Append(";\n"); insertCount = 0; } break; case TrackableDictionaryOperation.Modify: sqlModify.Append("UPDATE ").Append(_tableEscapedName); sqlModify.Append(" SET "); var concating = false; foreach (var col in _valueColumns) { if (concating == false) { concating = true; } else { sqlModify.Append(","); } sqlModify.Append(col.EscapedName).Append("=").Append(col.ExtractToSqlValue(v)); } sqlModify.Append(" WHERE "); for (var k = 0; k < _headKeyColumns.Length; k++) { sqlModify.Append(_headKeyColumns[k].EscapedName).Append("="); sqlModify.Append(_headKeyColumns[k].ConvertToSqlValue(keyValues[k])); sqlModify.Append(" AND "); } sqlModify.Append(_keyColumn.EscapedName).Append("="); sqlModify.Append(_keyColumn.ConvertToSqlValue(i.Key)).Append(";\n"); break; case TrackableDictionaryOperation.Remove: removeIds.Add(i.Key); break; } } if (insertCount > 0) { sqlAdd.Append(";\n"); } // merge insert, update and delete sql into one sql var sql = new StringBuilder(); sql.Append(sqlAdd); sql.Append(sqlModify); if (removeIds.Any()) { sql.Append("DELETE FROM ").Append(_tableEscapedName).Append(" WHERE "); for (var k = 0; k < _headKeyColumns.Length; k++) { sql.Append(_headKeyColumns[k].EscapedName).Append("="); sql.Append(_headKeyColumns[k].ConvertToSqlValue(keyValues[k])); sql.Append(" AND "); } sql.Append(_keyColumn.EscapedName).Append(" IN ("); var concating = false; foreach (var id in removeIds) { if (concating == false) { concating = true; } else { sql.Append(","); } sql.Append(_keyColumn.ConvertToSqlValue(id)); } sql.Append(");\n"); } return(sql.ToString()); }
public void TestDictionary_RollbackToTracker_Work() { var dict = CreateTestDictionaryWithTracker(); dict[1] = "OneModified"; dict.Remove(2); dict[4] = "FourAdded"; var tracker2 = new TrackableDictionaryTracker<int, string>(); dict.Tracker.ApplyTo(tracker2); dict.Tracker.RollbackTo(tracker2); var dict2 = CreateTestDictionary(); tracker2.ApplyTo(dict2); Assert.Equal( new KeyValuePair<int, string>[] { new KeyValuePair<int, string>(1, "One"), new KeyValuePair<int, string>(2, "Two"), new KeyValuePair<int, string>(3, "Three") }, dict2.OrderBy(kv => kv.Key)); }