* 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,8 @@ using LeanCloud.Utilities;
|
|||
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
public class AVAddOperation : IAVFieldOperation {
|
||||
private ReadOnlyCollection<object> objects;
|
||||
private readonly ReadOnlyCollection<object> objects;
|
||||
|
||||
public AVAddOperation(IEnumerable<object> objects) {
|
||||
this.objects = new ReadOnlyCollection<object>(objects.ToList());
|
||||
}
|
||||
|
@ -25,8 +26,7 @@ namespace LeanCloud.Storage.Internal {
|
|||
if (previous is AVDeleteOperation) {
|
||||
return new AVSetOperation(objects.ToList());
|
||||
}
|
||||
if (previous is AVSetOperation) {
|
||||
var setOp = (AVSetOperation)previous;
|
||||
if (previous is AVSetOperation setOp) {
|
||||
var oldList = Conversion.To<IList<object>>(setOp.Value);
|
||||
return new AVSetOperation(oldList.Concat(objects).ToList());
|
||||
}
|
||||
|
|
|
@ -25,8 +25,7 @@ namespace LeanCloud.Storage.Internal {
|
|||
if (previous is AVDeleteOperation) {
|
||||
return new AVSetOperation(objects.ToList());
|
||||
}
|
||||
if (previous is AVSetOperation) {
|
||||
var setOp = (AVSetOperation)previous;
|
||||
if (previous is AVSetOperation setOp) {
|
||||
var oldList = Conversion.To<IList<object>>(setOp.Value);
|
||||
var result = this.Apply(oldList, null);
|
||||
return new AVSetOperation(result);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,17 +4,14 @@ 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) {
|
||||
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) {
|
||||
var avObject = p as AVObject;
|
||||
if (avObject != null) {
|
||||
if (p is AVObject avObject) {
|
||||
return avObject.ObjectId.GetHashCode();
|
||||
}
|
||||
return p.GetHashCode();
|
||||
|
|
|
@ -2,14 +2,11 @@
|
|||
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},
|
||||
|
@ -77,10 +74,8 @@ namespace LeanCloud.Storage.Internal
|
|||
{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,13 +86,11 @@ namespace LeanCloud.Storage.Internal
|
|||
|
||||
private object amount;
|
||||
|
||||
public AVIncrementOperation(object amount)
|
||||
{
|
||||
public AVIncrementOperation(object amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public object Encode()
|
||||
{
|
||||
public object Encode() {
|
||||
return new Dictionary<string, object>
|
||||
{
|
||||
{"__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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 =
|
||||
|
@ -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