* ObjectControllerTests.cs: chore: 格式化
* AVObject.cs: * AVAddOperation.cs: * AVSetOperation.cs: * AVDeleteOperation.cs: * AVFieldOperations.cs: * AVRemoveOperation.cs: * IAVFieldOperation.cs: * AVRelationOperation.cs: * AVAddUniqueOperation.cs: * AVIncrementOperation.cs:
parent
afebf78444
commit
d118935f21
|
@ -47,16 +47,24 @@ namespace LeanCloud.Test {
|
|||
|
||||
AVObject post = new AVObject("Post") {
|
||||
{ "name", "New Post" },
|
||||
{ "category", new AVObject("Category") }
|
||||
{ "category", new AVObject("Category") {
|
||||
{ "name", "new post category" }
|
||||
} }
|
||||
};
|
||||
comment["post"] = post;
|
||||
|
||||
AVObject testPost = new AVObject("Post") {
|
||||
{ "name", "Test Post" }
|
||||
{ "name", "Test Post" },
|
||||
{ "category", new AVObject("Category") {
|
||||
{ "name", "test post category" }
|
||||
} }
|
||||
};
|
||||
comment["test_post"] = testPost;
|
||||
|
||||
await comment.SaveAsync();
|
||||
TestContext.Out.WriteLine(post);
|
||||
TestContext.Out.WriteLine(testPost);
|
||||
TestContext.Out.WriteLine(comment);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -137,9 +145,12 @@ namespace LeanCloud.Test {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void Set() {
|
||||
public async Task Set() {
|
||||
AVObject obj = AVObject.Create("Foo");
|
||||
obj["hello"] = "world";
|
||||
await obj.SaveAsync();
|
||||
obj["world"] = "aaa";
|
||||
obj.Revert();
|
||||
TestContext.Out.WriteAsync(obj["hello"] as string);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,49 +5,49 @@ using System.Linq;
|
|||
using LeanCloud.Utilities;
|
||||
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
public class AVAddOperation : IAVFieldOperation {
|
||||
private ReadOnlyCollection<object> objects;
|
||||
public AVAddOperation(IEnumerable<object> objects) {
|
||||
this.objects = new ReadOnlyCollection<object>(objects.ToList());
|
||||
}
|
||||
public class AVAddOperation : IAVFieldOperation {
|
||||
private readonly ReadOnlyCollection<object> objects;
|
||||
|
||||
public object Encode() {
|
||||
return new Dictionary<string, object> {
|
||||
{"__op", "Add"},
|
||||
{"objects", PointerOrLocalIdEncoder.Instance.Encode(objects)}
|
||||
};
|
||||
}
|
||||
public AVAddOperation(IEnumerable<object> objects) {
|
||||
this.objects = new ReadOnlyCollection<object>(objects.ToList());
|
||||
}
|
||||
|
||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous) {
|
||||
if (previous == null) {
|
||||
return this;
|
||||
}
|
||||
if (previous is AVDeleteOperation) {
|
||||
return new AVSetOperation(objects.ToList());
|
||||
}
|
||||
if (previous is AVSetOperation) {
|
||||
var setOp = (AVSetOperation)previous;
|
||||
var oldList = Conversion.To<IList<object>>(setOp.Value);
|
||||
return new AVSetOperation(oldList.Concat(objects).ToList());
|
||||
}
|
||||
if (previous is AVAddOperation) {
|
||||
return new AVAddOperation(((AVAddOperation)previous).Objects.Concat(objects));
|
||||
}
|
||||
throw new InvalidOperationException("Operation is invalid after previous operation.");
|
||||
}
|
||||
public object Encode() {
|
||||
return new Dictionary<string, object> {
|
||||
{ "__op", "Add" },
|
||||
{ "objects", PointerOrLocalIdEncoder.Instance.Encode(objects) }
|
||||
};
|
||||
}
|
||||
|
||||
public object Apply(object oldValue, string key) {
|
||||
if (oldValue == null) {
|
||||
return objects.ToList();
|
||||
}
|
||||
var oldList = Conversion.To<IList<object>>(oldValue);
|
||||
return oldList.Concat(objects).ToList();
|
||||
}
|
||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous) {
|
||||
if (previous == null) {
|
||||
return this;
|
||||
}
|
||||
if (previous is AVDeleteOperation) {
|
||||
return new AVSetOperation(objects.ToList());
|
||||
}
|
||||
if (previous is AVSetOperation setOp) {
|
||||
var oldList = Conversion.To<IList<object>>(setOp.Value);
|
||||
return new AVSetOperation(oldList.Concat(objects).ToList());
|
||||
}
|
||||
if (previous is AVAddOperation) {
|
||||
return new AVAddOperation(((AVAddOperation)previous).Objects.Concat(objects));
|
||||
}
|
||||
throw new InvalidOperationException("Operation is invalid after previous operation.");
|
||||
}
|
||||
|
||||
public IEnumerable<object> Objects {
|
||||
get {
|
||||
return objects;
|
||||
}
|
||||
public object Apply(object oldValue, string key) {
|
||||
if (oldValue == null) {
|
||||
return objects.ToList();
|
||||
}
|
||||
var oldList = Conversion.To<IList<object>>(oldValue);
|
||||
return oldList.Concat(objects).ToList();
|
||||
}
|
||||
|
||||
public IEnumerable<object> Objects {
|
||||
get {
|
||||
return objects;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,65 +5,64 @@ using System.Linq;
|
|||
using LeanCloud.Utilities;
|
||||
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
public class AVAddUniqueOperation : IAVFieldOperation {
|
||||
private ReadOnlyCollection<object> objects;
|
||||
public AVAddUniqueOperation(IEnumerable<object> objects) {
|
||||
this.objects = new ReadOnlyCollection<object>(objects.Distinct().ToList());
|
||||
}
|
||||
|
||||
public object Encode() {
|
||||
return new Dictionary<string, object> {
|
||||
{"__op", "AddUnique"},
|
||||
{"objects", PointerOrLocalIdEncoder.Instance.Encode(objects)}
|
||||
};
|
||||
}
|
||||
|
||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous) {
|
||||
if (previous == null) {
|
||||
return this;
|
||||
}
|
||||
if (previous is AVDeleteOperation) {
|
||||
return new AVSetOperation(objects.ToList());
|
||||
}
|
||||
if (previous is AVSetOperation) {
|
||||
var setOp = (AVSetOperation)previous;
|
||||
var oldList = Conversion.To<IList<object>>(setOp.Value);
|
||||
var result = this.Apply(oldList, null);
|
||||
return new AVSetOperation(result);
|
||||
}
|
||||
if (previous is AVAddUniqueOperation) {
|
||||
var oldList = ((AVAddUniqueOperation)previous).Objects;
|
||||
return new AVAddUniqueOperation((IList<object>)this.Apply(oldList, null));
|
||||
}
|
||||
throw new InvalidOperationException("Operation is invalid after previous operation.");
|
||||
}
|
||||
|
||||
public object Apply(object oldValue, string key) {
|
||||
if (oldValue == null) {
|
||||
return objects.ToList();
|
||||
}
|
||||
var newList = Conversion.To<IList<object>>(oldValue).ToList();
|
||||
var comparer = AVFieldOperations.AVObjectComparer;
|
||||
foreach (var objToAdd in objects) {
|
||||
if (objToAdd is AVObject) {
|
||||
var matchedObj = newList.FirstOrDefault(listObj => comparer.Equals(objToAdd, listObj));
|
||||
if (matchedObj == null) {
|
||||
newList.Add(objToAdd);
|
||||
} else {
|
||||
var index = newList.IndexOf(matchedObj);
|
||||
newList[index] = objToAdd;
|
||||
}
|
||||
} else if (!newList.Contains<object>(objToAdd, comparer)) {
|
||||
newList.Add(objToAdd);
|
||||
public class AVAddUniqueOperation : IAVFieldOperation {
|
||||
private ReadOnlyCollection<object> objects;
|
||||
public AVAddUniqueOperation(IEnumerable<object> objects) {
|
||||
this.objects = new ReadOnlyCollection<object>(objects.Distinct().ToList());
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
public IEnumerable<object> Objects {
|
||||
get {
|
||||
return objects;
|
||||
}
|
||||
public object Encode() {
|
||||
return new Dictionary<string, object> {
|
||||
{ "__op", "AddUnique" },
|
||||
{ "objects", PointerOrLocalIdEncoder.Instance.Encode(objects) }
|
||||
};
|
||||
}
|
||||
|
||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous) {
|
||||
if (previous == null) {
|
||||
return this;
|
||||
}
|
||||
if (previous is AVDeleteOperation) {
|
||||
return new AVSetOperation(objects.ToList());
|
||||
}
|
||||
if (previous is AVSetOperation setOp) {
|
||||
var oldList = Conversion.To<IList<object>>(setOp.Value);
|
||||
var result = this.Apply(oldList, null);
|
||||
return new AVSetOperation(result);
|
||||
}
|
||||
if (previous is AVAddUniqueOperation) {
|
||||
var oldList = ((AVAddUniqueOperation)previous).Objects;
|
||||
return new AVAddUniqueOperation((IList<object>)this.Apply(oldList, null));
|
||||
}
|
||||
throw new InvalidOperationException("Operation is invalid after previous operation.");
|
||||
}
|
||||
|
||||
public object Apply(object oldValue, string key) {
|
||||
if (oldValue == null) {
|
||||
return objects.ToList();
|
||||
}
|
||||
var newList = Conversion.To<IList<object>>(oldValue).ToList();
|
||||
var comparer = AVFieldOperations.AVObjectComparer;
|
||||
foreach (var objToAdd in objects) {
|
||||
if (objToAdd is AVObject) {
|
||||
var matchedObj = newList.FirstOrDefault(listObj => comparer.Equals(objToAdd, listObj));
|
||||
if (matchedObj == null) {
|
||||
newList.Add(objToAdd);
|
||||
} else {
|
||||
var index = newList.IndexOf(matchedObj);
|
||||
newList[index] = objToAdd;
|
||||
}
|
||||
} else if (!newList.Contains<object>(objToAdd, comparer)) {
|
||||
newList.Add(objToAdd);
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
public IEnumerable<object> Objects {
|
||||
get {
|
||||
return objects;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,32 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace LeanCloud.Storage.Internal
|
||||
{
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
/// <summary>
|
||||
/// An operation where a field is deleted from the object.
|
||||
/// </summary>
|
||||
public class AVDeleteOperation : IAVFieldOperation
|
||||
{
|
||||
public class AVDeleteOperation : IAVFieldOperation {
|
||||
internal static readonly object DeleteToken = new object();
|
||||
private static AVDeleteOperation _Instance = new AVDeleteOperation();
|
||||
public static AVDeleteOperation Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
public static AVDeleteOperation Instance {
|
||||
get {
|
||||
return _Instance;
|
||||
}
|
||||
}
|
||||
|
||||
private AVDeleteOperation() { }
|
||||
public object Encode()
|
||||
{
|
||||
|
||||
public object Encode() {
|
||||
return new Dictionary<string, object> {
|
||||
{"__op", "Delete"}
|
||||
};
|
||||
}
|
||||
|
||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous)
|
||||
{
|
||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public object Apply(object oldValue, string key)
|
||||
{
|
||||
public object Apply(object oldValue, string key) {
|
||||
return DeleteToken;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,39 +2,36 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
public class AVObjectIdComparer : IEqualityComparer<object> {
|
||||
bool IEqualityComparer<object>.Equals(object p1, object p2) {
|
||||
var avObj1 = p1 as AVObject;
|
||||
var avObj2 = p2 as AVObject;
|
||||
if (avObj1 != null && avObj2 != null) {
|
||||
return object.Equals(avObj1.ObjectId, avObj2.ObjectId);
|
||||
}
|
||||
return object.Equals(p1, p2);
|
||||
}
|
||||
|
||||
public int GetHashCode(object p) {
|
||||
var avObject = p as AVObject;
|
||||
if (avObject != null) {
|
||||
return avObject.ObjectId.GetHashCode();
|
||||
}
|
||||
return p.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
static class AVFieldOperations {
|
||||
private static AVObjectIdComparer comparer;
|
||||
|
||||
public static IAVFieldOperation Decode(IDictionary<string, object> json) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static IEqualityComparer<object> AVObjectComparer {
|
||||
get {
|
||||
if (comparer == null) {
|
||||
comparer = new AVObjectIdComparer();
|
||||
public class AVObjectIdComparer : IEqualityComparer<object> {
|
||||
bool IEqualityComparer<object>.Equals(object p1, object p2) {
|
||||
if (p1 is AVObject avObj1 && p2 is AVObject avObj2) {
|
||||
return object.Equals(avObj1.ObjectId, avObj2.ObjectId);
|
||||
}
|
||||
return object.Equals(p1, p2);
|
||||
}
|
||||
|
||||
public int GetHashCode(object p) {
|
||||
if (p is AVObject avObject) {
|
||||
return avObject.ObjectId.GetHashCode();
|
||||
}
|
||||
return p.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
static class AVFieldOperations {
|
||||
private static AVObjectIdComparer comparer;
|
||||
|
||||
public static IAVFieldOperation Decode(IDictionary<string, object> json) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static IEqualityComparer<object> AVObjectComparer {
|
||||
get {
|
||||
if (comparer == null) {
|
||||
comparer = new AVObjectIdComparer();
|
||||
}
|
||||
return comparer;
|
||||
}
|
||||
}
|
||||
return comparer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,85 +2,80 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace LeanCloud.Storage.Internal
|
||||
{
|
||||
public class AVIncrementOperation : IAVFieldOperation
|
||||
{
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
public class AVIncrementOperation : IAVFieldOperation {
|
||||
private static readonly IDictionary<Tuple<Type, Type>, Func<object, object, object>> adders;
|
||||
|
||||
static AVIncrementOperation()
|
||||
{
|
||||
static AVIncrementOperation() {
|
||||
// Defines adders for all of the implicit conversions: http://msdn.microsoft.com/en-US/library/y5b434w4(v=vs.80).aspx
|
||||
adders = new Dictionary<Tuple<Type, Type>, Func<object, object, object>> {
|
||||
{new Tuple<Type, Type>(typeof(sbyte), typeof(sbyte)), (left, right) => (sbyte)left + (sbyte)right},
|
||||
{new Tuple<Type, Type>(typeof(sbyte), typeof(short)), (left, right) => (sbyte)left + (short)right},
|
||||
{new Tuple<Type, Type>(typeof(sbyte), typeof(int)), (left, right) => (sbyte)left + (int)right},
|
||||
{new Tuple<Type, Type>(typeof(sbyte), typeof(long)), (left, right) => (sbyte)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(sbyte), typeof(float)), (left, right) => (sbyte)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(sbyte), typeof(double)), (left, right) => (sbyte)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(sbyte), typeof(decimal)), (left, right) => (sbyte)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(byte)), (left, right) => (byte)left + (byte)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(short)), (left, right) => (byte)left + (short)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(ushort)), (left, right) => (byte)left + (ushort)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(int)), (left, right) => (byte)left + (int)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(uint)), (left, right) => (byte)left + (uint)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(long)), (left, right) => (byte)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(ulong)), (left, right) => (byte)left + (ulong)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(float)), (left, right) => (byte)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(double)), (left, right) => (byte)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(decimal)), (left, right) => (byte)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(short), typeof(short)), (left, right) => (short)left + (short)right},
|
||||
{new Tuple<Type, Type>(typeof(short), typeof(int)), (left, right) => (short)left + (int)right},
|
||||
{new Tuple<Type, Type>(typeof(short), typeof(long)), (left, right) => (short)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(short), typeof(float)), (left, right) => (short)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(short), typeof(double)), (left, right) => (short)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(short), typeof(decimal)), (left, right) => (short)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(ushort)), (left, right) => (ushort)left + (ushort)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(int)), (left, right) => (ushort)left + (int)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(uint)), (left, right) => (ushort)left + (uint)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(long)), (left, right) => (ushort)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(ulong)), (left, right) => (ushort)left + (ulong)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(float)), (left, right) => (ushort)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(double)), (left, right) => (ushort)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(decimal)), (left, right) => (ushort)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(int), typeof(int)), (left, right) => (int)left + (int)right},
|
||||
{new Tuple<Type, Type>(typeof(int), typeof(long)), (left, right) => (int)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(int), typeof(float)), (left, right) => (int)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(int), typeof(double)), (left, right) => (int)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(int), typeof(decimal)), (left, right) => (int)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(uint), typeof(uint)), (left, right) => (uint)left + (uint)right},
|
||||
{new Tuple<Type, Type>(typeof(uint), typeof(long)), (left, right) => (uint)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(uint), typeof(ulong)), (left, right) => (uint)left + (ulong)right},
|
||||
{new Tuple<Type, Type>(typeof(uint), typeof(float)), (left, right) => (uint)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(uint), typeof(double)), (left, right) => (uint)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(uint), typeof(decimal)), (left, right) => (uint)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(long), typeof(long)), (left, right) => (long)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(long), typeof(float)), (left, right) => (long)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(long), typeof(double)), (left, right) => (long)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(long), typeof(decimal)), (left, right) => (long)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(char)), (left, right) => (char)left + (char)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(ushort)), (left, right) => (char)left + (ushort)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(int)), (left, right) => (char)left + (int)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(uint)), (left, right) => (char)left + (uint)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(long)), (left, right) => (char)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(ulong)), (left, right) => (char)left + (ulong)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(float)), (left, right) => (char)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(double)), (left, right) => (char)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(decimal)), (left, right) => (char)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(float), typeof(float)), (left, right) => (float)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(float), typeof(double)), (left, right) => (float)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(ulong), typeof(ulong)), (left, right) => (ulong)left + (ulong)right},
|
||||
{new Tuple<Type, Type>(typeof(ulong), typeof(float)), (left, right) => (ulong)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(ulong), typeof(double)), (left, right) => (ulong)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(ulong), typeof(decimal)), (left, right) => (ulong)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(double), typeof(double)), (left, right) => (double)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(decimal), typeof(decimal)), (left, right) => (decimal)left + (decimal)right}
|
||||
};
|
||||
{new Tuple<Type, Type>(typeof(sbyte), typeof(sbyte)), (left, right) => (sbyte)left + (sbyte)right},
|
||||
{new Tuple<Type, Type>(typeof(sbyte), typeof(short)), (left, right) => (sbyte)left + (short)right},
|
||||
{new Tuple<Type, Type>(typeof(sbyte), typeof(int)), (left, right) => (sbyte)left + (int)right},
|
||||
{new Tuple<Type, Type>(typeof(sbyte), typeof(long)), (left, right) => (sbyte)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(sbyte), typeof(float)), (left, right) => (sbyte)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(sbyte), typeof(double)), (left, right) => (sbyte)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(sbyte), typeof(decimal)), (left, right) => (sbyte)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(byte)), (left, right) => (byte)left + (byte)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(short)), (left, right) => (byte)left + (short)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(ushort)), (left, right) => (byte)left + (ushort)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(int)), (left, right) => (byte)left + (int)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(uint)), (left, right) => (byte)left + (uint)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(long)), (left, right) => (byte)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(ulong)), (left, right) => (byte)left + (ulong)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(float)), (left, right) => (byte)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(double)), (left, right) => (byte)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(byte), typeof(decimal)), (left, right) => (byte)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(short), typeof(short)), (left, right) => (short)left + (short)right},
|
||||
{new Tuple<Type, Type>(typeof(short), typeof(int)), (left, right) => (short)left + (int)right},
|
||||
{new Tuple<Type, Type>(typeof(short), typeof(long)), (left, right) => (short)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(short), typeof(float)), (left, right) => (short)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(short), typeof(double)), (left, right) => (short)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(short), typeof(decimal)), (left, right) => (short)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(ushort)), (left, right) => (ushort)left + (ushort)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(int)), (left, right) => (ushort)left + (int)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(uint)), (left, right) => (ushort)left + (uint)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(long)), (left, right) => (ushort)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(ulong)), (left, right) => (ushort)left + (ulong)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(float)), (left, right) => (ushort)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(double)), (left, right) => (ushort)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(ushort), typeof(decimal)), (left, right) => (ushort)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(int), typeof(int)), (left, right) => (int)left + (int)right},
|
||||
{new Tuple<Type, Type>(typeof(int), typeof(long)), (left, right) => (int)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(int), typeof(float)), (left, right) => (int)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(int), typeof(double)), (left, right) => (int)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(int), typeof(decimal)), (left, right) => (int)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(uint), typeof(uint)), (left, right) => (uint)left + (uint)right},
|
||||
{new Tuple<Type, Type>(typeof(uint), typeof(long)), (left, right) => (uint)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(uint), typeof(ulong)), (left, right) => (uint)left + (ulong)right},
|
||||
{new Tuple<Type, Type>(typeof(uint), typeof(float)), (left, right) => (uint)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(uint), typeof(double)), (left, right) => (uint)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(uint), typeof(decimal)), (left, right) => (uint)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(long), typeof(long)), (left, right) => (long)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(long), typeof(float)), (left, right) => (long)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(long), typeof(double)), (left, right) => (long)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(long), typeof(decimal)), (left, right) => (long)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(char)), (left, right) => (char)left + (char)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(ushort)), (left, right) => (char)left + (ushort)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(int)), (left, right) => (char)left + (int)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(uint)), (left, right) => (char)left + (uint)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(long)), (left, right) => (char)left + (long)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(ulong)), (left, right) => (char)left + (ulong)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(float)), (left, right) => (char)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(double)), (left, right) => (char)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(char), typeof(decimal)), (left, right) => (char)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(float), typeof(float)), (left, right) => (float)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(float), typeof(double)), (left, right) => (float)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(ulong), typeof(ulong)), (left, right) => (ulong)left + (ulong)right},
|
||||
{new Tuple<Type, Type>(typeof(ulong), typeof(float)), (left, right) => (ulong)left + (float)right},
|
||||
{new Tuple<Type, Type>(typeof(ulong), typeof(double)), (left, right) => (ulong)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(ulong), typeof(decimal)), (left, right) => (ulong)left + (decimal)right},
|
||||
{new Tuple<Type, Type>(typeof(double), typeof(double)), (left, right) => (double)left + (double)right},
|
||||
{new Tuple<Type, Type>(typeof(decimal), typeof(decimal)), (left, right) => (decimal)left + (decimal)right}
|
||||
};
|
||||
// Generate the adders in the other direction
|
||||
foreach (var pair in adders.Keys.ToList())
|
||||
{
|
||||
if (pair.Item1.Equals(pair.Item2))
|
||||
{
|
||||
foreach (var pair in adders.Keys.ToList()) {
|
||||
if (pair.Item1.Equals(pair.Item2)) {
|
||||
continue;
|
||||
}
|
||||
var reversePair = new Tuple<Type, Type>(pair.Item2, pair.Item1);
|
||||
|
@ -91,52 +86,42 @@ namespace LeanCloud.Storage.Internal
|
|||
|
||||
private object amount;
|
||||
|
||||
public AVIncrementOperation(object amount)
|
||||
{
|
||||
public AVIncrementOperation(object amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public object Encode()
|
||||
{
|
||||
return new Dictionary<string, object>
|
||||
public object Encode() {
|
||||
return new Dictionary<string, object>
|
||||
{
|
||||
{"__op", "Increment"},
|
||||
{"amount", amount}
|
||||
};
|
||||
}
|
||||
|
||||
private static object Add(object obj1, object obj2)
|
||||
{
|
||||
private static object Add(object obj1, object obj2) {
|
||||
Func<object, object, object> adder;
|
||||
if (adders.TryGetValue(new Tuple<Type, Type>(obj1.GetType(), obj2.GetType()), out adder))
|
||||
{
|
||||
if (adders.TryGetValue(new Tuple<Type, Type>(obj1.GetType(), obj2.GetType()), out adder)) {
|
||||
return adder(obj1, obj2);
|
||||
}
|
||||
throw new InvalidCastException("Cannot add " + obj1.GetType() + " to " + obj2.GetType());
|
||||
}
|
||||
|
||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous)
|
||||
{
|
||||
if (previous == null)
|
||||
{
|
||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous) {
|
||||
if (previous == null) {
|
||||
return this;
|
||||
}
|
||||
if (previous is AVDeleteOperation)
|
||||
{
|
||||
if (previous is AVDeleteOperation) {
|
||||
return new AVSetOperation(amount);
|
||||
}
|
||||
if (previous is AVSetOperation)
|
||||
{
|
||||
if (previous is AVSetOperation) {
|
||||
var otherAmount = ((AVSetOperation)previous).Value;
|
||||
if (otherAmount is string)
|
||||
{
|
||||
if (otherAmount is string) {
|
||||
throw new InvalidOperationException("Cannot increment a non-number type.");
|
||||
}
|
||||
var myAmount = amount;
|
||||
return new AVSetOperation(Add(otherAmount, myAmount));
|
||||
}
|
||||
if (previous is AVIncrementOperation)
|
||||
{
|
||||
if (previous is AVIncrementOperation) {
|
||||
object otherAmount = ((AVIncrementOperation)previous).Amount;
|
||||
object myAmount = amount;
|
||||
return new AVIncrementOperation(Add(otherAmount, myAmount));
|
||||
|
@ -144,10 +129,8 @@ namespace LeanCloud.Storage.Internal
|
|||
throw new InvalidOperationException("Operation is invalid after previous operation.");
|
||||
}
|
||||
|
||||
public object Apply(object oldValue, string key)
|
||||
{
|
||||
if (oldValue is string)
|
||||
{
|
||||
public object Apply(object oldValue, string key) {
|
||||
if (oldValue is string) {
|
||||
throw new InvalidOperationException("Cannot increment a non-number type.");
|
||||
}
|
||||
object otherAmount = oldValue ?? 0;
|
||||
|
@ -155,10 +138,8 @@ namespace LeanCloud.Storage.Internal
|
|||
return Add(otherAmount, myAmount);
|
||||
}
|
||||
|
||||
public object Amount
|
||||
{
|
||||
get
|
||||
{
|
||||
public object Amount {
|
||||
get {
|
||||
return amount;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,113 +6,113 @@ using System.Text;
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
public class AVRelationOperation : IAVFieldOperation {
|
||||
private readonly IList<string> adds;
|
||||
private readonly IList<string> removes;
|
||||
private readonly string targetClassName;
|
||||
public class AVRelationOperation : IAVFieldOperation {
|
||||
private readonly IList<string> adds;
|
||||
private readonly IList<string> removes;
|
||||
private readonly string targetClassName;
|
||||
|
||||
private AVRelationOperation(IEnumerable<string> adds,
|
||||
IEnumerable<string> removes,
|
||||
string targetClassName) {
|
||||
this.targetClassName = targetClassName;
|
||||
this.adds = new ReadOnlyCollection<string>(adds.ToList());
|
||||
this.removes = new ReadOnlyCollection<string>(removes.ToList());
|
||||
}
|
||||
|
||||
public AVRelationOperation(IEnumerable<AVObject> adds,
|
||||
IEnumerable<AVObject> removes) {
|
||||
adds = adds ?? new AVObject[0];
|
||||
removes = removes ?? new AVObject[0];
|
||||
this.targetClassName = adds.Concat(removes).Select(o => o.ClassName).FirstOrDefault();
|
||||
this.adds = new ReadOnlyCollection<string>(IdsFromObjects(adds).ToList());
|
||||
this.removes = new ReadOnlyCollection<string>(IdsFromObjects(removes).ToList());
|
||||
}
|
||||
|
||||
public object Encode() {
|
||||
var adds = this.adds
|
||||
.Select(id => PointerOrLocalIdEncoder.Instance.Encode(
|
||||
AVObject.CreateWithoutData(targetClassName, id)))
|
||||
.ToList();
|
||||
var removes = this.removes
|
||||
.Select(id => PointerOrLocalIdEncoder.Instance.Encode(
|
||||
AVObject.CreateWithoutData(targetClassName, id)))
|
||||
.ToList();
|
||||
var addDict = adds.Count == 0 ? null : new Dictionary<string, object> {
|
||||
{"__op", "AddRelation"},
|
||||
{"objects", adds}
|
||||
};
|
||||
var removeDict = removes.Count == 0 ? null : new Dictionary<string, object> {
|
||||
{"__op", "RemoveRelation"},
|
||||
{"objects", removes}
|
||||
};
|
||||
|
||||
if (addDict != null && removeDict != null) {
|
||||
return new Dictionary<string, object> {
|
||||
{"__op", "Batch"},
|
||||
{"ops", new[] {addDict, removeDict}}
|
||||
};
|
||||
}
|
||||
return addDict ?? removeDict;
|
||||
}
|
||||
|
||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous) {
|
||||
if (previous == null) {
|
||||
return this;
|
||||
}
|
||||
if (previous is AVDeleteOperation) {
|
||||
throw new InvalidOperationException("You can't modify a relation after deleting it.");
|
||||
}
|
||||
var other = previous as AVRelationOperation;
|
||||
if (other != null) {
|
||||
if (other.TargetClassName != TargetClassName) {
|
||||
throw new InvalidOperationException(
|
||||
string.Format("Related object must be of class {0}, but {1} was passed in.",
|
||||
other.TargetClassName,
|
||||
TargetClassName));
|
||||
private AVRelationOperation(IEnumerable<string> adds,
|
||||
IEnumerable<string> removes,
|
||||
string targetClassName) {
|
||||
this.targetClassName = targetClassName;
|
||||
this.adds = new ReadOnlyCollection<string>(adds.ToList());
|
||||
this.removes = new ReadOnlyCollection<string>(removes.ToList());
|
||||
}
|
||||
var newAdd = adds.Union(other.adds.Except(removes)).ToList();
|
||||
var newRemove = removes.Union(other.removes.Except(adds)).ToList();
|
||||
return new AVRelationOperation(newAdd, newRemove, TargetClassName);
|
||||
}
|
||||
throw new InvalidOperationException("Operation is invalid after previous operation.");
|
||||
}
|
||||
|
||||
public object Apply(object oldValue, string key) {
|
||||
if (adds.Count == 0 && removes.Count == 0) {
|
||||
return null;
|
||||
}
|
||||
if (oldValue == null) {
|
||||
return AVRelationBase.CreateRelation(null, key, targetClassName);
|
||||
}
|
||||
if (oldValue is AVRelationBase) {
|
||||
var oldRelation = (AVRelationBase)oldValue;
|
||||
var oldClassName = oldRelation.TargetClassName;
|
||||
if (oldClassName != null && oldClassName != targetClassName) {
|
||||
throw new InvalidOperationException("Related object must be a " + oldClassName
|
||||
+ ", but a " + targetClassName + " was passed in.");
|
||||
public AVRelationOperation(IEnumerable<AVObject> adds,
|
||||
IEnumerable<AVObject> removes) {
|
||||
adds = adds ?? new AVObject[0];
|
||||
removes = removes ?? new AVObject[0];
|
||||
this.targetClassName = adds.Concat(removes).Select(o => o.ClassName).FirstOrDefault();
|
||||
this.adds = new ReadOnlyCollection<string>(IdsFromObjects(adds).ToList());
|
||||
this.removes = new ReadOnlyCollection<string>(IdsFromObjects(removes).ToList());
|
||||
}
|
||||
oldRelation.TargetClassName = targetClassName;
|
||||
return oldRelation;
|
||||
}
|
||||
throw new InvalidOperationException("Operation is invalid after previous operation.");
|
||||
}
|
||||
|
||||
public string TargetClassName { get { return targetClassName; } }
|
||||
public object Encode() {
|
||||
var adds = this.adds
|
||||
.Select(id => PointerOrLocalIdEncoder.Instance.Encode(
|
||||
AVObject.CreateWithoutData(targetClassName, id)))
|
||||
.ToList();
|
||||
var removes = this.removes
|
||||
.Select(id => PointerOrLocalIdEncoder.Instance.Encode(
|
||||
AVObject.CreateWithoutData(targetClassName, id)))
|
||||
.ToList();
|
||||
var addDict = adds.Count == 0 ? null : new Dictionary<string, object> {
|
||||
{"__op", "AddRelation"},
|
||||
{"objects", adds}
|
||||
};
|
||||
var removeDict = removes.Count == 0 ? null : new Dictionary<string, object> {
|
||||
{"__op", "RemoveRelation"},
|
||||
{"objects", removes}
|
||||
};
|
||||
|
||||
private IEnumerable<string> IdsFromObjects(IEnumerable<AVObject> objects) {
|
||||
foreach (var obj in objects) {
|
||||
if (obj.ObjectId == null) {
|
||||
throw new ArgumentException(
|
||||
"You can't add an unsaved AVObject to a relation.");
|
||||
if (addDict != null && removeDict != null) {
|
||||
return new Dictionary<string, object> {
|
||||
{"__op", "Batch"},
|
||||
{"ops", new[] {addDict, removeDict}}
|
||||
};
|
||||
}
|
||||
return addDict ?? removeDict;
|
||||
}
|
||||
if (obj.ClassName != targetClassName) {
|
||||
throw new ArgumentException(string.Format(
|
||||
"Tried to create a AVRelation with 2 different types: {0} and {1}",
|
||||
targetClassName,
|
||||
obj.ClassName));
|
||||
|
||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous) {
|
||||
if (previous == null) {
|
||||
return this;
|
||||
}
|
||||
if (previous is AVDeleteOperation) {
|
||||
throw new InvalidOperationException("You can't modify a relation after deleting it.");
|
||||
}
|
||||
var other = previous as AVRelationOperation;
|
||||
if (other != null) {
|
||||
if (other.TargetClassName != TargetClassName) {
|
||||
throw new InvalidOperationException(
|
||||
string.Format("Related object must be of class {0}, but {1} was passed in.",
|
||||
other.TargetClassName,
|
||||
TargetClassName));
|
||||
}
|
||||
var newAdd = adds.Union(other.adds.Except(removes)).ToList();
|
||||
var newRemove = removes.Union(other.removes.Except(adds)).ToList();
|
||||
return new AVRelationOperation(newAdd, newRemove, TargetClassName);
|
||||
}
|
||||
throw new InvalidOperationException("Operation is invalid after previous operation.");
|
||||
}
|
||||
|
||||
public object Apply(object oldValue, string key) {
|
||||
if (adds.Count == 0 && removes.Count == 0) {
|
||||
return null;
|
||||
}
|
||||
if (oldValue == null) {
|
||||
return AVRelationBase.CreateRelation(null, key, targetClassName);
|
||||
}
|
||||
if (oldValue is AVRelationBase) {
|
||||
var oldRelation = (AVRelationBase)oldValue;
|
||||
var oldClassName = oldRelation.TargetClassName;
|
||||
if (oldClassName != null && oldClassName != targetClassName) {
|
||||
throw new InvalidOperationException("Related object must be a " + oldClassName
|
||||
+ ", but a " + targetClassName + " was passed in.");
|
||||
}
|
||||
oldRelation.TargetClassName = targetClassName;
|
||||
return oldRelation;
|
||||
}
|
||||
throw new InvalidOperationException("Operation is invalid after previous operation.");
|
||||
}
|
||||
|
||||
public string TargetClassName { get { return targetClassName; } }
|
||||
|
||||
private IEnumerable<string> IdsFromObjects(IEnumerable<AVObject> objects) {
|
||||
foreach (var obj in objects) {
|
||||
if (obj.ObjectId == null) {
|
||||
throw new ArgumentException(
|
||||
"You can't add an unsaved AVObject to a relation.");
|
||||
}
|
||||
if (obj.ClassName != targetClassName) {
|
||||
throw new ArgumentException(string.Format(
|
||||
"Tried to create a AVRelation with 2 different types: {0} and {1}",
|
||||
targetClassName,
|
||||
obj.ClassName));
|
||||
}
|
||||
}
|
||||
return objects.Select(o => o.ObjectId).Distinct();
|
||||
}
|
||||
}
|
||||
return objects.Select(o => o.ObjectId).Distinct();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,62 +5,49 @@ using System.Linq;
|
|||
|
||||
using LeanCloud.Utilities;
|
||||
|
||||
namespace LeanCloud.Storage.Internal
|
||||
{
|
||||
public class AVRemoveOperation : IAVFieldOperation
|
||||
{
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
public class AVRemoveOperation : IAVFieldOperation {
|
||||
private ReadOnlyCollection<object> objects;
|
||||
public AVRemoveOperation(IEnumerable<object> objects)
|
||||
{
|
||||
public AVRemoveOperation(IEnumerable<object> objects) {
|
||||
this.objects = new ReadOnlyCollection<object>(objects.Distinct().ToList());
|
||||
}
|
||||
|
||||
public object Encode()
|
||||
{
|
||||
public object Encode() {
|
||||
return new Dictionary<string, object> {
|
||||
{ "__op", "Remove" },
|
||||
{ "objects", PointerOrLocalIdEncoder.Instance.Encode(objects) }
|
||||
};
|
||||
}
|
||||
|
||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous)
|
||||
{
|
||||
if (previous == null)
|
||||
{
|
||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous) {
|
||||
if (previous == null) {
|
||||
return this;
|
||||
}
|
||||
if (previous is AVDeleteOperation)
|
||||
{
|
||||
if (previous is AVDeleteOperation) {
|
||||
return previous;
|
||||
}
|
||||
if (previous is AVSetOperation)
|
||||
{
|
||||
if (previous is AVSetOperation) {
|
||||
var setOp = (AVSetOperation)previous;
|
||||
var oldList = Conversion.As<IList<object>>(setOp.Value);
|
||||
return new AVSetOperation(this.Apply(oldList, null));
|
||||
}
|
||||
if (previous is AVRemoveOperation)
|
||||
{
|
||||
if (previous is AVRemoveOperation) {
|
||||
var oldOp = (AVRemoveOperation)previous;
|
||||
return new AVRemoveOperation(oldOp.Objects.Concat(objects));
|
||||
}
|
||||
throw new InvalidOperationException("Operation is invalid after previous operation.");
|
||||
}
|
||||
|
||||
public object Apply(object oldValue, string key)
|
||||
{
|
||||
if (oldValue == null)
|
||||
{
|
||||
public object Apply(object oldValue, string key) {
|
||||
if (oldValue == null) {
|
||||
return new List<object>();
|
||||
}
|
||||
var oldList = Conversion.As<IList<object>>(oldValue);
|
||||
return oldList.Except(objects, AVFieldOperations.AVObjectComparer).ToList();
|
||||
}
|
||||
|
||||
public IEnumerable<object> Objects
|
||||
{
|
||||
get
|
||||
{
|
||||
public IEnumerable<object> Objects {
|
||||
get {
|
||||
return objects;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
namespace LeanCloud.Storage.Internal {
|
||||
public class AVSetOperation : IAVFieldOperation {
|
||||
public AVSetOperation(object value) {
|
||||
Value = value;
|
||||
}
|
||||
public class AVSetOperation : IAVFieldOperation {
|
||||
public AVSetOperation(object value) {
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public object Encode() {
|
||||
return PointerOrLocalIdEncoder.Instance.Encode(Value);
|
||||
}
|
||||
public object Encode() {
|
||||
return PointerOrLocalIdEncoder.Instance.Encode(Value);
|
||||
}
|
||||
|
||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous) {
|
||||
return this;
|
||||
}
|
||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public object Apply(object oldValue, string key) {
|
||||
return Value;
|
||||
}
|
||||
public object Apply(object oldValue, string key) {
|
||||
return Value;
|
||||
}
|
||||
|
||||
public object Value { get; private set; }
|
||||
}
|
||||
public object Value { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,42 +1,42 @@
|
|||
namespace LeanCloud.Storage.Internal {
|
||||
/// <summary>
|
||||
/// A AVFieldOperation represents a modification to a value in a AVObject.
|
||||
/// For example, setting, deleting, or incrementing a value are all different kinds of
|
||||
/// AVFieldOperations. AVFieldOperations themselves can be considered to be
|
||||
/// immutable.
|
||||
/// </summary>
|
||||
public interface IAVFieldOperation {
|
||||
/// <summary>
|
||||
/// Converts the AVFieldOperation to a data structure that can be converted to JSON and sent to
|
||||
/// LeanCloud as part of a save operation.
|
||||
/// A AVFieldOperation represents a modification to a value in a AVObject.
|
||||
/// For example, setting, deleting, or incrementing a value are all different kinds of
|
||||
/// AVFieldOperations. AVFieldOperations themselves can be considered to be
|
||||
/// immutable.
|
||||
/// </summary>
|
||||
/// <returns>An object to be JSONified.</returns>
|
||||
object Encode();
|
||||
public interface IAVFieldOperation {
|
||||
/// <summary>
|
||||
/// Converts the AVFieldOperation to a data structure that can be converted to JSON and sent to
|
||||
/// LeanCloud as part of a save operation.
|
||||
/// </summary>
|
||||
/// <returns>An object to be JSONified.</returns>
|
||||
object Encode();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a field operation that is composed of a previous operation followed by
|
||||
/// this operation. This will not mutate either operation. However, it may return
|
||||
/// <code>this</code> if the current operation is not affected by previous changes.
|
||||
/// For example:
|
||||
/// {increment by 2}.MergeWithPrevious({set to 5}) -> {set to 7}
|
||||
/// {set to 5}.MergeWithPrevious({increment by 2}) -> {set to 5}
|
||||
/// {add "foo"}.MergeWithPrevious({delete}) -> {set to ["foo"]}
|
||||
/// {delete}.MergeWithPrevious({add "foo"}) -> {delete} /// </summary>
|
||||
/// <param name="previous">The most recent operation on the field, or null if none.</param>
|
||||
/// <returns>A new AVFieldOperation or this.</returns>
|
||||
IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous);
|
||||
/// <summary>
|
||||
/// Returns a field operation that is composed of a previous operation followed by
|
||||
/// this operation. This will not mutate either operation. However, it may return
|
||||
/// <code>this</code> if the current operation is not affected by previous changes.
|
||||
/// For example:
|
||||
/// {increment by 2}.MergeWithPrevious({set to 5}) -> {set to 7}
|
||||
/// {set to 5}.MergeWithPrevious({increment by 2}) -> {set to 5}
|
||||
/// {add "foo"}.MergeWithPrevious({delete}) -> {set to ["foo"]}
|
||||
/// {delete}.MergeWithPrevious({add "foo"}) -> {delete} /// </summary>
|
||||
/// <param name="previous">The most recent operation on the field, or null if none.</param>
|
||||
/// <returns>A new AVFieldOperation or this.</returns>
|
||||
IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new estimated value based on a previous value and this operation. This
|
||||
/// value is not intended to be sent to LeanCloud, but it is used locally on the client to
|
||||
/// inspect the most likely current value for a field.
|
||||
///
|
||||
/// The key and object are used solely for AVRelation to be able to construct objects
|
||||
/// that refer back to their parents.
|
||||
/// </summary>
|
||||
/// <param name="oldValue">The previous value for the field.</param>
|
||||
/// <param name="key">The key that this value is for.</param>
|
||||
/// <returns>The new value for the field.</returns>
|
||||
object Apply(object oldValue, string key);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a new estimated value based on a previous value and this operation. This
|
||||
/// value is not intended to be sent to LeanCloud, but it is used locally on the client to
|
||||
/// inspect the most likely current value for a field.
|
||||
///
|
||||
/// The key and object are used solely for AVRelation to be able to construct objects
|
||||
/// that refer back to their parents.
|
||||
/// </summary>
|
||||
/// <param name="oldValue">The previous value for the field.</param>
|
||||
/// <param name="key">The key that this value is for.</param>
|
||||
/// <returns>The new value for the field.</returns>
|
||||
object Apply(object oldValue, string key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,6 @@ using System.Runtime.CompilerServices;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace LeanCloud {
|
||||
/// <summary>
|
||||
|
@ -18,13 +16,6 @@ namespace LeanCloud {
|
|||
public class AVObject : IEnumerable<KeyValuePair<string, object>>, INotifyPropertyChanged, INotifyPropertyUpdated, INotifyCollectionPropertyUpdated {
|
||||
private static readonly string AutoClassName = "_Automatic";
|
||||
|
||||
#if UNITY
|
||||
private static readonly bool isCompiledByIL2CPP = AppDomain.CurrentDomain.FriendlyName.Equals("IL2CPP Root Domain");
|
||||
#else
|
||||
private static readonly bool isCompiledByIL2CPP = false;
|
||||
#endif
|
||||
|
||||
|
||||
internal readonly object mutex = new object();
|
||||
|
||||
private readonly LinkedList<IDictionary<string, IAVFieldOperation>> operationSetQueue =
|
||||
|
@ -75,7 +66,7 @@ namespace LeanCloud {
|
|||
/// Constructor for use in AVObject subclasses. Subclasses must specify a AVClassName attribute.
|
||||
/// </summary>
|
||||
protected AVObject()
|
||||
: this(AutoClassName) {
|
||||
: this(AutoClassName) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1008,7 +999,7 @@ string propertyName
|
|||
// We've just applied a bunch of operations to estimatedData which
|
||||
// may have changed all of its keys. Notify of all keys and properties
|
||||
// mapped to keys being changed.
|
||||
OnFieldsChanged(changedKeys);
|
||||
OnFieldsChanged(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue