Skip to content

Commit bdbc483

Browse files
authoredMar 20, 2023
fix: Unhandled exception when saving a ParseObject but its nested object fails to save (#858)
1 parent 8d17772 commit bdbc483

21 files changed

+220
-38
lines changed
 

‎.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ unlinked_spec.ds
102102

103103
# macOS
104104
**/macos/Flutter/GeneratedPluginRegistrant.swift
105-
**/macos/flutter/ephemeral/
105+
**/macos/Flutter/ephemeral/
106106

107107
# Linux
108108
**/linux/flutter/ephemeral

‎packages/dart/CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## [4.0.1](https://github.com/parse-community/Parse-SDK-Flutter/compare/dart-4.0.0...dart-4.0.1) (2023-03-20)
2+
3+
### Bug Fixes
4+
5+
* Unhandled exception when saving a `ParseObject` but its nested object fails to save ([#858](https://github.com/parse-community/Parse-SDK-Flutter/pull/858))
6+
17
## [4.0.0](https://github.com/parse-community/Parse-SDK-Flutter/compare/dart-3.1.14...dart-4.0.0) (2023-03-07)
28

39
### BREAKING CHANGES

‎packages/dart/lib/src/base/parse_constants.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
part of flutter_parse_sdk;
22

33
// Library
4-
const String keySdkVersion = '4.0.0';
4+
const String keySdkVersion = '4.0.1';
55
const String keyLibraryName = 'Flutter Parse SDK';
66

77
// End Points

‎packages/dart/lib/src/objects/response/parse_response_builder.dart

+18-5
Original file line numberDiff line numberDiff line change
@@ -54,27 +54,40 @@ class _ParseResponseBuilder {
5454
}
5555

5656
/// Handles successful response with results
57-
ParseResponse _handleSuccess<T>(ParseResponse response, dynamic object,
58-
String responseBody, ParseApiRQ type) {
57+
ParseResponse _handleSuccess<T>(
58+
ParseResponse response,
59+
dynamic object,
60+
String responseBody,
61+
ParseApiRQ type,
62+
) {
5963
response.success = true;
6064

6165
final dynamic result = json.decode(responseBody);
6266

6367
if (type == ParseApiRQ.batch) {
6468
final List<dynamic>? list = result;
69+
6570
if (object is List && object.length == list!.length) {
6671
response.count = object.length;
6772
response.results = <dynamic>[];
73+
6874
for (int i = 0; i < object.length; i++) {
6975
final Map<String, dynamic> objectResult = list[i];
76+
7077
if (objectResult.containsKey('success')) {
7178
final T? item = _handleSingleResult<T>(
72-
object[i], objectResult['success'], false);
79+
object[i],
80+
objectResult['success'],
81+
false,
82+
);
83+
7384
response.results!.add(item);
7485
} else {
7586
final ParseError error = ParseError(
76-
code: objectResult[keyCode],
77-
message: objectResult[keyError].toString());
87+
code: objectResult[keyError][keyCode],
88+
message: objectResult[keyError][keyError].toString(),
89+
);
90+
7891
response.results!.add(error);
7992
}
8093
}

‎packages/dart/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: parse_server_sdk
22
description: Dart plugin for Parse Server, (https://parseplatform.org), (https://back4app.com)
3-
version: 4.0.0
3+
version: 4.0.1
44
homepage: https://github.com/parse-community/Parse-SDK-Flutter
55

66
environment:

‎packages/dart/test/src/objects/parse_object/parse_object_array_test.dart

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import 'package:parse_server_sdk/parse_server_sdk.dart';
88
import 'package:test/test.dart';
99

1010
import '../../../parse_query_test.mocks.dart';
11-
import 'parse_object_test.dart';
1211
import '../../../test_utils.dart';
1312

1413
void main() {

‎packages/dart/test/src/objects/parse_object/parse_object_create_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'package:parse_server_sdk/parse_server_sdk.dart';
55
import 'package:test/test.dart';
66

77
import '../../../parse_query_test.mocks.dart';
8-
import 'parse_object_test.dart';
8+
import '../../../test_utils.dart';
99

1010
void main() {
1111
group('create()', () {

‎packages/dart/test/src/objects/parse_object/parse_object_delete_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'package:parse_server_sdk/parse_server_sdk.dart';
55
import 'package:test/test.dart';
66

77
import '../../../parse_query_test.mocks.dart';
8-
import 'parse_object_test.dart';
8+
import '../../../test_utils.dart';
99

1010
void main() {
1111
group('delete()', () {

‎packages/dart/test/src/objects/parse_object/parse_object_distinct_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'package:parse_server_sdk/parse_server_sdk.dart';
55
import 'package:test/test.dart';
66

77
import '../../../parse_query_test.mocks.dart';
8-
import 'parse_object_test.dart';
8+
import '../../../test_utils.dart';
99

1010
void main() {
1111
group('distinct()', () {

‎packages/dart/test/src/objects/parse_object/parse_object_fetch_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'package:parse_server_sdk/parse_server_sdk.dart';
55
import 'package:test/test.dart';
66

77
import '../../../parse_query_test.mocks.dart';
8-
import 'parse_object_test.dart';
8+
import '../../../test_utils.dart';
99

1010
void main() {
1111
group('fetch()', () {

‎packages/dart/test/src/objects/parse_object/parse_object_get_all_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'package:parse_server_sdk/parse_server_sdk.dart';
55
import 'package:test/test.dart';
66

77
import '../../../parse_query_test.mocks.dart';
8-
import 'parse_object_test.dart';
8+
import '../../../test_utils.dart';
99

1010
void main() {
1111
group('getAll()', () {

‎packages/dart/test/src/objects/parse_object/parse_object_get_object_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'package:parse_server_sdk/parse_server_sdk.dart';
55
import 'package:test/test.dart';
66

77
import '../../../parse_query_test.mocks.dart';
8-
import 'parse_object_test.dart';
8+
import '../../../test_utils.dart';
99

1010
void main() {
1111
group('getObject()', () {

‎packages/dart/test/src/objects/parse_object/parse_object_increment_decrement_test.dart

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import 'package:parse_server_sdk/parse_server_sdk.dart';
77
import 'package:test/test.dart';
88

99
import '../../../parse_query_test.mocks.dart';
10-
import 'parse_object_test.dart';
1110
import '../../../test_utils.dart';
1211

1312
void main() {

‎packages/dart/test/src/objects/parse_object/parse_object_query_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'package:parse_server_sdk/parse_server_sdk.dart';
55
import 'package:test/test.dart';
66

77
import '../../../parse_query_test.mocks.dart';
8-
import 'parse_object_test.dart';
8+
import '../../../test_utils.dart';
99

1010
void main() {
1111
group('query()', () {

‎packages/dart/test/src/objects/parse_object/parse_object_relation_test.dart

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import 'package:collection/collection.dart';
22
import 'package:parse_server_sdk/parse_server_sdk.dart';
33
import 'package:test/test.dart';
44

5-
import 'parse_object_test.dart';
65
import '../../../test_utils.dart';
76

87
void main() {

‎packages/dart/test/src/objects/parse_object/parse_object_save_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'package:parse_server_sdk/parse_server_sdk.dart';
55
import 'package:test/test.dart';
66

77
import '../../../parse_query_test.mocks.dart';
8-
import 'parse_object_test.dart';
8+
import '../../../test_utils.dart';
99

1010
void main() {
1111
group('save()', () {

‎packages/dart/test/src/objects/parse_object/parse_object_test.dart

+1-17
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,7 @@ import 'package:mockito/annotations.dart';
22
import 'package:parse_server_sdk/parse_server_sdk.dart';
33
import 'package:test/test.dart';
44

5-
const serverUrl = 'https://example.com';
6-
7-
Future<void> initializeParse() async {
8-
await Parse().initialize(
9-
'appId',
10-
serverUrl,
11-
debug: true,
12-
// to prevent automatic detection
13-
fileDirectory: 'someDirectory',
14-
// to prevent automatic detection
15-
appName: 'appName',
16-
// to prevent automatic detection
17-
appPackageName: 'somePackageName',
18-
// to prevent automatic detection
19-
appVersion: 'someAppVersion',
20-
);
21-
}
5+
import '../../../test_utils.dart';
226

237
@GenerateMocks([ParseClient])
248
void main() {

‎packages/dart/test/src/objects/parse_object/parse_object_unset_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'package:parse_server_sdk/parse_server_sdk.dart';
55
import 'package:test/test.dart';
66

77
import '../../../parse_query_test.mocks.dart';
8-
import 'parse_object_test.dart';
8+
import '../../../test_utils.dart';
99

1010
void main() {
1111
group('unset()', () {

‎packages/dart/test/src/objects/parse_object/parse_object_update_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'package:parse_server_sdk/parse_server_sdk.dart';
55
import 'package:test/test.dart';
66

77
import '../../../parse_query_test.mocks.dart';
8-
import 'parse_object_test.dart';
8+
import '../../../test_utils.dart';
99

1010
void main() {
1111
group('update()', () {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import 'dart:convert';
2+
3+
import 'package:parse_server_sdk/parse_server_sdk.dart';
4+
import 'package:test/test.dart';
5+
6+
import '../../../test_utils.dart';
7+
8+
void main() {
9+
group('handleResponse()', () {
10+
setUp(() async {
11+
await initializeParse();
12+
});
13+
14+
group('when batch', () {
15+
test(
16+
'should return a ParseResponse holds a list of created/updated ParseObjects',
17+
() {
18+
// arrange
19+
final object1 = ParseObject("object1");
20+
21+
final object2 = ParseObject("object2")..objectId = "GYfSRRRXbL";
22+
23+
final objectsToBatch = [object1, object2];
24+
25+
const object1ResultFromServerObjectId = "YAfSAWwXbL";
26+
const object1ResultFromServerCreatedAt = "2023-03-19T00:20:37.187Z";
27+
28+
const object2ResultFromServerUpdatedAt = "2023-03-19T00:20:37.187Z";
29+
30+
final resultFromServerForBatch = json.encode(
31+
[
32+
{
33+
"success": {
34+
keyVarObjectId: object1ResultFromServerObjectId,
35+
keyVarCreatedAt: object1ResultFromServerCreatedAt,
36+
}
37+
},
38+
{
39+
"success": {
40+
keyVarUpdatedAt: object2ResultFromServerUpdatedAt,
41+
}
42+
}
43+
],
44+
);
45+
46+
final result = ParseNetworkResponse(
47+
data: resultFromServerForBatch,
48+
statusCode: 200,
49+
);
50+
51+
// act
52+
final response = handleResponse(
53+
objectsToBatch,
54+
result,
55+
ParseApiRQ.batch,
56+
true,
57+
'test_batch',
58+
);
59+
60+
// assert
61+
expect(response.success, isTrue);
62+
63+
expect(response.count, equals(2));
64+
65+
expect(response.error, isNull);
66+
67+
final resultsObjectsList = List<ParseObject>.from(response.results!);
68+
69+
expect(resultsObjectsList.length, equals(2));
70+
71+
final firstObject = resultsObjectsList[0];
72+
final secondObject = resultsObjectsList[1];
73+
74+
expect(firstObject.objectId, equals(object1ResultFromServerObjectId));
75+
76+
expect(
77+
firstObject.createdAt!.toIso8601String(),
78+
equals(object1ResultFromServerCreatedAt),
79+
);
80+
81+
expect(
82+
secondObject.updatedAt!.toIso8601String(),
83+
equals(object2ResultFromServerUpdatedAt),
84+
);
85+
});
86+
87+
test(
88+
'should return a ParseResponse holds a list of ParseObject and ParseError',
89+
() {
90+
// arrange
91+
final object1 = ParseObject("object1");
92+
final object2 = ParseObject("object2");
93+
94+
final objectsToBatch = [object1, object2];
95+
96+
const object1ResultFromServerObjectId = "YAfSAWwXbL";
97+
const object1ResultFromServerCreatedAt = "2023-03-19T00:20:37.187Z";
98+
99+
final resultFromServerForBatch = json.encode(
100+
[
101+
{
102+
"success": {
103+
keyVarObjectId: object1ResultFromServerObjectId,
104+
keyVarCreatedAt: object1ResultFromServerCreatedAt,
105+
}
106+
},
107+
// error while saving the second object
108+
{
109+
"error": {
110+
"code": ParseError.internalServerError,
111+
"error": "internal server error",
112+
}
113+
}
114+
],
115+
);
116+
117+
final result = ParseNetworkResponse(
118+
data: resultFromServerForBatch,
119+
statusCode: 200,
120+
);
121+
122+
// act
123+
final response = handleResponse(
124+
objectsToBatch,
125+
result,
126+
ParseApiRQ.batch,
127+
true,
128+
'test_batch',
129+
);
130+
131+
// assert
132+
expect(response.success, isTrue);
133+
134+
expect(response.count, equals(2));
135+
136+
expect(response.error, isNull);
137+
138+
expect(response.results, isNotNull);
139+
140+
final resultsList = response.results!;
141+
142+
expect(resultsList.length, equals(2));
143+
144+
final ParseObject firstObject = resultsList[0];
145+
146+
final ParseError secondObjectError = resultsList[1];
147+
148+
expect(firstObject.objectId, equals(object1ResultFromServerObjectId));
149+
150+
expect(
151+
firstObject.createdAt!.toIso8601String(),
152+
equals(object1ResultFromServerCreatedAt),
153+
);
154+
155+
expect(
156+
secondObjectError.code,
157+
equals(ParseError.internalServerError),
158+
);
159+
160+
expect(object2.objectId, isNull);
161+
});
162+
});
163+
});
164+
}

‎packages/dart/test/test_utils.dart

+18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
11
import 'package:parse_server_sdk/parse_server_sdk.dart';
22
import 'package:test/test.dart';
33

4+
const serverUrl = 'https://example.com';
5+
6+
Future<void> initializeParse() async {
7+
await Parse().initialize(
8+
'appId',
9+
serverUrl,
10+
debug: true,
11+
// to prevent automatic detection
12+
fileDirectory: 'someDirectory',
13+
// to prevent automatic detection
14+
appName: 'appName',
15+
// to prevent automatic detection
16+
appPackageName: 'somePackageName',
17+
// to prevent automatic detection
18+
appVersion: 'someAppVersion',
19+
);
20+
}
21+
422
/// If an unmergeable operation [testingOn] is attempted after an operation,
523
/// it should result in an exception being thrown. in context of the same key.
624
///

0 commit comments

Comments
 (0)
Please sign in to comment.