Skip to content

Commit 04a8d5b

Browse files
authored
fix: ParseBase.toJson() failure when date fields are stored as Maps (#1094)
1 parent ffc651d commit 04a8d5b

File tree

2 files changed

+101
-10
lines changed

2 files changed

+101
-10
lines changed

packages/dart/lib/src/objects/parse_base.dart

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,24 @@ abstract class ParseBase {
5252

5353
/// Returns [DateTime] createdAt
5454
DateTime? get createdAt {
55-
if (get<dynamic>(keyVarCreatedAt) is String) {
56-
final String? dateAsString = get<String>(keyVarCreatedAt);
57-
return dateAsString != null ? _parseDateFormat.parse(dateAsString) : null;
58-
} else {
59-
return get<DateTime>(keyVarCreatedAt);
55+
final dynamic value = get<dynamic>(keyVarCreatedAt);
56+
if (value is DateTime) return value;
57+
if (value is String) return _parseDateFormat.parse(value);
58+
if (value is Map<String, dynamic> && value['iso'] is String) {
59+
return _parseDateFormat.parse(value['iso'] as String);
6060
}
61+
return null;
6162
}
6263

6364
/// Returns [DateTime] updatedAt
6465
DateTime? get updatedAt {
65-
if (get<dynamic>(keyVarUpdatedAt) is String) {
66-
final String? dateAsString = get<String>(keyVarUpdatedAt);
67-
return dateAsString != null ? _parseDateFormat.parse(dateAsString) : null;
68-
} else {
69-
return get<DateTime>(keyVarUpdatedAt);
66+
final dynamic value = get<dynamic>(keyVarUpdatedAt);
67+
if (value is DateTime) return value;
68+
if (value is String) return _parseDateFormat.parse(value);
69+
if (value is Map<String, dynamic> && value['iso'] is String) {
70+
return _parseDateFormat.parse(value['iso'] as String);
7071
}
72+
return null;
7173
}
7274

7375
/// Converts object to [String] in JSON format
@@ -140,12 +142,20 @@ abstract class ParseBase {
140142
} else if (key == keyVarCreatedAt) {
141143
if (value is String) {
142144
_getObjectData()[keyVarCreatedAt] = _parseDateFormat.parse(value);
145+
} else if (value is Map<String, dynamic> && value['iso'] is String) {
146+
_getObjectData()[keyVarCreatedAt] = _parseDateFormat.parse(
147+
value['iso'] as String,
148+
);
143149
} else {
144150
_getObjectData()[keyVarCreatedAt] = value;
145151
}
146152
} else if (key == keyVarUpdatedAt) {
147153
if (value is String) {
148154
_getObjectData()[keyVarUpdatedAt] = _parseDateFormat.parse(value);
155+
} else if (value is Map<String, dynamic> && value['iso'] is String) {
156+
_getObjectData()[keyVarUpdatedAt] = _parseDateFormat.parse(
157+
value['iso'] as String,
158+
);
149159
} else {
150160
_getObjectData()[keyVarUpdatedAt] = value;
151161
}

packages/dart/test/src/objects/parse_base_test.dart

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,5 +170,86 @@ void main() {
170170
);
171171
},
172172
);
173+
174+
group('date parsing', () {
175+
test('createdAt and updatedAt should handle Map date format', () {
176+
// Create a parse object and simulate server response with date as Map
177+
final parseObject = ParseObject('TestClass');
178+
179+
// This is what the server sometimes returns - date as Map
180+
parseObject.fromJson({
181+
'objectId': 'testObjectId',
182+
'createdAt': {'__type': 'Date', 'iso': '2023-01-01T00:00:00.000Z'},
183+
'updatedAt': {'__type': 'Date', 'iso': '2023-01-02T00:00:00.000Z'},
184+
});
185+
186+
// These should not throw and return DateTime objects
187+
expect(parseObject.createdAt, isA<DateTime>());
188+
expect(parseObject.updatedAt, isA<DateTime>());
189+
190+
expect(parseObject.createdAt?.year, equals(2023));
191+
expect(parseObject.createdAt?.month, equals(1));
192+
expect(parseObject.createdAt?.day, equals(1));
193+
194+
expect(parseObject.updatedAt?.year, equals(2023));
195+
expect(parseObject.updatedAt?.month, equals(1));
196+
expect(parseObject.updatedAt?.day, equals(2));
197+
});
198+
199+
test('createdAt and updatedAt should handle String date format', () {
200+
final parseObject = ParseObject('TestClass');
201+
202+
parseObject.fromJson({
203+
'objectId': 'testObjectId',
204+
'createdAt': '2023-01-01T00:00:00.000Z',
205+
'updatedAt': '2023-01-02T00:00:00.000Z',
206+
});
207+
208+
expect(parseObject.createdAt, isA<DateTime>());
209+
expect(parseObject.updatedAt, isA<DateTime>());
210+
211+
expect(parseObject.createdAt?.year, equals(2023));
212+
expect(parseObject.updatedAt?.year, equals(2023));
213+
});
214+
215+
test('createdAt and updatedAt should handle DateTime objects', () {
216+
final createdAt = DateTime(2023, 1, 1);
217+
final updatedAt = DateTime(2023, 1, 2);
218+
219+
final parseObject = ParseObject('TestClass');
220+
parseObject.fromJson({
221+
'objectId': 'testObjectId',
222+
'createdAt': createdAt,
223+
'updatedAt': updatedAt,
224+
});
225+
226+
expect(parseObject.createdAt, equals(createdAt));
227+
expect(parseObject.updatedAt, equals(updatedAt));
228+
});
229+
230+
test('toJson should work when date fields are stored as Maps', () {
231+
final parseObject = ParseObject('TestClass');
232+
233+
// Simulate server response with date as Map
234+
parseObject.fromJson({
235+
'objectId': 'testObjectId',
236+
'createdAt': {'__type': 'Date', 'iso': '2023-01-01T00:00:00.000Z'},
237+
'updatedAt': {'__type': 'Date', 'iso': '2023-01-02T00:00:00.000Z'},
238+
});
239+
240+
// toJson should work without throwing
241+
expect(() => parseObject.toJson(full: true), returnsNormally);
242+
expect(() => parseObject.toString(), returnsNormally);
243+
});
244+
245+
test('createdAt and updatedAt should return null for null values', () {
246+
final parseObject = ParseObject('TestClass');
247+
248+
parseObject.fromJson({'objectId': 'testObjectId'});
249+
250+
expect(parseObject.createdAt, isNull);
251+
expect(parseObject.updatedAt, isNull);
252+
});
253+
});
173254
});
174255
}

0 commit comments

Comments
 (0)