* ObjectControllerTests.cs: chore: 格式化

* AVObject.cs:
* AVAddOperation.cs:
* AVSetOperation.cs:
* AVDeleteOperation.cs:
* AVFieldOperations.cs:
* AVRemoveOperation.cs:
* IAVFieldOperation.cs:
* AVRelationOperation.cs:
* AVAddUniqueOperation.cs:
* AVIncrementOperation.cs:
oneRain 2019-09-19 17:59:16 +08:00
parent afebf78444
commit d118935f21
11 changed files with 400 additions and 439 deletions

View File

@ -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);
} }
} }

View File

@ -6,15 +6,16 @@ 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());
} }
public object Encode() { public object Encode() {
return new Dictionary<string, object> { return new Dictionary<string, object> {
{"__op", "Add"}, { "__op", "Add" },
{"objects", PointerOrLocalIdEncoder.Instance.Encode(objects)} { "objects", PointerOrLocalIdEncoder.Instance.Encode(objects) }
}; };
} }
@ -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());
} }

View File

@ -13,8 +13,8 @@ namespace LeanCloud.Storage.Internal {
public object Encode() { public object Encode() {
return new Dictionary<string, object> { return new Dictionary<string, object> {
{"__op", "AddUnique"}, { "__op", "AddUnique" },
{"objects", PointerOrLocalIdEncoder.Instance.Encode(objects)} { "objects", PointerOrLocalIdEncoder.Instance.Encode(objects) }
}; };
} }
@ -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);

View File

@ -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;
} }
} }

View File

@ -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();

View File

@ -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;
} }
} }

View File

@ -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;
} }
} }

View File

@ -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);
} }
} }