Skip to content

RegisterSubClass and smaler changes #368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,24 @@ class DietPlan extends ParseObject implements ParseCloneable {

```

When receiving an `ParseObject` from the SDK, you can often provide an instance of your custom object as an copy object.
To always use your custom object class, you can register your subclass at the initialization of the SDK.
```dart
Parse().initialize(
...,
registeredSubClassMap: <String, ParseObjectConstructor>{
'Diet_Plans': () => DietPlan(),
},
parseUserConstructor: (username, password, emailAddress, {client, debug, sessionToken}) => CustomParseUser(username, password, emailAddress),
);
```
Additionally you can register `SubClasses` after the initialization of the SDK.
```dart
ParseCoreData().registerSubClass('Diet_Plans', () => DietPlan());
ParseCoreData().registerUserSubClass((username, password, emailAddress, {client, debug, sessionToken}) => CustomParseUser(username, password, emailAddress));
```
Providing a `ParseObject` as described above should still work, even if you have registered a different `SubClass`.

## Add new values to objects
To add a variable to an object call and retrieve it, call

Expand Down
51 changes: 31 additions & 20 deletions lib/parse_server_sdk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export 'src/network/parse_live_query.dart'
if (dart.library.js) 'src/network/parse_live_query_web.dart';
export 'src/utils/parse_live_list.dart';

part 'package:parse_server_sdk/src/data/parse_subclass_handler.dart';
part 'package:parse_server_sdk/src/objects/response/parse_error_response.dart';

part 'package:parse_server_sdk/src/objects/response/parse_exception_response.dart';
Expand Down Expand Up @@ -111,28 +112,38 @@ class Parse {
// debug: true,
// liveQuery: true);
// ```
Future<Parse> initialize(String appId, String serverUrl,
{bool debug = false,
String appName = '',
String liveQueryUrl,
String clientKey,
String masterKey,
String sessionId,
bool autoSendSessionId,
SecurityContext securityContext,
CoreStore coreStore}) async {
Future<Parse> initialize(
String appId,
String serverUrl, {
bool debug = false,
String appName = '',
String liveQueryUrl,
String clientKey,
String masterKey,
String sessionId,
bool autoSendSessionId,
SecurityContext securityContext,
CoreStore coreStore,
Map<String, ParseObjectConstructor> registeredSubClassMap,
ParseUserConstructor parseUserConstructor,
}) async {
final String url = removeTrailingSlash(serverUrl);

await ParseCoreData.init(appId, url,
debug: debug,
appName: appName,
liveQueryUrl: liveQueryUrl,
masterKey: masterKey,
clientKey: clientKey,
sessionId: sessionId,
autoSendSessionId: autoSendSessionId,
securityContext: securityContext,
store: coreStore);
await ParseCoreData.init(
appId,
url,
debug: debug,
appName: appName,
liveQueryUrl: liveQueryUrl,
masterKey: masterKey,
clientKey: clientKey,
sessionId: sessionId,
autoSendSessionId: autoSendSessionId,
securityContext: securityContext,
store: coreStore,
registeredSubClassMap: registeredSubClassMap,
parseUserConstructor: parseUserConstructor,
);

_hasBeenInitialized = true;

Expand Down
32 changes: 30 additions & 2 deletions lib/src/data/parse_core_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ class ParseCoreData {
String clientKey,
String sessionId,
bool autoSendSessionId,
SecurityContext securityContext,
CoreStore store}) async {
SecurityContext securityContext,
CoreStore store,
Map<String, ParseObjectConstructor> registeredSubClassMap,
ParseUserConstructor parseUserConstructor}) async {
_instance = ParseCoreData._init(appId, serverUrl);

_instance.storage ??=
Expand Down Expand Up @@ -53,6 +55,11 @@ class ParseCoreData {
if (securityContext != null) {
_instance.securityContext = securityContext;
}

_instance._subClassHandler = ParseSubClassHandler(
registeredSubClassMap: registeredSubClassMap,
parseUserConstructor: parseUserConstructor,
);
}

String appName;
Expand All @@ -66,6 +73,27 @@ class ParseCoreData {
SecurityContext securityContext;
bool debug;
CoreStore storage;
ParseSubClassHandler _subClassHandler;

void registerSubClass(
String className, ParseObjectConstructor objectConstructor) {
_subClassHandler.registerSubClass(className, objectConstructor);
}

void registerUserSubClass(ParseUserConstructor parseUserConstructor) {
_subClassHandler.registerUserSubClass(parseUserConstructor);
}

ParseObject createObject(String classname) {
return _subClassHandler.createObject(classname);
}

ParseUser createParseUser(
String username, String password, String emailAddress,
{String sessionToken, bool debug, ParseHTTPClient client}) {
return _subClassHandler.createParseUser(username, password, emailAddress,
sessionToken: sessionToken, debug: debug, client: client);
}

/// Sets the current sessionId.
///
Expand Down
46 changes: 46 additions & 0 deletions lib/src/data/parse_subclass_handler.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
part of flutter_parse_sdk;

typedef ParseObjectConstructor = ParseObject Function();
typedef ParseUserConstructor = ParseUser Function(
String username, String password, String emailAddress,
{String sessionToken, bool debug, ParseHTTPClient client});

class ParseSubClassHandler {

ParseSubClassHandler({Map<String, ParseObjectConstructor> registeredSubClassMap,
ParseUserConstructor parseUserConstructor}){
_subClassMap = registeredSubClassMap ?? Map<String, ParseObjectConstructor>();
_parseUserConstructor = parseUserConstructor;
}

Map<String, ParseObjectConstructor> _subClassMap;
ParseUserConstructor _parseUserConstructor;

void registerSubClass(
String className, ParseObjectConstructor objectConstructor) {
if (className != keyClassUser &&
className != keyClassInstallation &&
className != keyClassSession)
_subClassMap.putIfAbsent(className, () => objectConstructor);
}

void registerUserSubClass(ParseUserConstructor parseUserConstructor) {
_parseUserConstructor ??= parseUserConstructor;
}

ParseObject createObject(String classname) {
if (classname == keyClassUser) return createParseUser(null, null, null);
if (_subClassMap.containsKey(classname)) return _subClassMap[classname]();
return ParseObject(classname);
}

ParseUser createParseUser(
String username, String password, String emailAddress,
{String sessionToken, bool debug, ParseHTTPClient client}) {
return _parseUserConstructor != null
? _parseUserConstructor(username, password, emailAddress,
sessionToken: sessionToken, debug: debug, client: client)
: ParseUser(username, password, emailAddress,
sessionToken: sessionToken, debug: debug, client: client);
}
}
8 changes: 5 additions & 3 deletions lib/src/network/parse_live_query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -408,13 +408,15 @@ class Client {
if (actionData.containsKey('object')) {
final Map<String, dynamic> map = actionData['object'];
final String className = map['className'];
if (className == '_User') {
if (className == keyClassUser) {
subscription.eventCallbacks[actionData['op']](
(subscription.copyObject ?? ParseUser(null, null, null))
(subscription.copyObject ??
ParseCoreData.instance.createParseUser(null, null, null))
.fromJson(map));
} else {
subscription.eventCallbacks[actionData['op']](
(subscription.copyObject ?? ParseObject(className))
(subscription.copyObject ??
ParseCoreData.instance.createObject(className))
.fromJson(map));
}
} else {
Expand Down
8 changes: 5 additions & 3 deletions lib/src/network/parse_live_query_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -406,13 +406,15 @@ class Client {
if (actionData.containsKey('object')) {
final Map<String, dynamic> map = actionData['object'];
final String className = map['className'];
if (className == '_User') {
if (className == keyClassUser) {
subscription.eventCallbacks[actionData['op']](
(subscription.copyObject ?? ParseUser(null, null, null))
(subscription.copyObject ??
ParseCoreData.instance.createParseUser(null, null, null))
.fromJson(map));
} else {
subscription.eventCallbacks[actionData['op']](
(subscription.copyObject ?? ParseObject(className))
(subscription.copyObject ??
ParseCoreData.instance.createObject(className))
.fromJson(map));
}
} else {
Expand Down
3 changes: 3 additions & 0 deletions lib/src/network/parse_query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ class QueryBuilder<T extends ParseObject> {
/// Class to create complex queries
QueryBuilder(this.object) : super();

QueryBuilder.name(String classname)
: this(ParseCoreData.instance.createObject(classname));

QueryBuilder.or(this.object, List<QueryBuilder<T>> list) {
if (list != null) {
String query = '"\$or":[';
Expand Down
19 changes: 17 additions & 2 deletions lib/src/objects/parse_user.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ class ParseUser extends ParseObject implements ParseCloneable {

static ParseUser createUser(
[String username, String password, String emailAddress]) {
return ParseUser(username, password, emailAddress);
return ParseCoreData.instance
.createParseUser(username, password, emailAddress);
}

/// Gets the current user from the server
Expand Down Expand Up @@ -327,6 +328,19 @@ class ParseUser extends ParseObject implements ParseCloneable {
}
}

@override
Future<ParseResponse> update() async {
if (objectId == null) {
return await signUp();
} else {
final ParseResponse response = await super.update();
if (response.success) {
await _onResponseSuccess();
}
return response;
}
}

Future<void> _onResponseSuccess() async {
await saveInStorage(keyParseStoreUser);
}
Expand Down Expand Up @@ -412,7 +426,8 @@ class ParseUser extends ParseObject implements ParseCloneable {
}
}

static ParseUser _getEmptyUser() => ParseUser(null, null, null);
static ParseUser _getEmptyUser() =>
ParseCoreData.instance.createParseUser(null, null, null);

static Future<String> _getInstallationId() async {
final ParseInstallation parseInstallation =
Expand Down
2 changes: 1 addition & 1 deletion lib/src/storage/core_store_sem_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class CoreStoreSembastImp implements CoreStore {
factory ??= databaseFactoryIo;
final SembastCodec codec = getXXTeaSembastCodec(password: password);
String dbDirectory = '';
if (Platform.isIOS || Platform.isAndroid)
if (Platform.isIOS || Platform.isAndroid || Platform.isMacOS)
dbDirectory = (await getApplicationDocumentsDirectory()).path;
final String dbPath = path.join('$dbDirectory/parse', 'parse.db');
final Database db = await factory.openDatabase(dbPath, codec: codec);
Expand Down
16 changes: 4 additions & 12 deletions lib/src/utils/parse_decoder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,9 @@ dynamic parseDecode(dynamic value) {
final String val = map['base64'];
return base64.decode(val);
case 'Pointer':
final String className = map['className'];
if (className == '_User') {
return ParseUser._getEmptyUser().fromJson(map);
}
return ParseObject(className).fromJson(map);
case 'Object':
final String className = map['className'];
if (className == '_User') {
return ParseUser._getEmptyUser().fromJson(map);
}
return ParseObject(className).fromJson(map);
return ParseCoreData.instance.createObject(className).fromJson(map);
case 'File':
return ParseFile(null, url: map['url'], name: map['name'])
.fromJson(map);
Expand All @@ -86,15 +78,15 @@ dynamic parseDecode(dynamic value) {
/// Decoding from locally cached JSON
if (map.containsKey('className')) {
switch (map['className']) {
case '_User':
return ParseUser._getEmptyUser().fromJson(map);
case 'GeoPoint':
final num latitude = map['latitude'] ?? 0.0;
final num longitude = map['longitude'] ?? 0.0;
return ParseGeoPoint(
latitude: latitude.toDouble(), longitude: longitude.toDouble());
default:
return ParseObject(map['className']).fromJson(map);
return ParseCoreData.instance
.createObject(map['className'])
.fromJson(map);
}
}

Expand Down