From d351cafcb667679b85a58afe3488312aa9f22e12 Mon Sep 17 00:00:00 2001 From: moorelwang Date: Wed, 7 Aug 2019 15:17:04 +0800 Subject: [PATCH 1/3] The method of setAdd, setRemove, setAddAll, setRemoveAll, Increment, Decrement, AddUnique, AddRelation, RemoveRelation can be merged between the same operation and some other operation. Implementation method reference iOS SDK. I do this by Implementing a tool class in "parse_merge.dart" and calling the "mergeWithPrevious" Method in the set method which implemented in parse_base.dart. --- lib/parse_server_sdk.dart | 8 +- lib/src/objects/parse_base.dart | 13 +- lib/src/objects/parse_merge.dart | 251 +++++++++++++++++++++++++++++++ 3 files changed, 265 insertions(+), 7 deletions(-) create mode 100644 lib/src/objects/parse_merge.dart diff --git a/lib/parse_server_sdk.dart b/lib/parse_server_sdk.dart index 0a276e93e..671c7af85 100644 --- a/lib/parse_server_sdk.dart +++ b/lib/parse_server_sdk.dart @@ -92,6 +92,8 @@ part 'src/utils/parse_utils.dart'; part 'src/utils/parse_login_helpers.dart'; +part 'src/objects/parse_merge.dart'; + class Parse { ParseCoreData data; bool _hasBeenInitialized = false; @@ -116,8 +118,8 @@ class Parse { String masterKey, String sessionId, bool autoSendSessionId, - SecurityContext securityContext, - CoreStore coreStore}) async { + SecurityContext securityContext, + CoreStore coreStore}) async { final String url = removeTrailingSlash(serverUrl); await ParseCoreData.init(appId, url, @@ -147,7 +149,7 @@ class Parse { final ParseHTTPClient _client = client ?? ParseHTTPClient( sendSessionId: - sendSessionIdByDefault ?? ParseCoreData().autoSendSessionId, + sendSessionIdByDefault ?? ParseCoreData().autoSendSessionId, securityContext: ParseCoreData().securityContext); const String className = 'parseBase'; diff --git a/lib/src/objects/parse_base.dart b/lib/src/objects/parse_base.dart index 8331ee2db..5218fb508 100644 --- a/lib/src/objects/parse_base.dart +++ b/lib/src/objects/parse_base.dart @@ -191,13 +191,18 @@ abstract class ParseBase { if (_getObjectData()[key] == value) { return; } - if (forceUpdate) { - _getObjectData()[key] = value; - } + /*if (!forceUpdate) { + if (value is Map) { + value = mergeWithPrevious(_getObjectData()[key], value); + } + }*/ + // value = mergeWithPrevious(_unsavedChanges[key], value); + _getObjectData()[key] = + ParseMergeTool().mergeWithPrevious(_unsavedChanges[key], value); } else { _getObjectData()[key] = value; } - _unsavedChanges[key] = value; + _unsavedChanges[key] = _getObjectData()[key]; } } diff --git a/lib/src/objects/parse_merge.dart b/lib/src/objects/parse_merge.dart new file mode 100644 index 000000000..f800655de --- /dev/null +++ b/lib/src/objects/parse_merge.dart @@ -0,0 +1,251 @@ +part of flutter_parse_sdk; + +class ParseMergeTool { + // merge method + dynamic mergeWithPrevious(dynamic previous, dynamic values) { + if (previous == null) { + return values; + } + String previousAction = 'Set'; + if (previous is Map) { + previousAction = previous['__op']; + } + if (values is Map) { + if (values['__op'] == 'Add') { + values = _mergeWithPreviousAdd(previousAction, previous, values); + } else if (values['__op'] == 'Remove') { + values = _mergeWithPreviousRemove(previousAction, previous, values); + } else if (values['__op'] == 'Increment') { + values = _mergeWithPreviousIncrement(previousAction, previous, values); + } else if (values['__op'] == 'AddUnique') { + values = _mergeWithPreviousAddUnique(previousAction, previous, values); + } else if (values['__op'] == 'AddRelation') { + values = + _mergeWithPreviousAddRelation(previousAction, previous, values); + } else if (values['__op'] == 'RemoveRelation') { + values = + _mergeWithPreviousRemoveRelation(previousAction, previous, values); + } + } + return values; + } + + // Add operation Merge + dynamic _mergeWithPreviousAdd( + String previousAction, dynamic previous, dynamic values) { + if (previousAction == 'Set') { + if (previous is List) { + return List.from(previous)..addAll(values['objects']); + } else { + throw 'Unable to add an item to a non-array.'; + } + } + if (previousAction == 'Add') { + if (values['objects'].length == 1) { + previous['objects'].add(values['objects'].first); + } else { + previous['objects'].add(values['objects']); + } + values = previous; + } + if (previousAction == 'Increment') { + throw 'Add operation is invalid after Increment operation'; + } + if (previousAction == 'Remove') { + throw 'Add operation is invalid after Remove operation'; + } + if (previousAction == 'AddUnique') { + throw 'Add operation is invalid after AddUnique operation'; + } + if (previousAction == 'AddRelation') { + throw 'Add operation is invalid after AddRelation operation'; + } + if (previousAction == 'RemoveRelation') { + throw 'Add operation is invalid after RemoveRelation operation'; + } + return values; + } + + // Remove operation Merge + dynamic _mergeWithPreviousRemove( + String previousAction, dynamic previous, dynamic values) { + if (previousAction == 'Set') { + return previous; + } + if (previousAction == 'Remove') { + if (values['objects'].length == 1) { + previous['objects'].add(values['objects'].first); + } else { + previous['objects'].add(values['objects']); + } + values = previous; + } + if (previousAction == 'Increment') { + throw 'Remove operation is invalid after Increment operation'; + } + if (previousAction == 'Add') { + throw 'Remove operation is invalid after Add operation'; + } + if (previousAction == 'AddUnique') { + throw 'Remove operation is invalid after AddUnique operation'; + } + if (previousAction == 'AddRelation') { + throw 'Remove operation is invalid after AddRelation operation'; + } + if (previousAction == 'RemoveRelation') { + throw 'Remove operation is invalid after RemoveRelation operation'; + } + return values; + } + + // Increment operation Merge + dynamic _mergeWithPreviousIncrement( + String previousAction, dynamic previous, dynamic values) { + if (previousAction == 'Set') { + if (previous is num) { + values['amount'] += previous; + } else { + throw 'Invalid Operation'; + } + } + if (previousAction == 'Increment') { + values['amount'] += previous['amount']; + } + if (previousAction == 'Add') { + throw 'Increment operation is invalid after Add operation'; + } + if (previousAction == 'Remove') { + throw 'Increment operation is invalid after Remove operation'; + } + if (previousAction == 'AddUnique') { + throw 'Increment operation is invalid after AddUnique operation'; + } + if (previousAction == 'AddRelation') { + throw 'Increment operation is invalid after AddRelation operation'; + } + if (previousAction == 'RemoveRelation') { + throw 'Increment operation is invalid after RemoveRelation operation'; + } + return values; + } + + // AddUnique operation Merge + dynamic _mergeWithPreviousAddUnique( + String previousAction, dynamic previous, dynamic values) { + if (previousAction == 'Set') { + if (previous is List) { + return _applyToValueAddUnique(previous, values['objects']); + } else { + throw 'Unable to add an item to a non-array.'; + } + } + if (previousAction == 'AddUnique') { + values['objects'] = + _applyToValueAddUnique(previous['objects'], values['objects']); + return values; + } + if (previousAction == 'Add') { + throw 'AddUnique operation is invalid after Add operation'; + } + if (previousAction == 'Remove') { + throw 'AddUnique operation is invalid after Reomve operation'; + } + if (previousAction == 'Increment') { + throw 'AddUnique operation is invalid after Increment operation'; + } + if (previousAction == 'AddRelation') { + throw 'AddUnique operation is invalid after AddRelation operation'; + } + if (previousAction == 'RemoveRelation') { + throw 'AddUnique operation is invalid after RemoveRelation operation'; + } + return values; + } + + // AddRelation operation Merge + dynamic _mergeWithPreviousAddRelation( + String previousAction, dynamic previous, dynamic values) { + if (previousAction == 'AddRelation') { + if (values['objects'].length == 1) { + previous['objects'].add(values['objects'].first); + } else { + previous['objects'].add(values['objects']); + } + values = previous; + } + if (previousAction == 'Set') { + throw 'AddRelation operation is invalid after Set operation.'; + } + if (previousAction == 'Increment') { + throw 'AddRelation operation is invalid after Increment operation'; + } + if (previousAction == 'Add') { + throw 'AddRelation operation is invalid after Add operation'; + } + if (previousAction == 'Remove') { + throw 'AddRelation operation is invalid after Remove operation'; + } + if (previousAction == 'AddUnique') { + throw 'AddRelation operation is invalid after AddUnique operation'; + } + if (previousAction == 'RemoveRelation') { + throw 'AddRelation operation is invalid after RemoveRelation operation'; + } + return values; + } + + // RemoveRelation operation Merge + dynamic _mergeWithPreviousRemoveRelation( + String previousAction, dynamic previous, dynamic values) { + if (previousAction == 'RemoveRelation') { + if (values['objects'].length == 1) { + previous['objects'].add(values['objects'].first); + } else { + previous['objects'].add(values['objects']); + } + values = previous; + } + if (previousAction == 'Set') { + throw 'RemoveRelation operation is invalid after Set operation.'; + } + if (previousAction == 'Increment') { + throw 'RemoveRelation operation is invalid after Increment operation'; + } + if (previousAction == 'Add') { + throw 'RemoveRelation operation is invalid after Add operation'; + } + if (previousAction == 'Remove') { + throw 'RemoveRelation operation is invalid after Remove operation'; + } + if (previousAction == 'AddUnique') { + throw 'RemoveRelation operation is invalid after AddUnique operation'; + } + if (previousAction == 'AddRelation') { + throw 'RemoveRelation operation is invalid after AddRelation operation'; + } + return values; + } + + // service for AddUnique method + dynamic _applyToValueAddUnique(dynamic oldValue, dynamic newValue) { + for (var objectToAdd in newValue) { + if (objectToAdd is ParseObject && objectToAdd.objectId != null) { + var index = 0; + for (var objc in oldValue) { + if (objc is ParseObject && objc.objectId == objectToAdd.objectId) { + oldValue[index] = objectToAdd; + break; + } + index += 1; + } + if (index == oldValue.length) { + oldValue.add(objectToAdd); + } + } else if (!oldValue.contains(objectToAdd)) { + oldValue.add(objectToAdd); + } + } + print(oldValue); + return oldValue; + } +} From d2b8cf3bcaa85d6fe931c56beee3cdbe0c822da6 Mon Sep 17 00:00:00 2001 From: moorelwang Date: Wed, 7 Aug 2019 16:02:54 +0800 Subject: [PATCH 2/3] remove the commented out code. --- lib/src/objects/parse_base.dart | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/src/objects/parse_base.dart b/lib/src/objects/parse_base.dart index 5218fb508..01e1535bb 100644 --- a/lib/src/objects/parse_base.dart +++ b/lib/src/objects/parse_base.dart @@ -191,12 +191,6 @@ abstract class ParseBase { if (_getObjectData()[key] == value) { return; } - /*if (!forceUpdate) { - if (value is Map) { - value = mergeWithPrevious(_getObjectData()[key], value); - } - }*/ - // value = mergeWithPrevious(_unsavedChanges[key], value); _getObjectData()[key] = ParseMergeTool().mergeWithPrevious(_unsavedChanges[key], value); } else { From 5a65098c0b0e322e8933436af782895c77f1e3e6 Mon Sep 17 00:00:00 2001 From: moorelwang Date: Fri, 9 Aug 2019 19:17:54 +0800 Subject: [PATCH 3/3] Fix OrderBy multiple columns #241 --- lib/src/network/parse_query.dart | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/src/network/parse_query.dart b/lib/src/network/parse_query.dart index 4c8b06266..2ac995bc9 100644 --- a/lib/src/network/parse_query.dart +++ b/lib/src/network/parse_query.dart @@ -32,7 +32,11 @@ class QueryBuilder { /// [String] order will be the column of the table that the results are /// ordered by void orderByAscending(String order) { - limiters['order'] = order; + if (limiters.containsKey('order')) { + limiters['order'] += ',$order'; + } else { + limiters['order'] = order; + } } /// Sorts the results descending order. @@ -40,7 +44,11 @@ class QueryBuilder { /// [String] order will be the column of the table that the results are /// ordered by void orderByDescending(String order) { - limiters['order'] = '-$order'; + if (limiters.containsKey('order')) { + limiters['order'] += ',-$order'; + } else { + limiters['order'] = '-$order'; + } } /// Define which keys in an object to return.