Skip to content

Commit f107ff5

Browse files
authored
RegisterSubClass and smaler changes (#368)
* added subclass handler * integraded subclass handler * added constructor for QueryBuilder using registered SubClasses * subclass handler optimizations * Convenience changes * Convenience change * sembast CoreStore on macos * Fix: ParseUser updated on server but not locally This should be a fix for: #364 and #256 * Update README.md * Update README.md
1 parent 057f2b3 commit f107ff5

10 files changed

+160
-43
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,24 @@ class DietPlan extends ParseObject implements ParseCloneable {
119119
120120
```
121121

122+
When receiving an `ParseObject` from the SDK, you can often provide an instance of your custom object as an copy object.
123+
To always use your custom object class, you can register your subclass at the initialization of the SDK.
124+
```dart
125+
Parse().initialize(
126+
...,
127+
registeredSubClassMap: <String, ParseObjectConstructor>{
128+
'Diet_Plans': () => DietPlan(),
129+
},
130+
parseUserConstructor: (username, password, emailAddress, {client, debug, sessionToken}) => CustomParseUser(username, password, emailAddress),
131+
);
132+
```
133+
Additionally you can register `SubClasses` after the initialization of the SDK.
134+
```dart
135+
ParseCoreData().registerSubClass('Diet_Plans', () => DietPlan());
136+
ParseCoreData().registerUserSubClass((username, password, emailAddress, {client, debug, sessionToken}) => CustomParseUser(username, password, emailAddress));
137+
```
138+
Providing a `ParseObject` as described above should still work, even if you have registered a different `SubClass`.
139+
122140
## Add new values to objects
123141
To add a variable to an object call and retrieve it, call
124142

lib/parse_server_sdk.dart

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export 'src/network/parse_live_query.dart'
2323
if (dart.library.js) 'src/network/parse_live_query_web.dart';
2424
export 'src/utils/parse_live_list.dart';
2525

26+
part 'package:parse_server_sdk/src/data/parse_subclass_handler.dart';
2627
part 'package:parse_server_sdk/src/objects/response/parse_error_response.dart';
2728

2829
part 'package:parse_server_sdk/src/objects/response/parse_exception_response.dart';
@@ -111,28 +112,38 @@ class Parse {
111112
// debug: true,
112113
// liveQuery: true);
113114
// ```
114-
Future<Parse> initialize(String appId, String serverUrl,
115-
{bool debug = false,
116-
String appName = '',
117-
String liveQueryUrl,
118-
String clientKey,
119-
String masterKey,
120-
String sessionId,
121-
bool autoSendSessionId,
122-
SecurityContext securityContext,
123-
CoreStore coreStore}) async {
115+
Future<Parse> initialize(
116+
String appId,
117+
String serverUrl, {
118+
bool debug = false,
119+
String appName = '',
120+
String liveQueryUrl,
121+
String clientKey,
122+
String masterKey,
123+
String sessionId,
124+
bool autoSendSessionId,
125+
SecurityContext securityContext,
126+
CoreStore coreStore,
127+
Map<String, ParseObjectConstructor> registeredSubClassMap,
128+
ParseUserConstructor parseUserConstructor,
129+
}) async {
124130
final String url = removeTrailingSlash(serverUrl);
125131

126-
await ParseCoreData.init(appId, url,
127-
debug: debug,
128-
appName: appName,
129-
liveQueryUrl: liveQueryUrl,
130-
masterKey: masterKey,
131-
clientKey: clientKey,
132-
sessionId: sessionId,
133-
autoSendSessionId: autoSendSessionId,
134-
securityContext: securityContext,
135-
store: coreStore);
132+
await ParseCoreData.init(
133+
appId,
134+
url,
135+
debug: debug,
136+
appName: appName,
137+
liveQueryUrl: liveQueryUrl,
138+
masterKey: masterKey,
139+
clientKey: clientKey,
140+
sessionId: sessionId,
141+
autoSendSessionId: autoSendSessionId,
142+
securityContext: securityContext,
143+
store: coreStore,
144+
registeredSubClassMap: registeredSubClassMap,
145+
parseUserConstructor: parseUserConstructor,
146+
);
136147

137148
_hasBeenInitialized = true;
138149

lib/src/data/parse_core_data.dart

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ class ParseCoreData {
2222
String clientKey,
2323
String sessionId,
2424
bool autoSendSessionId,
25-
SecurityContext securityContext,
26-
CoreStore store}) async {
25+
SecurityContext securityContext,
26+
CoreStore store,
27+
Map<String, ParseObjectConstructor> registeredSubClassMap,
28+
ParseUserConstructor parseUserConstructor}) async {
2729
_instance = ParseCoreData._init(appId, serverUrl);
2830

2931
_instance.storage ??=
@@ -53,6 +55,11 @@ class ParseCoreData {
5355
if (securityContext != null) {
5456
_instance.securityContext = securityContext;
5557
}
58+
59+
_instance._subClassHandler = ParseSubClassHandler(
60+
registeredSubClassMap: registeredSubClassMap,
61+
parseUserConstructor: parseUserConstructor,
62+
);
5663
}
5764

5865
String appName;
@@ -66,6 +73,27 @@ class ParseCoreData {
6673
SecurityContext securityContext;
6774
bool debug;
6875
CoreStore storage;
76+
ParseSubClassHandler _subClassHandler;
77+
78+
void registerSubClass(
79+
String className, ParseObjectConstructor objectConstructor) {
80+
_subClassHandler.registerSubClass(className, objectConstructor);
81+
}
82+
83+
void registerUserSubClass(ParseUserConstructor parseUserConstructor) {
84+
_subClassHandler.registerUserSubClass(parseUserConstructor);
85+
}
86+
87+
ParseObject createObject(String classname) {
88+
return _subClassHandler.createObject(classname);
89+
}
90+
91+
ParseUser createParseUser(
92+
String username, String password, String emailAddress,
93+
{String sessionToken, bool debug, ParseHTTPClient client}) {
94+
return _subClassHandler.createParseUser(username, password, emailAddress,
95+
sessionToken: sessionToken, debug: debug, client: client);
96+
}
6997

7098
/// Sets the current sessionId.
7199
///
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
part of flutter_parse_sdk;
2+
3+
typedef ParseObjectConstructor = ParseObject Function();
4+
typedef ParseUserConstructor = ParseUser Function(
5+
String username, String password, String emailAddress,
6+
{String sessionToken, bool debug, ParseHTTPClient client});
7+
8+
class ParseSubClassHandler {
9+
10+
ParseSubClassHandler({Map<String, ParseObjectConstructor> registeredSubClassMap,
11+
ParseUserConstructor parseUserConstructor}){
12+
_subClassMap = registeredSubClassMap ?? Map<String, ParseObjectConstructor>();
13+
_parseUserConstructor = parseUserConstructor;
14+
}
15+
16+
Map<String, ParseObjectConstructor> _subClassMap;
17+
ParseUserConstructor _parseUserConstructor;
18+
19+
void registerSubClass(
20+
String className, ParseObjectConstructor objectConstructor) {
21+
if (className != keyClassUser &&
22+
className != keyClassInstallation &&
23+
className != keyClassSession)
24+
_subClassMap.putIfAbsent(className, () => objectConstructor);
25+
}
26+
27+
void registerUserSubClass(ParseUserConstructor parseUserConstructor) {
28+
_parseUserConstructor ??= parseUserConstructor;
29+
}
30+
31+
ParseObject createObject(String classname) {
32+
if (classname == keyClassUser) return createParseUser(null, null, null);
33+
if (_subClassMap.containsKey(classname)) return _subClassMap[classname]();
34+
return ParseObject(classname);
35+
}
36+
37+
ParseUser createParseUser(
38+
String username, String password, String emailAddress,
39+
{String sessionToken, bool debug, ParseHTTPClient client}) {
40+
return _parseUserConstructor != null
41+
? _parseUserConstructor(username, password, emailAddress,
42+
sessionToken: sessionToken, debug: debug, client: client)
43+
: ParseUser(username, password, emailAddress,
44+
sessionToken: sessionToken, debug: debug, client: client);
45+
}
46+
}

lib/src/network/parse_live_query.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -408,13 +408,15 @@ class Client {
408408
if (actionData.containsKey('object')) {
409409
final Map<String, dynamic> map = actionData['object'];
410410
final String className = map['className'];
411-
if (className == '_User') {
411+
if (className == keyClassUser) {
412412
subscription.eventCallbacks[actionData['op']](
413-
(subscription.copyObject ?? ParseUser(null, null, null))
413+
(subscription.copyObject ??
414+
ParseCoreData.instance.createParseUser(null, null, null))
414415
.fromJson(map));
415416
} else {
416417
subscription.eventCallbacks[actionData['op']](
417-
(subscription.copyObject ?? ParseObject(className))
418+
(subscription.copyObject ??
419+
ParseCoreData.instance.createObject(className))
418420
.fromJson(map));
419421
}
420422
} else {

lib/src/network/parse_live_query_web.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -406,13 +406,15 @@ class Client {
406406
if (actionData.containsKey('object')) {
407407
final Map<String, dynamic> map = actionData['object'];
408408
final String className = map['className'];
409-
if (className == '_User') {
409+
if (className == keyClassUser) {
410410
subscription.eventCallbacks[actionData['op']](
411-
(subscription.copyObject ?? ParseUser(null, null, null))
411+
(subscription.copyObject ??
412+
ParseCoreData.instance.createParseUser(null, null, null))
412413
.fromJson(map));
413414
} else {
414415
subscription.eventCallbacks[actionData['op']](
415-
(subscription.copyObject ?? ParseObject(className))
416+
(subscription.copyObject ??
417+
ParseCoreData.instance.createObject(className))
416418
.fromJson(map));
417419
}
418420
} else {

lib/src/network/parse_query.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ class QueryBuilder<T extends ParseObject> {
55
/// Class to create complex queries
66
QueryBuilder(this.object) : super();
77

8+
QueryBuilder.name(String classname)
9+
: this(ParseCoreData.instance.createObject(classname));
10+
811
QueryBuilder.or(this.object, List<QueryBuilder<T>> list) {
912
if (list != null) {
1013
String query = '"\$or":[';

lib/src/objects/parse_user.dart

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ class ParseUser extends ParseObject implements ParseCloneable {
7676

7777
static ParseUser createUser(
7878
[String username, String password, String emailAddress]) {
79-
return ParseUser(username, password, emailAddress);
79+
return ParseCoreData.instance
80+
.createParseUser(username, password, emailAddress);
8081
}
8182

8283
/// Gets the current user from the server
@@ -327,6 +328,19 @@ class ParseUser extends ParseObject implements ParseCloneable {
327328
}
328329
}
329330

331+
@override
332+
Future<ParseResponse> update() async {
333+
if (objectId == null) {
334+
return await signUp();
335+
} else {
336+
final ParseResponse response = await super.update();
337+
if (response.success) {
338+
await _onResponseSuccess();
339+
}
340+
return response;
341+
}
342+
}
343+
330344
Future<void> _onResponseSuccess() async {
331345
await saveInStorage(keyParseStoreUser);
332346
}
@@ -412,7 +426,8 @@ class ParseUser extends ParseObject implements ParseCloneable {
412426
}
413427
}
414428

415-
static ParseUser _getEmptyUser() => ParseUser(null, null, null);
429+
static ParseUser _getEmptyUser() =>
430+
ParseCoreData.instance.createParseUser(null, null, null);
416431

417432
static Future<String> _getInstallationId() async {
418433
final ParseInstallation parseInstallation =

lib/src/storage/core_store_sem_impl.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class CoreStoreSembastImp implements CoreStore {
1212
factory ??= databaseFactoryIo;
1313
final SembastCodec codec = getXXTeaSembastCodec(password: password);
1414
String dbDirectory = '';
15-
if (Platform.isIOS || Platform.isAndroid)
15+
if (Platform.isIOS || Platform.isAndroid || Platform.isMacOS)
1616
dbDirectory = (await getApplicationDocumentsDirectory()).path;
1717
final String dbPath = path.join('$dbDirectory/parse', 'parse.db');
1818
final Database db = await factory.openDatabase(dbPath, codec: codec);

lib/src/utils/parse_decoder.dart

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,9 @@ dynamic parseDecode(dynamic value) {
5858
final String val = map['base64'];
5959
return base64.decode(val);
6060
case 'Pointer':
61-
final String className = map['className'];
62-
if (className == '_User') {
63-
return ParseUser._getEmptyUser().fromJson(map);
64-
}
65-
return ParseObject(className).fromJson(map);
6661
case 'Object':
6762
final String className = map['className'];
68-
if (className == '_User') {
69-
return ParseUser._getEmptyUser().fromJson(map);
70-
}
71-
return ParseObject(className).fromJson(map);
63+
return ParseCoreData.instance.createObject(className).fromJson(map);
7264
case 'File':
7365
return ParseFile(null, url: map['url'], name: map['name'])
7466
.fromJson(map);
@@ -86,15 +78,15 @@ dynamic parseDecode(dynamic value) {
8678
/// Decoding from locally cached JSON
8779
if (map.containsKey('className')) {
8880
switch (map['className']) {
89-
case '_User':
90-
return ParseUser._getEmptyUser().fromJson(map);
9181
case 'GeoPoint':
9282
final num latitude = map['latitude'] ?? 0.0;
9383
final num longitude = map['longitude'] ?? 0.0;
9484
return ParseGeoPoint(
9585
latitude: latitude.toDouble(), longitude: longitude.toDouble());
9686
default:
97-
return ParseObject(map['className']).fromJson(map);
87+
return ParseCoreData.instance
88+
.createObject(map['className'])
89+
.fromJson(map);
9890
}
9991
}
10092

0 commit comments

Comments
 (0)