From 9af640adc69ea400f8f281e1134fcda776e641a2 Mon Sep 17 00:00:00 2001 From: Yvan Brunel <41630728+YBTopaz8@users.noreply.github.com> Date: Sun, 2 Feb 2025 16:51:53 -0500 Subject: [PATCH] fix: `ParseObject` Relations not working (#407) --- Parse.Tests/EncoderTests.cs | 7 - Parse.Tests/RelationTests.cs | 347 +++++++++++++++++- .../Infrastructure/IJsonConvertible.cs | 3 +- .../Control/ParseAddOperation.cs | 2 +- .../Control/ParseAddUniqueOperation.cs | 2 +- .../Control/ParseDeleteOperation.cs | 2 +- .../Control/ParseIncrementOperation.cs | 2 +- .../Control/ParseRelationOperation.cs | 58 ++- .../Control/ParseRemoveOperation.cs | 2 +- .../Control/ParseSetOperation.cs | 4 +- .../Execution/ParseCommandRunner.cs | 12 +- .../Execution/UniversalWebClient.cs | 4 +- .../Configuration/ParseConfiguration.cs | 2 +- .../ParseCurrentConfigurationController.cs | 5 +- Parse/Platform/Files/ParseFile.cs | 2 +- Parse/Platform/Location/ParseGeoPoint.cs | 2 +- Parse/Platform/Relations/ParseRelation.cs | 2 +- Parse/Platform/Security/ParseACL.cs | 2 +- 18 files changed, 396 insertions(+), 64 deletions(-) diff --git a/Parse.Tests/EncoderTests.cs b/Parse.Tests/EncoderTests.cs index 6cd103a3..ea390dc9 100644 --- a/Parse.Tests/EncoderTests.cs +++ b/Parse.Tests/EncoderTests.cs @@ -76,13 +76,6 @@ public void TestEncodeBytes() Assert.AreEqual(Convert.ToBase64String(new byte[] { 1, 2, 3, 4 }), value["base64"]); } - [TestMethod] - public void TestEncodeParseObjectWithNoObjectsEncoder() - { - ParseObject obj = new ParseObject("Corgi"); - - Assert.ThrowsException(() => NoObjectsEncoder.Instance.Encode(obj, Client)); - } [TestMethod] public void TestEncodeParseObjectWithPointerOrLocalIdEncoder() diff --git a/Parse.Tests/RelationTests.cs b/Parse.Tests/RelationTests.cs index c1a362cf..c550e582 100644 --- a/Parse.Tests/RelationTests.cs +++ b/Parse.Tests/RelationTests.cs @@ -1,13 +1,84 @@ +using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Parse.Abstractions.Infrastructure.Control; +using Parse.Abstractions.Infrastructure; using Parse.Abstractions.Internal; +using Parse.Abstractions.Platform.Objects; using Parse.Infrastructure; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using Parse.Platform.Objects; +using System.Threading; +using Parse.Abstractions.Platform.Users; namespace Parse.Tests; [TestClass] public class RelationTests { + [ParseClassName("TestObject")] + private class TestObject : ParseObject { } + + [ParseClassName("Friend")] + private class Friend : ParseObject { } + + private ParseClient Client { get; set; } + + [TestInitialize] + public void SetUp() + { + // Initialize the client and ensure the instance is set + Client = new ParseClient(new ServerConnectionData { Test = true }); + Client.Publicize(); + + // Register the test classes + Client.RegisterSubclass(typeof(TestObject)); + Client.RegisterSubclass(typeof(Friend)); + Client.RegisterSubclass(typeof(ParseUser)); + Client.RegisterSubclass(typeof(ParseSession)); + Client.RegisterSubclass(typeof(ParseUser)); + + // **--- Mocking Setup ---** + var hub = new MutableServiceHub(); // Use MutableServiceHub for mocking + var mockUserController = new Mock(); + var mockObjectController = new Mock(); + + // **Mock SignUpAsync for ParseUser:** + mockUserController + .Setup(controller => controller.SignUpAsync( + It.IsAny(), + It.IsAny>(), + It.IsAny(), + It.IsAny())) + .ReturnsAsync(new MutableObjectState { ObjectId = "some0neTol4v4" }); // Predefined ObjectId for User + + // **Mock SaveAsync for ParseObject (Friend objects):** + int objectSaveCounter = 1; // Counter for Friend ObjectIds + mockObjectController + .Setup(controller => controller.SaveAsync( + It.IsAny(), + It.IsAny>(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .ReturnsAsync(() => // Use a lambda to generate different ObjectIds for each Friend + { + return new MutableObjectState { ObjectId = $"mockFriendObjectId{objectSaveCounter++}" }; + }); + + // **Inject Mocks into ServiceHub:** + hub.UserController = mockUserController.Object; + hub.ObjectController = mockObjectController.Object; + + } + + [TestCleanup] + public void TearDown() => (Client.Services as ServiceHub).Reset(); + [TestMethod] public void TestRelationQuery() { @@ -24,4 +95,278 @@ public void TestRelationQuery() Assert.AreEqual("child", encoded["redirectClassNameForKey"]); } -} \ No newline at end of file + + [TestMethod] + [Description("Tests AddRelationToUserAsync throws exception when user is null")] // Mock difficulty: 1 + public async Task AddRelationToUserAsync_ThrowsException_WhenUserIsNull() + { + + var relatedObjects = new List + { + new ParseObject("Friend", Client.Services) { ["name"] = "Friend1" } + }; + + await Assert.ThrowsExceptionAsync(() => UserManagement.AddRelationToUserAsync(null, "friends", relatedObjects)); + + } + [TestMethod] + [Description("Tests AddRelationToUserAsync throws exception when relationfield is null")] // Mock difficulty: 1 + public async Task AddRelationToUserAsync_ThrowsException_WhenRelationFieldIsNull() + { + var user = new ParseUser() { Username = "TestUser", Password = "TestPass", Services = Client.Services }; + await user.SignUpAsync(); + var relatedObjects = new List + { + new ParseObject("Friend", Client.Services) { ["name"] = "Friend1" } + }; + await Assert.ThrowsExceptionAsync(() => UserManagement.AddRelationToUserAsync(user, null, relatedObjects)); + } + + [TestMethod] + [Description("Tests UpdateUserRelationAsync throws exception when user is null")] // Mock difficulty: 1 + public async Task UpdateUserRelationAsync_ThrowsException_WhenUserIsNull() + { + var relatedObjectsToAdd = new List + { + new ParseObject("Friend", Client.Services) { ["name"] = "Friend1" } + }; + var relatedObjectsToRemove = new List + { + new ParseObject("Friend", Client.Services) { ["name"] = "Friend2" } + }; + + + await Assert.ThrowsExceptionAsync(() => UserManagement.UpdateUserRelationAsync(null, "friends", relatedObjectsToAdd, relatedObjectsToRemove)); + } + [TestMethod] + [Description("Tests UpdateUserRelationAsync throws exception when relationfield is null")] // Mock difficulty: 1 + public async Task UpdateUserRelationAsync_ThrowsException_WhenRelationFieldIsNull() + { + var user = new ParseUser() { Username = "TestUser", Password = "TestPass", Services = Client.Services }; + await user.SignUpAsync(); + + var relatedObjectsToAdd = new List + { + new ParseObject("Friend", Client.Services) { ["name"] = "Friend1" } + }; + var relatedObjectsToRemove = new List + { + new ParseObject("Friend", Client.Services) { ["name"] = "Friend2" } + }; + + + await Assert.ThrowsExceptionAsync(() => UserManagement.UpdateUserRelationAsync(user, null, relatedObjectsToAdd, relatedObjectsToRemove)); + } + [TestMethod] + [Description("Tests DeleteUserRelationAsync throws exception when user is null")] // Mock difficulty: 1 + public async Task DeleteUserRelationAsync_ThrowsException_WhenUserIsNull() + { + await Assert.ThrowsExceptionAsync(() => UserManagement.DeleteUserRelationAsync(null, "friends")); + } + [TestMethod] + [Description("Tests DeleteUserRelationAsync throws exception when relationfield is null")] // Mock difficulty: 1 + public async Task DeleteUserRelationAsync_ThrowsException_WhenRelationFieldIsNull() + { + var user = new ParseUser() { Username = "TestUser", Password = "TestPass", Services = Client.Services }; + await user.SignUpAsync(); + + await Assert.ThrowsExceptionAsync(() => UserManagement.DeleteUserRelationAsync(user, null)); + } + [TestMethod] + [Description("Tests GetUserRelationsAsync throws exception when user is null")] // Mock difficulty: 1 + public async Task GetUserRelationsAsync_ThrowsException_WhenUserIsNull() + { + await Assert.ThrowsExceptionAsync(() => UserManagement.GetUserRelationsAsync(null, "friends")); + } + [TestMethod] + [Description("Tests GetUserRelationsAsync throws exception when relationfield is null")] // Mock difficulty: 1 + public async Task GetUserRelationsAsync_ThrowsException_WhenRelationFieldIsNull() + { + var user = new ParseUser() { Username = "TestUser", Password = "TestPass", Services = Client.Services }; + await user.SignUpAsync(); + + await Assert.ThrowsExceptionAsync(() => UserManagement.GetUserRelationsAsync(user, null)); + } + + + + [TestMethod] + [Description("Tests that AddRelationToUserAsync throws when a related object is unsaved")] + public async Task AddRelationToUserAsync_ThrowsException_WhenRelatedObjectIsUnsaved() + { + // Arrange: Create and sign up a test user. + var user = new ParseUser() { Username = "TestUser", Password = "TestPass", Services = Client.Services }; + await user.SignUpAsync(); + + // Create an unsaved Friend object (do NOT call SaveAsync). + var unsavedFriend = new ParseObject("Friend", Client.Services) { ["name"] = "UnsavedFriend" }; + var relatedObjects = new List { unsavedFriend }; + + // Act & Assert: Expect an exception when trying to add an unsaved object. + await Assert.ThrowsExceptionAsync(() => + UserManagement.AddRelationToUserAsync(user, "friends", relatedObjects)); + } + + + +} + +public static class UserManagement +{ + public static async Task AddRelationToUserAsync(ParseUser user, string relationField, IList relatedObjects) + { + if (user == null) + { + throw new ArgumentNullException(nameof(user), "User must not be null."); + } + + if (string.IsNullOrEmpty(relationField)) + { + throw new ArgumentException("Relation field must not be null or empty.", nameof(relationField)); + } + + if (relatedObjects == null || relatedObjects.Count == 0) + { + Debug.WriteLine("No objects provided to add to the relation."); + return; + } + + var relation = user.GetRelation(relationField); + + foreach (var obj in relatedObjects) + { + relation.Add(obj); + } + + await user.SaveAsync(); + Debug.WriteLine($"Added {relatedObjects.Count} objects to the '{relationField}' relation for user '{user.Username}'."); + } + public static async Task UpdateUserRelationAsync(ParseUser user, string relationField, IList toAdd, IList toRemove) + { + if (user == null) + { + throw new ArgumentNullException(nameof(user), "User must not be null."); + } + + if (string.IsNullOrEmpty(relationField)) + { + throw new ArgumentException("Relation field must not be null or empty.", nameof(relationField)); + } + + var relation = user.GetRelation(relationField); + + // Add objects to the relation + if (toAdd != null && toAdd.Count > 0) + { + foreach (var obj in toAdd) + { + relation.Add(obj); + } + Debug.WriteLine($"Added {toAdd.Count} objects to the '{relationField}' relation."); + } + + // Remove objects from the relation + if (toRemove != null && toRemove.Count > 0) + { + + foreach (var obj in toRemove) + { + relation.Remove(obj); + } + Debug.WriteLine($"Removed {toRemove.Count} objects from the '{relationField}' relation."); + } + + await user.SaveAsync(); + } + public static async Task DeleteUserRelationAsync(ParseUser user, string relationField) + { + if (user == null) + { + throw new ArgumentNullException(nameof(user), "User must not be null."); + } + + if (string.IsNullOrEmpty(relationField)) + { + throw new ArgumentException("Relation field must not be null or empty.", nameof(relationField)); + } + + var relation = user.GetRelation(relationField); + var relatedObjects = await relation.Query.FindAsync(); + + + foreach (var obj in relatedObjects) + { + relation.Remove(obj); + } + + await user.SaveAsync(); + Debug.WriteLine($"Removed all objects from the '{relationField}' relation for user '{user.Username}'."); + } + public static async Task ManageUserRelationsAsync(ParseClient client) + { + // Get the current user + var user = await ParseClient.Instance.GetCurrentUser(); + + if (user == null) + { + Debug.WriteLine("No user is currently logged in."); + return; + } + + const string relationField = "friends"; // Example relation field name + + // Create related objects to add + var relatedObjectsToAdd = new List + { + new ParseObject("Friend", client.Services) { ["name"] = "Alice" }, + new ParseObject("Friend", client.Services) { ["name"] = "Bob" } + }; + + // Save related objects to the server before adding to the relation + foreach (var obj in relatedObjectsToAdd) + { + await obj.SaveAsync(); + } + + // Add objects to the relation + await AddRelationToUserAsync(user, relationField, relatedObjectsToAdd); + + // Query the relation + var relatedObjects = await GetUserRelationsAsync(user, relationField); + + // Update the relation (add and remove objects) + var relatedObjectsToRemove = new List { relatedObjects[0] }; // Remove the first related object + var newObjectsToAdd = new List + { + new ParseObject("Friend", client.Services) { ["name"] = "Charlie" } + }; + + foreach (var obj in newObjectsToAdd) + { + await obj.SaveAsync(); + } + + await UpdateUserRelationAsync(user, relationField, newObjectsToAdd, relatedObjectsToRemove); + + } + public static async Task> GetUserRelationsAsync(ParseUser user, string relationField) + { + if (user == null) + { + throw new ArgumentNullException(nameof(user), "User must not be null."); + } + + if (string.IsNullOrEmpty(relationField)) + { + throw new ArgumentException("Relation field must not be null or empty.", nameof(relationField)); + } + + var relation = user.GetRelation(relationField); + + var results = await relation.Query.FindAsync(); + Debug.WriteLine($"Retrieved {results.Count()} objects from the '{relationField}' relation for user '{user.Username}'."); + return results.ToList(); + } + +} + diff --git a/Parse/Abstractions/Infrastructure/IJsonConvertible.cs b/Parse/Abstractions/Infrastructure/IJsonConvertible.cs index 954f626e..e5d0db0a 100644 --- a/Parse/Abstractions/Infrastructure/IJsonConvertible.cs +++ b/Parse/Abstractions/Infrastructure/IJsonConvertible.cs @@ -11,5 +11,6 @@ public interface IJsonConvertible /// Converts the object to a data structure that can be converted to JSON. /// /// An object to be JSONified. - IDictionary ConvertToJSON(IServiceHub serviceHub=default); + + object ConvertToJSON(IServiceHub serviceHub=default); } diff --git a/Parse/Infrastructure/Control/ParseAddOperation.cs b/Parse/Infrastructure/Control/ParseAddOperation.cs index 164503b5..7f62a142 100644 --- a/Parse/Infrastructure/Control/ParseAddOperation.cs +++ b/Parse/Infrastructure/Control/ParseAddOperation.cs @@ -49,7 +49,7 @@ public object Apply(object oldValue, string key) return result; } - public IDictionary ConvertToJSON(IServiceHub serviceHub = default) + public object ConvertToJSON(IServiceHub serviceHub = default) { // Convert the data into JSON-compatible structures var encodedObjects = Data.Select(EncodeForParse).ToList(); diff --git a/Parse/Infrastructure/Control/ParseAddUniqueOperation.cs b/Parse/Infrastructure/Control/ParseAddUniqueOperation.cs index 3c6cad30..a63c9133 100644 --- a/Parse/Infrastructure/Control/ParseAddUniqueOperation.cs +++ b/Parse/Infrastructure/Control/ParseAddUniqueOperation.cs @@ -55,7 +55,7 @@ public object Apply(object oldValue, string key) return result; } - public IDictionary ConvertToJSON(IServiceHub serviceHub = default) + public object ConvertToJSON(IServiceHub serviceHub = default) { // Converts the data into JSON-compatible structures var encodedObjects = Data.Select(EncodeForParse).ToList(); diff --git a/Parse/Infrastructure/Control/ParseDeleteOperation.cs b/Parse/Infrastructure/Control/ParseDeleteOperation.cs index c074e616..56e12649 100644 --- a/Parse/Infrastructure/Control/ParseDeleteOperation.cs +++ b/Parse/Infrastructure/Control/ParseDeleteOperation.cs @@ -18,7 +18,7 @@ public class ParseDeleteOperation : IParseFieldOperation private ParseDeleteOperation() { } // Replaced Encode with ConvertToJSON - public IDictionary ConvertToJSON(IServiceHub serviceHub = default) + public object ConvertToJSON(IServiceHub serviceHub = default) { return new Dictionary { diff --git a/Parse/Infrastructure/Control/ParseIncrementOperation.cs b/Parse/Infrastructure/Control/ParseIncrementOperation.cs index 036ef5ae..f2271e87 100644 --- a/Parse/Infrastructure/Control/ParseIncrementOperation.cs +++ b/Parse/Infrastructure/Control/ParseIncrementOperation.cs @@ -97,7 +97,7 @@ static ParseIncrementOperation() public ParseIncrementOperation(object amount) => Amount = amount; // Updated Encode to ConvertToJSON - public IDictionary ConvertToJSON(IServiceHub serviceHub = default) + public object ConvertToJSON(IServiceHub serviceHub = default) { // Updated to produce a JSON-compatible structure return new Dictionary diff --git a/Parse/Infrastructure/Control/ParseRelationOperation.cs b/Parse/Infrastructure/Control/ParseRelationOperation.cs index 7960bfbd..c489a592 100644 --- a/Parse/Infrastructure/Control/ParseRelationOperation.cs +++ b/Parse/Infrastructure/Control/ParseRelationOperation.cs @@ -36,33 +36,6 @@ public ParseRelationOperation(IParseObjectClassController classController, IEnum Removals = new ReadOnlyCollection(GetIdsFromObjects(removes).ToList()); } - public object Encode(IServiceHub serviceHub) - { - List additions = Additions.Select(id => PointerOrLocalIdEncoder.Instance.Encode(ClassController.CreateObjectWithoutData(TargetClassName, id, serviceHub), serviceHub)).ToList(), removals = Removals.Select(id => PointerOrLocalIdEncoder.Instance.Encode(ClassController.CreateObjectWithoutData(TargetClassName, id, serviceHub), serviceHub)).ToList(); - - Dictionary addition = additions.Count == 0 ? default : new Dictionary - { - ["__op"] = "AddRelation", - ["objects"] = additions - }; - - Dictionary removal = removals.Count == 0 ? default : new Dictionary - { - ["__op"] = "RemoveRelation", - ["objects"] = removals - }; - - if (addition is { } && removal is { }) - { - return new Dictionary - { - ["__op"] = "Batch", - ["ops"] = new[] { addition, removal } - }; - } - return addition ?? removal; - } - public IParseFieldOperation MergeWithPrevious(IParseFieldOperation previous) { return previous switch @@ -88,8 +61,8 @@ public object Apply(object oldValue, string key) } public string TargetClassName { get; } - - public object Value => throw new NotImplementedException(); + + public object Value => Additions.ToList(); IEnumerable GetIdsFromObjects(IEnumerable objects) { @@ -109,5 +82,30 @@ IEnumerable GetIdsFromObjects(IEnumerable objects) return objects.Select(entity => entity.ObjectId).Distinct(); } - public IDictionary ConvertToJSON(IServiceHub serviceHub = null) => throw new NotImplementedException(); + public object ConvertToJSON(IServiceHub serviceHub = null) + { + List additions = Additions.Select(id => PointerOrLocalIdEncoder.Instance.Encode(ClassController.CreateObjectWithoutData(TargetClassName, id, serviceHub), serviceHub)).ToList(), removals = Removals.Select(id => PointerOrLocalIdEncoder.Instance.Encode(ClassController.CreateObjectWithoutData(TargetClassName, id, serviceHub), serviceHub)).ToList(); + + Dictionary addition = additions.Count == 0 ? default : new Dictionary + { + ["__op"] = "AddRelation", + ["objects"] = additions + }; + + Dictionary removal = removals.Count == 0 ? default : new Dictionary + { + ["__op"] = "RemoveRelation", + ["objects"] = removals + }; + + if (addition is { } && removal is { }) + { + return new Dictionary + { + ["__op"] = "Batch", + ["ops"] = new[] { addition, removal } + }; + } + return addition ?? removal; + } } diff --git a/Parse/Infrastructure/Control/ParseRemoveOperation.cs b/Parse/Infrastructure/Control/ParseRemoveOperation.cs index 899c6002..0f280cd8 100644 --- a/Parse/Infrastructure/Control/ParseRemoveOperation.cs +++ b/Parse/Infrastructure/Control/ParseRemoveOperation.cs @@ -39,7 +39,7 @@ public object Apply(object oldValue, string key) : new List { }; // Return empty list if no previous value } - public IDictionary ConvertToJSON(IServiceHub serviceHub = default) + public object ConvertToJSON(IServiceHub serviceHub = default) { // Convert data to a JSON-compatible structure var encodedObjects = Data.Select(obj => PointerOrLocalIdEncoder.Instance.Encode(obj, serviceHub)).ToList(); diff --git a/Parse/Infrastructure/Control/ParseSetOperation.cs b/Parse/Infrastructure/Control/ParseSetOperation.cs index 4a15b367..d6c1eae1 100644 --- a/Parse/Infrastructure/Control/ParseSetOperation.cs +++ b/Parse/Infrastructure/Control/ParseSetOperation.cs @@ -14,7 +14,7 @@ public ParseSetOperation(object value) } // Replace Encode with ConvertToJSON - public IDictionary ConvertToJSON(IServiceHub serviceHub = default) + public object ConvertToJSON(IServiceHub serviceHub = default) { if (serviceHub == null) { @@ -26,7 +26,7 @@ public IDictionary ConvertToJSON(IServiceHub serviceHub = defaul // For simple values, return them directly (avoid unnecessary __op) if (Value != null && (Value.GetType().IsPrimitive || Value is string)) { - return new Dictionary { ["value"] = Value }; + return Value ; } // If the encoded value is a dictionary, return it directly diff --git a/Parse/Infrastructure/Execution/ParseCommandRunner.cs b/Parse/Infrastructure/Execution/ParseCommandRunner.cs index 630ed81a..5f937332 100644 --- a/Parse/Infrastructure/Execution/ParseCommandRunner.cs +++ b/Parse/Infrastructure/Execution/ParseCommandRunner.cs @@ -73,16 +73,8 @@ public async Task>> RunCommand var statusCode = response.Item1; var content = response.Item2; var responseCode = (int) statusCode; - - - if (responseCode == 200) - { - - } - else if (responseCode == 201) - { - } - else if (responseCode == 404) + + if (responseCode == 404) { throw new ParseFailureException(ParseFailureException.ErrorCode.ERROR404, "Error 404"); } diff --git a/Parse/Infrastructure/Execution/UniversalWebClient.cs b/Parse/Infrastructure/Execution/UniversalWebClient.cs index 656af000..21f682cd 100644 --- a/Parse/Infrastructure/Execution/UniversalWebClient.cs +++ b/Parse/Infrastructure/Execution/UniversalWebClient.cs @@ -50,7 +50,7 @@ public async Task> ExecuteAsync( HttpRequestMessage message = new HttpRequestMessage(new HttpMethod(httpRequest.Method), httpRequest.Target); Stream data = httpRequest.Data; - if (data != null || httpRequest.Method.Equals("POST", StringComparison.OrdinalIgnoreCase)) + if (data != null || httpRequest.Method.Equals("POST", StringComparison.OrdinalIgnoreCase)) { message.Content = new StreamContent(data ?? new MemoryStream(new byte[0])); } @@ -128,4 +128,4 @@ public async Task> ExecuteAsync( return new Tuple(response.StatusCode, resultString); } -} +} \ No newline at end of file diff --git a/Parse/Platform/Configuration/ParseConfiguration.cs b/Parse/Platform/Configuration/ParseConfiguration.cs index 7cc76950..356bfd1e 100644 --- a/Parse/Platform/Configuration/ParseConfiguration.cs +++ b/Parse/Platform/Configuration/ParseConfiguration.cs @@ -106,7 +106,7 @@ public bool TryGetValue(string key, out T result) /// The value for the key. virtual public object this[string key] => Properties[key]; - public IDictionary ConvertToJSON(IServiceHub serviceHub = default) + public object ConvertToJSON(IServiceHub serviceHub = default) { return new Dictionary { diff --git a/Parse/Platform/Configuration/ParseCurrentConfigurationController.cs b/Parse/Platform/Configuration/ParseCurrentConfigurationController.cs index 70717e75..8ece93d6 100644 --- a/Parse/Platform/Configuration/ParseCurrentConfigurationController.cs +++ b/Parse/Platform/Configuration/ParseCurrentConfigurationController.cs @@ -2,6 +2,7 @@ using Parse.Abstractions.Infrastructure.Data; using Parse.Abstractions.Infrastructure; using Parse.Abstractions.Platform.Configuration; +using System.Collections.Generic; namespace Parse.Platform.Configuration; @@ -42,7 +43,9 @@ public async Task SetCurrentConfigAsync(ParseConfiguration target) _currentConfiguration = target; var data = await _storageController.LoadAsync(); - await data.AddAsync(CurrentConfigurationKey, ParseClient.SerializeJsonString(((IJsonConvertible) target).ConvertToJSON())); + var jsonData = ((IJsonConvertible) target).ConvertToJSON() as IDictionary; + + await data.AddAsync(CurrentConfigurationKey, ParseClient.SerializeJsonString(jsonData)); } public async Task ClearCurrentConfigAsync() diff --git a/Parse/Platform/Files/ParseFile.cs b/Parse/Platform/Files/ParseFile.cs index 3559512c..f86a113f 100644 --- a/Parse/Platform/Files/ParseFile.cs +++ b/Parse/Platform/Files/ParseFile.cs @@ -165,7 +165,7 @@ public ParseFile(string name, Stream data, string mimeType = null) #endregion - public IDictionary ConvertToJSON(IServiceHub serviceHub = default) + public object ConvertToJSON(IServiceHub serviceHub = default) { if (IsDirty) { diff --git a/Parse/Platform/Location/ParseGeoPoint.cs b/Parse/Platform/Location/ParseGeoPoint.cs index e9aa5ead..18216f84 100644 --- a/Parse/Platform/Location/ParseGeoPoint.cs +++ b/Parse/Platform/Location/ParseGeoPoint.cs @@ -91,7 +91,7 @@ public ParseGeoDistance DistanceTo(ParseGeoPoint point) return new ParseGeoDistance(2 * Math.Asin(Math.Sqrt(a))); } - public IDictionary ConvertToJSON(IServiceHub serviceHub = default) + public object ConvertToJSON(IServiceHub serviceHub = default) { return new Dictionary { {"__type", "GeoPoint"}, diff --git a/Parse/Platform/Relations/ParseRelation.cs b/Parse/Platform/Relations/ParseRelation.cs index b0d65ee2..aca8f0d7 100644 --- a/Parse/Platform/Relations/ParseRelation.cs +++ b/Parse/Platform/Relations/ParseRelation.cs @@ -70,7 +70,7 @@ internal void Remove(ParseObject entity) TargetClassName = change.TargetClassName; } - public IDictionary ConvertToJSON(IServiceHub serviceHub = default) + public object ConvertToJSON(IServiceHub serviceHub = default) { return new Dictionary { diff --git a/Parse/Platform/Security/ParseACL.cs b/Parse/Platform/Security/ParseACL.cs index 30d3376e..3154a51a 100644 --- a/Parse/Platform/Security/ParseACL.cs +++ b/Parse/Platform/Security/ParseACL.cs @@ -105,7 +105,7 @@ public ParseACL(ParseUser owner) SetWriteAccess(owner, true); } - public IDictionary ConvertToJSON(IServiceHub serviceHub = default) + public object ConvertToJSON(IServiceHub serviceHub = default) { Dictionary result = new Dictionary(); foreach (string user in readers.Union(writers))