* 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") {
|
AVObject post = new AVObject("Post") {
|
||||||
{ "name", "New Post" },
|
{ "name", "New Post" },
|
||||||
{ "category", new AVObject("Category") }
|
{ "category", new AVObject("Category") {
|
||||||
|
{ "name", "new post category" }
|
||||||
|
} }
|
||||||
};
|
};
|
||||||
comment["post"] = post;
|
comment["post"] = post;
|
||||||
|
|
||||||
AVObject testPost = new AVObject("Post") {
|
AVObject testPost = new AVObject("Post") {
|
||||||
{ "name", "Test Post" }
|
{ "name", "Test Post" },
|
||||||
|
{ "category", new AVObject("Category") {
|
||||||
|
{ "name", "test post category" }
|
||||||
|
} }
|
||||||
};
|
};
|
||||||
comment["test_post"] = testPost;
|
comment["test_post"] = testPost;
|
||||||
|
|
||||||
await comment.SaveAsync();
|
await comment.SaveAsync();
|
||||||
|
TestContext.Out.WriteLine(post);
|
||||||
|
TestContext.Out.WriteLine(testPost);
|
||||||
|
TestContext.Out.WriteLine(comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -137,9 +145,12 @@ namespace LeanCloud.Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Set() {
|
public async Task Set() {
|
||||||
AVObject obj = AVObject.Create("Foo");
|
AVObject obj = AVObject.Create("Foo");
|
||||||
obj["hello"] = "world";
|
obj["hello"] = "world";
|
||||||
|
await obj.SaveAsync();
|
||||||
|
obj["world"] = "aaa";
|
||||||
|
obj.Revert();
|
||||||
TestContext.Out.WriteAsync(obj["hello"] as string);
|
TestContext.Out.WriteAsync(obj["hello"] as string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,8 @@ using LeanCloud.Utilities;
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal {
|
namespace LeanCloud.Storage.Internal {
|
||||||
public class AVAddOperation : IAVFieldOperation {
|
public class AVAddOperation : IAVFieldOperation {
|
||||||
private ReadOnlyCollection<object> objects;
|
private readonly ReadOnlyCollection<object> objects;
|
||||||
|
|
||||||
public AVAddOperation(IEnumerable<object> objects) {
|
public AVAddOperation(IEnumerable<object> objects) {
|
||||||
this.objects = new ReadOnlyCollection<object>(objects.ToList());
|
this.objects = new ReadOnlyCollection<object>(objects.ToList());
|
||||||
}
|
}
|
||||||
|
@ -25,8 +26,7 @@ namespace LeanCloud.Storage.Internal {
|
||||||
if (previous is AVDeleteOperation) {
|
if (previous is AVDeleteOperation) {
|
||||||
return new AVSetOperation(objects.ToList());
|
return new AVSetOperation(objects.ToList());
|
||||||
}
|
}
|
||||||
if (previous is AVSetOperation) {
|
if (previous is AVSetOperation setOp) {
|
||||||
var setOp = (AVSetOperation)previous;
|
|
||||||
var oldList = Conversion.To<IList<object>>(setOp.Value);
|
var oldList = Conversion.To<IList<object>>(setOp.Value);
|
||||||
return new AVSetOperation(oldList.Concat(objects).ToList());
|
return new AVSetOperation(oldList.Concat(objects).ToList());
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,7 @@ namespace LeanCloud.Storage.Internal {
|
||||||
if (previous is AVDeleteOperation) {
|
if (previous is AVDeleteOperation) {
|
||||||
return new AVSetOperation(objects.ToList());
|
return new AVSetOperation(objects.ToList());
|
||||||
}
|
}
|
||||||
if (previous is AVSetOperation) {
|
if (previous is AVSetOperation setOp) {
|
||||||
var setOp = (AVSetOperation)previous;
|
|
||||||
var oldList = Conversion.To<IList<object>>(setOp.Value);
|
var oldList = Conversion.To<IList<object>>(setOp.Value);
|
||||||
var result = this.Apply(oldList, null);
|
var result = this.Apply(oldList, null);
|
||||||
return new AVSetOperation(result);
|
return new AVSetOperation(result);
|
||||||
|
|
|
@ -1,37 +1,32 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal
|
namespace LeanCloud.Storage.Internal {
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An operation where a field is deleted from the object.
|
/// An operation where a field is deleted from the object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AVDeleteOperation : IAVFieldOperation
|
public class AVDeleteOperation : IAVFieldOperation {
|
||||||
{
|
|
||||||
internal static readonly object DeleteToken = new object();
|
internal static readonly object DeleteToken = new object();
|
||||||
private static AVDeleteOperation _Instance = new AVDeleteOperation();
|
private static AVDeleteOperation _Instance = new AVDeleteOperation();
|
||||||
public static AVDeleteOperation Instance
|
|
||||||
{
|
public static AVDeleteOperation Instance {
|
||||||
get
|
get {
|
||||||
{
|
|
||||||
return _Instance;
|
return _Instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AVDeleteOperation() { }
|
private AVDeleteOperation() { }
|
||||||
public object Encode()
|
|
||||||
{
|
public object Encode() {
|
||||||
return new Dictionary<string, object> {
|
return new Dictionary<string, object> {
|
||||||
{"__op", "Delete"}
|
{"__op", "Delete"}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous)
|
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous) {
|
||||||
{
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Apply(object oldValue, string key)
|
public object Apply(object oldValue, string key) {
|
||||||
{
|
|
||||||
return DeleteToken;
|
return DeleteToken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,17 +4,14 @@ using System.Collections.Generic;
|
||||||
namespace LeanCloud.Storage.Internal {
|
namespace LeanCloud.Storage.Internal {
|
||||||
public class AVObjectIdComparer : IEqualityComparer<object> {
|
public class AVObjectIdComparer : IEqualityComparer<object> {
|
||||||
bool IEqualityComparer<object>.Equals(object p1, object p2) {
|
bool IEqualityComparer<object>.Equals(object p1, object p2) {
|
||||||
var avObj1 = p1 as AVObject;
|
if (p1 is AVObject avObj1 && p2 is AVObject avObj2) {
|
||||||
var avObj2 = p2 as AVObject;
|
|
||||||
if (avObj1 != null && avObj2 != null) {
|
|
||||||
return object.Equals(avObj1.ObjectId, avObj2.ObjectId);
|
return object.Equals(avObj1.ObjectId, avObj2.ObjectId);
|
||||||
}
|
}
|
||||||
return object.Equals(p1, p2);
|
return object.Equals(p1, p2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetHashCode(object p) {
|
public int GetHashCode(object p) {
|
||||||
var avObject = p as AVObject;
|
if (p is AVObject avObject) {
|
||||||
if (avObject != null) {
|
|
||||||
return avObject.ObjectId.GetHashCode();
|
return avObject.ObjectId.GetHashCode();
|
||||||
}
|
}
|
||||||
return p.GetHashCode();
|
return p.GetHashCode();
|
||||||
|
|
|
@ -2,14 +2,11 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal
|
namespace LeanCloud.Storage.Internal {
|
||||||
{
|
public class AVIncrementOperation : IAVFieldOperation {
|
||||||
public class AVIncrementOperation : IAVFieldOperation
|
|
||||||
{
|
|
||||||
private static readonly IDictionary<Tuple<Type, Type>, Func<object, object, object>> adders;
|
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
|
// 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>> {
|
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(sbyte)), (left, right) => (sbyte)left + (sbyte)right},
|
||||||
|
@ -77,10 +74,8 @@ namespace LeanCloud.Storage.Internal
|
||||||
{new Tuple<Type, Type>(typeof(decimal), typeof(decimal)), (left, right) => (decimal)left + (decimal)right}
|
{new Tuple<Type, Type>(typeof(decimal), typeof(decimal)), (left, right) => (decimal)left + (decimal)right}
|
||||||
};
|
};
|
||||||
// Generate the adders in the other direction
|
// Generate the adders in the other direction
|
||||||
foreach (var pair in adders.Keys.ToList())
|
foreach (var pair in adders.Keys.ToList()) {
|
||||||
{
|
if (pair.Item1.Equals(pair.Item2)) {
|
||||||
if (pair.Item1.Equals(pair.Item2))
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var reversePair = new Tuple<Type, Type>(pair.Item2, pair.Item1);
|
var reversePair = new Tuple<Type, Type>(pair.Item2, pair.Item1);
|
||||||
|
@ -91,13 +86,11 @@ namespace LeanCloud.Storage.Internal
|
||||||
|
|
||||||
private object amount;
|
private object amount;
|
||||||
|
|
||||||
public AVIncrementOperation(object amount)
|
public AVIncrementOperation(object amount) {
|
||||||
{
|
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Encode()
|
public object Encode() {
|
||||||
{
|
|
||||||
return new Dictionary<string, object>
|
return new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
{"__op", "Increment"},
|
{"__op", "Increment"},
|
||||||
|
@ -105,38 +98,30 @@ namespace LeanCloud.Storage.Internal
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static object Add(object obj1, object obj2)
|
private static object Add(object obj1, object obj2) {
|
||||||
{
|
|
||||||
Func<object, object, object> adder;
|
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);
|
return adder(obj1, obj2);
|
||||||
}
|
}
|
||||||
throw new InvalidCastException("Cannot add " + obj1.GetType() + " to " + obj2.GetType());
|
throw new InvalidCastException("Cannot add " + obj1.GetType() + " to " + obj2.GetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous)
|
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous) {
|
||||||
{
|
if (previous == null) {
|
||||||
if (previous == null)
|
|
||||||
{
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
if (previous is AVDeleteOperation)
|
if (previous is AVDeleteOperation) {
|
||||||
{
|
|
||||||
return new AVSetOperation(amount);
|
return new AVSetOperation(amount);
|
||||||
}
|
}
|
||||||
if (previous is AVSetOperation)
|
if (previous is AVSetOperation) {
|
||||||
{
|
|
||||||
var otherAmount = ((AVSetOperation)previous).Value;
|
var otherAmount = ((AVSetOperation)previous).Value;
|
||||||
if (otherAmount is string)
|
if (otherAmount is string) {
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Cannot increment a non-number type.");
|
throw new InvalidOperationException("Cannot increment a non-number type.");
|
||||||
}
|
}
|
||||||
var myAmount = amount;
|
var myAmount = amount;
|
||||||
return new AVSetOperation(Add(otherAmount, myAmount));
|
return new AVSetOperation(Add(otherAmount, myAmount));
|
||||||
}
|
}
|
||||||
if (previous is AVIncrementOperation)
|
if (previous is AVIncrementOperation) {
|
||||||
{
|
|
||||||
object otherAmount = ((AVIncrementOperation)previous).Amount;
|
object otherAmount = ((AVIncrementOperation)previous).Amount;
|
||||||
object myAmount = amount;
|
object myAmount = amount;
|
||||||
return new AVIncrementOperation(Add(otherAmount, myAmount));
|
return new AVIncrementOperation(Add(otherAmount, myAmount));
|
||||||
|
@ -144,10 +129,8 @@ namespace LeanCloud.Storage.Internal
|
||||||
throw new InvalidOperationException("Operation is invalid after previous operation.");
|
throw new InvalidOperationException("Operation is invalid after previous operation.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Apply(object oldValue, string key)
|
public object Apply(object oldValue, string key) {
|
||||||
{
|
if (oldValue is string) {
|
||||||
if (oldValue is string)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Cannot increment a non-number type.");
|
throw new InvalidOperationException("Cannot increment a non-number type.");
|
||||||
}
|
}
|
||||||
object otherAmount = oldValue ?? 0;
|
object otherAmount = oldValue ?? 0;
|
||||||
|
@ -155,10 +138,8 @@ namespace LeanCloud.Storage.Internal
|
||||||
return Add(otherAmount, myAmount);
|
return Add(otherAmount, myAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Amount
|
public object Amount {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,62 +5,49 @@ using System.Linq;
|
||||||
|
|
||||||
using LeanCloud.Utilities;
|
using LeanCloud.Utilities;
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal
|
namespace LeanCloud.Storage.Internal {
|
||||||
{
|
public class AVRemoveOperation : IAVFieldOperation {
|
||||||
public class AVRemoveOperation : IAVFieldOperation
|
|
||||||
{
|
|
||||||
private ReadOnlyCollection<object> objects;
|
private ReadOnlyCollection<object> objects;
|
||||||
public AVRemoveOperation(IEnumerable<object> objects)
|
public AVRemoveOperation(IEnumerable<object> objects) {
|
||||||
{
|
|
||||||
this.objects = new ReadOnlyCollection<object>(objects.Distinct().ToList());
|
this.objects = new ReadOnlyCollection<object>(objects.Distinct().ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Encode()
|
public object Encode() {
|
||||||
{
|
|
||||||
return new Dictionary<string, object> {
|
return new Dictionary<string, object> {
|
||||||
{ "__op", "Remove" },
|
{ "__op", "Remove" },
|
||||||
{ "objects", PointerOrLocalIdEncoder.Instance.Encode(objects) }
|
{ "objects", PointerOrLocalIdEncoder.Instance.Encode(objects) }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous)
|
public IAVFieldOperation MergeWithPrevious(IAVFieldOperation previous) {
|
||||||
{
|
if (previous == null) {
|
||||||
if (previous == null)
|
|
||||||
{
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
if (previous is AVDeleteOperation)
|
if (previous is AVDeleteOperation) {
|
||||||
{
|
|
||||||
return previous;
|
return previous;
|
||||||
}
|
}
|
||||||
if (previous is AVSetOperation)
|
if (previous is AVSetOperation) {
|
||||||
{
|
|
||||||
var setOp = (AVSetOperation)previous;
|
var setOp = (AVSetOperation)previous;
|
||||||
var oldList = Conversion.As<IList<object>>(setOp.Value);
|
var oldList = Conversion.As<IList<object>>(setOp.Value);
|
||||||
return new AVSetOperation(this.Apply(oldList, null));
|
return new AVSetOperation(this.Apply(oldList, null));
|
||||||
}
|
}
|
||||||
if (previous is AVRemoveOperation)
|
if (previous is AVRemoveOperation) {
|
||||||
{
|
|
||||||
var oldOp = (AVRemoveOperation)previous;
|
var oldOp = (AVRemoveOperation)previous;
|
||||||
return new AVRemoveOperation(oldOp.Objects.Concat(objects));
|
return new AVRemoveOperation(oldOp.Objects.Concat(objects));
|
||||||
}
|
}
|
||||||
throw new InvalidOperationException("Operation is invalid after previous operation.");
|
throw new InvalidOperationException("Operation is invalid after previous operation.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Apply(object oldValue, string key)
|
public object Apply(object oldValue, string key) {
|
||||||
{
|
if (oldValue == null) {
|
||||||
if (oldValue == null)
|
|
||||||
{
|
|
||||||
return new List<object>();
|
return new List<object>();
|
||||||
}
|
}
|
||||||
var oldList = Conversion.As<IList<object>>(oldValue);
|
var oldList = Conversion.As<IList<object>>(oldValue);
|
||||||
return oldList.Except(objects, AVFieldOperations.AVObjectComparer).ToList();
|
return oldList.Except(objects, AVFieldOperations.AVObjectComparer).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<object> Objects
|
public IEnumerable<object> Objects {
|
||||||
{
|
get {
|
||||||
get
|
|
||||||
{
|
|
||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,6 @@ using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Linq;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
|
|
||||||
namespace LeanCloud {
|
namespace LeanCloud {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -18,13 +16,6 @@ namespace LeanCloud {
|
||||||
public class AVObject : IEnumerable<KeyValuePair<string, object>>, INotifyPropertyChanged, INotifyPropertyUpdated, INotifyCollectionPropertyUpdated {
|
public class AVObject : IEnumerable<KeyValuePair<string, object>>, INotifyPropertyChanged, INotifyPropertyUpdated, INotifyCollectionPropertyUpdated {
|
||||||
private static readonly string AutoClassName = "_Automatic";
|
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();
|
internal readonly object mutex = new object();
|
||||||
|
|
||||||
private readonly LinkedList<IDictionary<string, IAVFieldOperation>> operationSetQueue =
|
private readonly LinkedList<IDictionary<string, IAVFieldOperation>> operationSetQueue =
|
||||||
|
@ -1008,7 +999,7 @@ string propertyName
|
||||||
// We've just applied a bunch of operations to estimatedData which
|
// We've just applied a bunch of operations to estimatedData which
|
||||||
// may have changed all of its keys. Notify of all keys and properties
|
// may have changed all of its keys. Notify of all keys and properties
|
||||||
// mapped to keys being changed.
|
// mapped to keys being changed.
|
||||||
OnFieldsChanged(changedKeys);
|
OnFieldsChanged(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue