diff --git a/Storage/Storage/Internal/AVCorePlugins.cs b/Storage/Storage/Internal/AVCorePlugins.cs index 3f7b9f4..3ae2718 100644 --- a/Storage/Storage/Internal/AVCorePlugins.cs +++ b/Storage/Storage/Internal/AVCorePlugins.cs @@ -22,7 +22,6 @@ namespace LeanCloud.Storage.Internal { private AVCloudCodeController cloudCodeController; private AVFileController fileController; - private AVObjectController objectController; private AVQueryController queryController; private AVUserController userController; private ObjectSubclassingController subclassingController; @@ -42,7 +41,6 @@ namespace LeanCloud.Storage.Internal { CloudCodeController = null; FileController = null; - ObjectController = null; UserController = null; SubclassingController = null; @@ -108,20 +106,6 @@ namespace LeanCloud.Storage.Internal { } } - public AVObjectController ObjectController { - get { - lock (mutex) { - objectController = objectController ?? new AVObjectController(); - return objectController; - } - } - set { - lock (mutex) { - objectController = value; - } - } - } - public AVQueryController QueryController { get { lock (mutex) { diff --git a/Storage/Storage/Internal/Encoding/PointerOrLocalIdEncoder.cs b/Storage/Storage/Internal/Encoding/PointerOrLocalIdEncoder.cs index 2394cf7..ba50743 100644 --- a/Storage/Storage/Internal/Encoding/PointerOrLocalIdEncoder.cs +++ b/Storage/Storage/Internal/Encoding/PointerOrLocalIdEncoder.cs @@ -46,24 +46,21 @@ namespace LeanCloud.Storage.Internal var operations = value.GetCurrentOperations(); var operationJSON = AVObject.ToJSONObjectForSaving(operations); var objectJSON = value.ToDictionary(kvp => kvp.Key, kvp => PointerOrLocalIdEncoder.Instance.Encode(kvp.Value)); - foreach (var kvp in operationJSON) - { + foreach (var kvp in operationJSON) { objectJSON[kvp.Key] = kvp.Value; } - if (value.CreatedAt.HasValue) - { - objectJSON["createdAt"] = value.CreatedAt.Value.ToString(AVClient.DateFormatStrings.First(), - CultureInfo.InvariantCulture); + if (value.CreatedAt.HasValue) { + objectJSON["createdAt"] = value.CreatedAt.Value.ToString(AVClient.DateFormatStrings.First(), CultureInfo.InvariantCulture); } - if (value.UpdatedAt.HasValue) - { - objectJSON["updatedAt"] = value.UpdatedAt.Value.ToString(AVClient.DateFormatStrings.First(), - CultureInfo.InvariantCulture); + if (value.UpdatedAt.HasValue) { + objectJSON["updatedAt"] = value.UpdatedAt.Value.ToString(AVClient.DateFormatStrings.First(), CultureInfo.InvariantCulture); } - if(!string.IsNullOrEmpty(value.ObjectId)) - { + if(!string.IsNullOrEmpty(value.ObjectId)) { objectJSON["objectId"] = value.ObjectId; } + if (value.ACL != null) { + objectJSON["acl"] = Encode(value.ACL); + } objectJSON["className"] = value.ClassName; objectJSON["__type"] = "Object"; return objectJSON; diff --git a/Storage/Storage/Internal/Object/Controller/AVObjectController.cs b/Storage/Storage/Internal/Object/Controller/AVObjectController.cs deleted file mode 100644 index e2ebe8a..0000000 --- a/Storage/Storage/Internal/Object/Controller/AVObjectController.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.Linq; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using System.Net.Http; - -namespace LeanCloud.Storage.Internal { - public class AVObjectController { - public async Task FetchAsync(IObjectState state, - IDictionary queryString, - CancellationToken cancellationToken) { - var command = new AVCommand { - Path = $"classes/{Uri.EscapeDataString(state.ClassName)}/{Uri.EscapeDataString(state.ObjectId)}?{AVClient.BuildQueryString(queryString)}", - Method = HttpMethod.Get - }; - var data = await AVPlugins.Instance.CommandRunner.RunCommandAsync>(command, cancellationToken); - var objState = AVObjectCoder.Instance.Decode(data.Item2, AVDecoder.Instance); - return objState; - } - - public async Task SaveAsync(IObjectState state, - IDictionary operations, - bool fetchWhenSave, - AVQuery query, - CancellationToken cancellationToken) { - var objectJSON = AVObject.ToJSONObjectForSaving(operations); - - var command = new AVCommand { - Path = state.ObjectId == null ? $"classes/{Uri.EscapeDataString(state.ClassName)}" : $"classes/{Uri.EscapeDataString(state.ClassName)}/{state.ObjectId}", - Method = state.ObjectId == null ? HttpMethod.Post : HttpMethod.Put, - Content = objectJSON - }; - Dictionary args = new Dictionary(); - if (fetchWhenSave) { - args.Add("fetchWhenSave", fetchWhenSave); - } - // 查询条件 - if (query != null) { - args.Add("where", query.BuildWhere()); - } - if (args.Count > 0) { - string encode = AVClient.BuildQueryString(args); - command.Path = $"{command.Path}?{encode}"; - } - var data = await AVPlugins.Instance.CommandRunner.RunCommandAsync>(command, cancellationToken); - var serverState = AVObjectCoder.Instance.Decode(data.Item2, AVDecoder.Instance); - serverState = serverState.MutatedClone(mutableClone => { - mutableClone.IsNew = data.Item1 == System.Net.HttpStatusCode.Created; - }); - return serverState; - } - - public async Task> SaveAllAsync(IList states, - IList> operationsList, - CancellationToken cancellationToken) { - var requests = states - .Zip(operationsList, (item, ops) => new AVCommand { - Path = item.ObjectId == null ? $"classes/{Uri.EscapeDataString(item.ClassName)}" : $"classes/{Uri.EscapeDataString(item.ClassName)}/{Uri.EscapeDataString(item.ObjectId)}", - Method = item.ObjectId == null ? HttpMethod.Post : HttpMethod.Put, - Content = AVObject.ToJSONObjectForSaving(ops) - }) - .ToList(); - IList list = new List(); - var result = await AVPlugins.Instance.CommandRunner.ExecuteBatchRequests(requests, cancellationToken); - foreach (var data in result) { - if (data.TryGetValue("success", out object val)) { - IObjectState obj = AVObjectCoder.Instance.Decode(val as IDictionary, AVDecoder.Instance); - list.Add(obj); - } - } - return list; - } - - public async Task> SaveAllAsync(IList avObjects, CancellationToken cancellationToken) { - List commandList = new List(); - foreach (AVObject avObj in avObjects) { - AVCommand command = new AVCommand { - Path = avObj.ObjectId == null ? $"classes/{Uri.EscapeDataString(avObj.ClassName)}" : $"classes/{Uri.EscapeDataString(avObj.ClassName)}/{Uri.EscapeDataString(avObj.ObjectId)}", - Method = avObj.ObjectId == null ? HttpMethod.Post : HttpMethod.Put, - Content = AVObject.ToJSONObjectForSaving(avObj.operationDict) - }; - commandList.Add(command); - } - IList list = new List(); - var result = await AVPlugins.Instance.CommandRunner.ExecuteBatchRequests(commandList, cancellationToken); - foreach (var data in result) { - if (data.TryGetValue("success", out object val)) { - IObjectState obj = AVObjectCoder.Instance.Decode(val as IDictionary, AVDecoder.Instance); - list.Add(obj); - } - } - return list; - } - } -} diff --git a/Storage/Storage/Internal/Object/State/IObjectState.cs b/Storage/Storage/Internal/Object/State/IObjectState.cs index ab7b074..a22a4e3 100644 --- a/Storage/Storage/Internal/Object/State/IObjectState.cs +++ b/Storage/Storage/Internal/Object/State/IObjectState.cs @@ -1,13 +1,11 @@ using System; using System.Collections.Generic; -namespace LeanCloud.Storage.Internal -{ - public interface IObjectState : IEnumerable> - { - bool IsNew { get; } +namespace LeanCloud.Storage.Internal { + public interface IObjectState : IEnumerable> { string ClassName { get; } string ObjectId { get; } + AVACL ACL { get; set; } DateTime? UpdatedAt { get; } DateTime? CreatedAt { get; } object this[string key] { get; } diff --git a/Storage/Storage/Internal/Object/State/MutableObjectState.cs b/Storage/Storage/Internal/Object/State/MutableObjectState.cs index 6682307..c141d95 100644 --- a/Storage/Storage/Internal/Object/State/MutableObjectState.cs +++ b/Storage/Storage/Internal/Object/State/MutableObjectState.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; namespace LeanCloud.Storage.Internal { public class MutableObjectState : IObjectState { - public bool IsNew { get; set; } public string ClassName { get; set; } public string ObjectId { get; set; } public AVACL ACL { get; set; } @@ -38,13 +37,12 @@ namespace LeanCloud.Storage.Internal { } public void Apply(IObjectState other) { - IsNew = other.IsNew; if (other.ObjectId != null) { ObjectId = other.ObjectId; } - //if (other.ACL != null) { - - //} + if (other.ACL != null) { + ACL = other.ACL; + } if (other.UpdatedAt != null) { UpdatedAt = other.UpdatedAt; } @@ -65,7 +63,6 @@ namespace LeanCloud.Storage.Internal { protected virtual MutableObjectState MutableClone() { return new MutableObjectState { - IsNew = IsNew, ClassName = ClassName, ObjectId = ObjectId, CreatedAt = CreatedAt, diff --git a/Storage/Storage/Internal/User/Controller/AVUserController.cs b/Storage/Storage/Internal/User/Controller/AVUserController.cs index 2853051..eab422f 100644 --- a/Storage/Storage/Internal/User/Controller/AVUserController.cs +++ b/Storage/Storage/Internal/User/Controller/AVUserController.cs @@ -14,9 +14,6 @@ namespace LeanCloud.Storage.Internal { }; var ret = await AVPlugins.Instance.CommandRunner.RunCommandAsync>(command); var serverState = AVObjectCoder.Instance.Decode(ret.Item2, AVDecoder.Instance); - serverState = serverState.MutatedClone(mutableClone => { - mutableClone.IsNew = true; - }); return serverState; } @@ -37,9 +34,6 @@ namespace LeanCloud.Storage.Internal { }; var ret = await AVPlugins.Instance.CommandRunner.RunCommandAsync>(command); var serverState = AVObjectCoder.Instance.Decode(ret.Item2, AVDecoder.Instance); - serverState = serverState.MutatedClone(mutableClone => { - mutableClone.IsNew = ret.Item1 == System.Net.HttpStatusCode.Created; - }); return serverState; } @@ -57,9 +51,6 @@ namespace LeanCloud.Storage.Internal { }; var ret = await AVPlugins.Instance.CommandRunner.RunCommandAsync>(command); var serverState = AVObjectCoder.Instance.Decode(ret.Item2, AVDecoder.Instance); - serverState = serverState.MutatedClone(mutableClone => { - mutableClone.IsNew = ret.Item1 == System.Net.HttpStatusCode.Created; - }); return serverState; } @@ -94,9 +85,6 @@ namespace LeanCloud.Storage.Internal { }; var ret = await AVPlugins.Instance.CommandRunner.RunCommandAsync>(command); var serverState = AVObjectCoder.Instance.Decode(ret.Item2, AVDecoder.Instance); - serverState = serverState.MutatedClone(mutableClone => { - mutableClone.IsNew = ret.Item1 == System.Net.HttpStatusCode.Created; - }); return serverState; } diff --git a/Storage/Storage/Public/AVObject.cs b/Storage/Storage/Public/AVObject.cs index 7813a1d..364a415 100644 --- a/Storage/Storage/Public/AVObject.cs +++ b/Storage/Storage/Public/AVObject.cs @@ -35,16 +35,16 @@ namespace LeanCloud { } } + internal AVACL acl; + [AVFieldName("ACL")] public AVACL ACL { + // 设置 IsDirty get { - return GetProperty(null, "ACL"); - } - set { + return acl; + } set { + acl = value; IsDirty = true; - MutateState(mutableClone => { - mutableClone.ACL = value; - }); } } @@ -89,12 +89,6 @@ namespace LeanCloud { } } - internal static AVObjectController ObjectController { - get { - return AVPlugins.Instance.ObjectController; - } - } - internal static ObjectSubclassingController SubclassingController { get { return AVPlugins.Instance.SubclassingController; @@ -261,6 +255,17 @@ namespace LeanCloud { RebuildEstimatedData(); } + internal IDictionary ToJSONObject() { + IDictionary result = new Dictionary(); + if (ACL != null) { + result["ACL"] = PointerOrLocalIdEncoder.Instance.Encode(ACL); + } + foreach (KeyValuePair kv in operationDict) { + result[kv.Key] = PointerOrLocalIdEncoder.Instance.Encode(kv.Value); + } + return result; + } + public static IDictionary ToJSONObjectForSaving(IDictionary operations) { var result = new Dictionary(); foreach (var pair in operations) { @@ -296,8 +301,29 @@ namespace LeanCloud { } Stack batches = BatchObjects(new List { this }, false); await SaveBatches(batches, cancellationToken); - IObjectState result = await ObjectController.SaveAsync(state, operationDict, fetchWhenSave, query, cancellationToken); - HandleSave(result); + + IDictionary objectJSON = ToJSONObject(); + var command = new AVCommand { + Path = ObjectId == null ? $"classes/{Uri.EscapeDataString(ClassName)}" : + $"classes/{Uri.EscapeDataString(ClassName)}/{ObjectId}", + Method = ObjectId == null ? HttpMethod.Post : HttpMethod.Put, + Content = objectJSON + }; + Dictionary args = new Dictionary(); + if (fetchWhenSave) { + args.Add("fetchWhenSave", fetchWhenSave); + } + // 查询条件 + if (query != null) { + args.Add("where", query.BuildWhere()); + } + if (args.Count > 0) { + string encode = AVClient.BuildQueryString(args); + command.Path = $"{command.Path}?{encode}"; + } + var data = await AVPlugins.Instance.CommandRunner.RunCommandAsync>(command, cancellationToken); + IObjectState serverState = AVObjectCoder.Instance.Decode(data.Item2, AVDecoder.Instance); + HandleSave(serverState); } public static async Task SaveAllAsync(IEnumerable objects, CancellationToken cancellationToken = default) @@ -315,10 +341,28 @@ namespace LeanCloud { while (batches.Any()) { Batch batch = batches.Pop(); IList dirtyObjects = batch.Objects.Where(o => o.IsDirty).ToList(); - var serverStates = await ObjectController.SaveAllAsync(dirtyObjects, cancellationToken); + + List commandList = new List(); + foreach (AVObject avObj in dirtyObjects) { + AVCommand command = new AVCommand { + Path = avObj.ObjectId == null ? $"classes/{Uri.EscapeDataString(avObj.ClassName)}" : + $"classes/{Uri.EscapeDataString(avObj.ClassName)}/{Uri.EscapeDataString(avObj.ObjectId)}", + Method = avObj.ObjectId == null ? HttpMethod.Post : HttpMethod.Put, + Content = avObj.ToJSONObject() + }; + commandList.Add(command); + } + IList list = new List(); + var result = await AVPlugins.Instance.CommandRunner.ExecuteBatchRequests(commandList, cancellationToken); + foreach (var data in result) { + if (data.TryGetValue("success", out object val)) { + IObjectState obj = AVObjectCoder.Instance.Decode(val as IDictionary, AVDecoder.Instance); + list.Add(obj); + } + } try { - foreach (var pair in dirtyObjects.Zip(serverStates, (item, state) => new { item, state })) { + foreach (var pair in dirtyObjects.Zip(list, (item, state) => new { item, state })) { pair.item.HandleSave(pair.state); } } catch (Exception e) { @@ -334,7 +378,14 @@ namespace LeanCloud { if (queryString == null) { queryString = new Dictionary(); } - IObjectState objectState = await ObjectController.FetchAsync(state, queryString, cancellationToken); + + var command = new AVCommand { + Path = $"classes/{Uri.EscapeDataString(state.ClassName)}/{Uri.EscapeDataString(state.ObjectId)}?{AVClient.BuildQueryString(queryString)}", + Method = HttpMethod.Get + }; + var data = await AVPlugins.Instance.CommandRunner.RunCommandAsync>(command, cancellationToken); + IObjectState objectState = AVObjectCoder.Instance.Decode(data.Item2, AVDecoder.Instance); + HandleFetchResult(objectState); return this; }