public void Test_ListTracker_Serialize()
        {
            var tracker = new TrackableListTracker <int>();

            tracker.TrackPushBack(0);
            AssertTrackerSerialize(tracker);
        }
Esempio n. 2
0
        public void TestList_ApplyToTracker_Work()
        {
            var list = CreateTestListWithTracker();

            ModifyListForTest(list);

            var tracker2 = new TrackableListTracker <string>();

            list.Tracker.ApplyTo(tracker2);

            var list2 = CreateTestList();

            tracker2.ApplyTo(list2);

            Assert.Equal(GetModifiedList(), list2);
        }
Esempio n. 3
0
        public static IListTracker <T> Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
        {
            var tracker = new TrackableListTracker <T>();
            var length  = reader.ReadArrayHeader();

            for (int i = 0; i < length; i++)
            {
                var operation = reader.ReadInt32();
                var index     = reader.ReadInt32();
                var value     = MessagePackSerializer.Deserialize <T>(ref reader, options);
                switch ((TrackableListOperation)operation)
                {
                case TrackableListOperation.Insert:
                    tracker.TrackInsert(index, value);
                    break;

                case TrackableListOperation.Remove:
                    tracker.TrackRemove(index, value);
                    break;

                case TrackableListOperation.Modify:
                    tracker.TrackModify(index, default(T), value);
                    break;

                case TrackableListOperation.PushFront:
                    tracker.TrackPushFront(value);
                    break;

                case TrackableListOperation.PushBack:
                    tracker.TrackPushBack(value);
                    break;

                case TrackableListOperation.PopFront:
                    tracker.TrackPopFront(default(T));
                    break;

                case TrackableListOperation.PopBack:
                    tracker.TrackPopBack(default(T));
                    break;
                }
            }
            return(tracker);
        }
        public static TrackableListTracker <T> Convert(TrackableListTrackerSurrogate <T> surrogate)
        {
            if (surrogate == null)
            {
                return(null);
            }

            var tracker = new TrackableListTracker <T>();

            foreach (var change in surrogate.ChangeList)
            {
                tracker.ChangeList.Add(new TrackableListTracker <T> .Change
                {
                    Operation = change.Operation,
                    Index     = change.Index,
                    NewValue  = change.NewValue,
                });
            }
            return(tracker);
        }
        public async Task SaveAsync(IDatabase db, TrackableListTracker <T> tracker, RedisKey key)
        {
            foreach (var change in tracker.ChangeList)
            {
                switch (change.Operation)
                {
                case TrackableListOperation.Insert:
                    throw new InvalidOperationException("Redis doesn't support insert value by index.");

                case TrackableListOperation.Remove:
                    throw new InvalidOperationException("Redis doesn't support remove value by index.");

                case TrackableListOperation.Modify:
                    await db.ListSetByIndexAsync(key, change.Index, _valueToRedisValue(change.NewValue));

                    break;

                case TrackableListOperation.PushFront:
                    await db.ListLeftPushAsync(key, _valueToRedisValue(change.NewValue));

                    break;

                case TrackableListOperation.PushBack:
                    await db.ListRightPushAsync(key, _valueToRedisValue(change.NewValue));

                    break;

                case TrackableListOperation.PopFront:
                    await db.ListLeftPopAsync(key);

                    break;

                case TrackableListOperation.PopBack:
                    await db.ListRightPopAsync(key);

                    break;
                }
            }
        }
Esempio n. 6
0
        public async Task SaveAsync(IMongoCollection <BsonDocument> collection,
                                    TrackableListTracker <T> tracker,
                                    params object[] keyValues)
        {
            if (keyValues.Length < 2)
            {
                throw new ArgumentException("At least 2 keyValue required.");
            }

            if (tracker.HasChange == false)
            {
                return;
            }

            var filter = Builders <BsonDocument> .Filter.Eq("_id", keyValues[0]);

            foreach (var update in BuildUpdatesForSave(null, tracker, keyValues.Skip(1).ToArray()))
            {
                await collection.UpdateOneAsync(
                    filter, update, new UpdateOptions { IsUpsert = true });
            }
        }
Esempio n. 7
0
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
                                        JsonSerializer serializer)
        {
            if (reader.TokenType != JsonToken.StartArray)
            {
                return(null);
            }

            var tracker = new TrackableListTracker <T>();

            reader.Read();
            while (true)
            {
                if (reader.TokenType != JsonToken.StartArray)
                {
                    break;
                }
                reader.Read();

                var str = (string)reader.Value;
                reader.Read();

                if (str.Length < 2)
                {
                    throw new Exception("Wrong index token: " + str);
                }

                int index;
                if (str[1] == 'F')
                {
                    index = -2;
                }
                else if (str[1] == 'B')
                {
                    index = -1;
                }
                else if (int.TryParse(str.Substring(1), out index) == false)
                {
                    throw new Exception("Invalid token: " + str);
                }

                T obj;
                switch (str[0])
                {
                case '+':
                    obj = serializer.Deserialize <T>(reader);
                    reader.Read();
                    if (index == -2)
                    {
                        tracker.TrackPushFront(obj);
                    }
                    else if (index == -1)
                    {
                        tracker.TrackPushBack(obj);
                    }
                    else
                    {
                        tracker.TrackInsert(index, obj);
                    }
                    break;

                case '-':
                    if (index == -2)
                    {
                        tracker.TrackPopFront(default(T));
                    }
                    else if (index == -1)
                    {
                        tracker.TrackPopBack(default(T));
                    }
                    else
                    {
                        tracker.TrackRemove(index, default(T));
                    }
                    break;

                case '=':
                    obj = serializer.Deserialize <T>(reader);
                    reader.Read();
                    tracker.TrackModify(index, default(T), obj);
                    break;
                }

                if (reader.TokenType != JsonToken.EndArray)
                {
                    throw new Exception("Wrong token type: " + reader.TokenType);
                }

                reader.Read();
            }

            return(tracker);
        }
Esempio n. 8
0
        public List <UpdateDefinition <BsonDocument> > BuildUpdatesForSave(
            UpdateDefinition <BsonDocument> update, TrackableListTracker <T> tracker, params object[] keyValues)
        {
            var keyNamespace = DocumentHelper.ToDotPath(keyValues);

            // Multiple push-back batching optimization
            if (tracker.ChangeList.Count > 1 &&
                tracker.ChangeList.All(c => c.Operation == TrackableListOperation.PushBack))
            {
                var newValues = tracker.ChangeList.Select(c => c.NewValue);
                return(new List <UpdateDefinition <BsonDocument> >
                {
                    update == null
                        ? Builders <BsonDocument> .Update.PushEach(keyNamespace, newValues)
                        : update.PushEach(keyNamespace, newValues)
                });
            }

            // Multiple push-front batching optimization
            if (tracker.ChangeList.Count > 1 &&
                tracker.ChangeList.All(c => c.Operation == TrackableListOperation.PushFront))
            {
                var newValues = tracker.ChangeList.Select(c => c.NewValue).Reverse();
                return(new List <UpdateDefinition <BsonDocument> >
                {
                    update == null
                        ? Builders <BsonDocument> .Update.PushEach(keyNamespace, newValues, position : 0)
                        : update.PushEach(keyNamespace, newValues, position: 0)
                });
            }

            // List update can process only one change each time
            var updates = new List <UpdateDefinition <BsonDocument> >();

            foreach (var change in tracker.ChangeList)
            {
                switch (change.Operation)
                {
                case TrackableListOperation.Insert:
                    updates.Add(update == null
                            ? Builders <BsonDocument> .Update.PushEach(keyNamespace, new[] { change.NewValue }, position: change.Index)
                            : update.PushEach(keyNamespace, new[] { change.NewValue }, position: change.Index));
                    update = null;
                    break;

                case TrackableListOperation.Remove:
                    throw new Exception("Remove operation is not supported!");

                case TrackableListOperation.Modify:
                    updates.Add(update == null
                            ? Builders <BsonDocument> .Update.Set(keyNamespace + "." + change.Index, change.NewValue)
                            : update.Set(keyNamespace + "." + change.Index, change.NewValue));
                    break;

                case TrackableListOperation.PushFront:
                    updates.Add(update == null
                            ? Builders <BsonDocument> .Update.PushEach(keyNamespace, new[] { change.NewValue }, position: 0)
                            : update.PushEach(keyNamespace, new[] { change.NewValue }, position: 0));
                    break;

                case TrackableListOperation.PushBack:
                    updates.Add(update == null
                            ? Builders <BsonDocument> .Update.Push(keyNamespace, change.NewValue)
                            : update.Push(keyNamespace, change.NewValue));
                    break;

                case TrackableListOperation.PopFront:
                    updates.Add(update == null
                            ? Builders <BsonDocument> .Update.PopFirst(keyNamespace)
                            : update.PopFirst(keyNamespace));
                    break;

                case TrackableListOperation.PopBack:
                    updates.Add(update == null
                            ? Builders <BsonDocument> .Update.PopLast(keyNamespace)
                            : update.PopLast(keyNamespace));
                    break;
                }
            }

            if (update != null)
            {
                updates.Add(update);
            }

            return(updates);
        }
Esempio n. 9
0
 public void Serialize(ref MessagePackWriter writer, TrackableListTracker <T> value, MessagePackSerializerOptions options)
 {
     TrackableListTrackerMessagePackFormatter <T> .Serialize(ref writer, value, options);
 }
Esempio n. 10
0
        public void TestList_RollbackToTracker_Work()
        {
            var list = CreateTestListWithTracker();
            ModifyListForTest(list);

            var tracker2 = new TrackableListTracker<string>();
            list.Tracker.ApplyTo(tracker2);
            list.Tracker.RollbackTo(tracker2);

            var list2 = CreateTestList();
            tracker2.ApplyTo(list2);

            Assert.Equal(GetInitialList(), list2);
        }