Skip to content

Commit ca568a6

Browse files
authored
feat: Add support for custom EventEmitter (#1999)
1 parent c6ffeb2 commit ca568a6

10 files changed

+137
-76
lines changed

integration/test/ParseLocalDatastoreTest.js

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,52 @@
11
'use strict';
22

33
const assert = require('assert');
4-
const Parse = require('../../node');
54

65
global.localStorage = require('./mockLocalStorage');
6+
global.WebSocket = require('ws');
77
const mockRNStorage = require('./mockRNStorage');
8-
const LocalDatastoreUtils = require('../../lib/node/LocalDatastoreUtils');
8+
const serverURL = 'http://localhost:1337/parse';
99

10-
const { DEFAULT_PIN, PIN_PREFIX, isLocalDatastoreKey } = LocalDatastoreUtils;
10+
function runTest(controller) {
11+
const Parse = require(`../../${controller.name}`);
12+
const LocalDatastoreUtils = require('../../lib/node/LocalDatastoreUtils');
1113

12-
function LDS_KEY(object) {
13-
return Parse.LocalDatastore.getKeyForObject(object);
14-
}
15-
function LDS_FULL_JSON(object) {
16-
const json = object._toFullJSON();
17-
if (object._localId) {
18-
json._localId = object._localId;
14+
const { DEFAULT_PIN, PIN_PREFIX, isLocalDatastoreKey } = LocalDatastoreUtils;
15+
16+
const Item = Parse.Object.extend('Item');
17+
const TestObject = Parse.Object.extend('TestObject');
18+
19+
function LDS_KEY(object) {
20+
return Parse.LocalDatastore.getKeyForObject(object);
1921
}
20-
return json;
21-
}
22-
function runTest(controller) {
22+
function LDS_FULL_JSON(object) {
23+
const json = object._toFullJSON();
24+
if (object._localId) {
25+
json._localId = object._localId;
26+
}
27+
return json;
28+
}
29+
2330
describe(`Parse Object Pinning (${controller.name})`, () => {
2431
beforeEach(async () => {
2532
const StorageController = require(controller.file);
2633
Parse.CoreManager.setAsyncStorage(mockRNStorage);
2734
Parse.CoreManager.setLocalDatastoreController(StorageController);
28-
Parse.enableLocalDatastore();
35+
Parse.CoreManager.setEventEmitter(require('events').EventEmitter);
36+
Parse.User.enableUnsafeCurrentUser();
2937
await Parse.LocalDatastore._clear();
38+
Parse.initialize('integration');
39+
Parse.CoreManager.set('SERVER_URL', serverURL);
40+
Parse.CoreManager.set('MASTER_KEY', 'notsosecret');
41+
const RESTController = Parse.CoreManager.getRESTController();
42+
RESTController._setXHR(require('xmlhttprequest').XMLHttpRequest);
43+
Parse.enableLocalDatastore();
3044
});
45+
3146
function getStorageCount(storage) {
3247
return Object.keys(storage).reduce((acc, key) => acc + (isLocalDatastoreKey(key) ? 1 : 0), 1);
3348
}
49+
3450
it(`${controller.name} can clear localDatastore`, async () => {
3551
const obj1 = new TestObject();
3652
const obj2 = new TestObject();
@@ -1060,8 +1076,15 @@ function runTest(controller) {
10601076
const StorageController = require(controller.file);
10611077
Parse.CoreManager.setAsyncStorage(mockRNStorage);
10621078
Parse.CoreManager.setLocalDatastoreController(StorageController);
1063-
Parse.enableLocalDatastore();
1079+
Parse.CoreManager.setEventEmitter(require('events').EventEmitter);
10641080
Parse.LocalDatastore._clear();
1081+
Parse.User.enableUnsafeCurrentUser();
1082+
Parse.initialize('integration');
1083+
Parse.CoreManager.set('SERVER_URL', serverURL);
1084+
Parse.CoreManager.set('MASTER_KEY', 'notsosecret');
1085+
const RESTController = Parse.CoreManager.getRESTController();
1086+
RESTController._setXHR(require('xmlhttprequest').XMLHttpRequest);
1087+
Parse.enableLocalDatastore();
10651088

10661089
const numbers = [];
10671090
for (let i = 0; i < 10; i++) {
@@ -2949,20 +2972,10 @@ function runTest(controller) {
29492972
}
29502973

29512974
describe('Parse LocalDatastore', () => {
2952-
beforeEach(() => {
2953-
Parse.CoreManager.getInstallationController()._setInstallationIdCache('1234');
2954-
Parse.enableLocalDatastore();
2955-
Parse.User.enableUnsafeCurrentUser();
2956-
});
2957-
29582975
const controllers = [
2959-
{ name: 'Default', file: '../../lib/node/LocalDatastoreController' },
2960-
{
2961-
name: 'React-Native',
2962-
file: '../../lib/node/LocalDatastoreController.react-native',
2963-
},
2976+
{ name: 'node', file: '../../lib/node/LocalDatastoreController' },
2977+
{ name: 'react-native', file: '../../lib/react-native/LocalDatastoreController.react-native' },
29642978
];
2965-
29662979
for (let i = 0; i < controllers.length; i += 1) {
29672980
const controller = controllers[i];
29682981
runTest(controller);

src/CoreManager.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,13 @@ const CoreManager = {
217217
config[key] = value;
218218
},
219219

220+
setIfNeeded: function (key: string, value: any): any {
221+
if (!config.hasOwnProperty(key)) {
222+
config[key] = value;
223+
}
224+
return config[key];
225+
},
226+
220227
/* Specialized Controller Setters/Getters */
221228

222229
setAnalyticsController(controller: AnalyticsController) {
@@ -255,6 +262,14 @@ const CoreManager = {
255262
return config['CryptoController'];
256263
},
257264

265+
setEventEmitter(eventEmitter: any) {
266+
config['EventEmitter'] = eventEmitter;
267+
},
268+
269+
getEventEmitter(): any {
270+
return config['EventEmitter'];
271+
},
272+
258273
setFileController(controller: FileController) {
259274
requireMethods('FileController', ['saveFile', 'saveBase64'], controller);
260275
config['FileController'] = controller;
@@ -273,6 +288,14 @@ const CoreManager = {
273288
return config['InstallationController'];
274289
},
275290

291+
setLiveQuery(liveQuery: any) {
292+
config['LiveQuery'] = liveQuery;
293+
},
294+
295+
getLiveQuery(): any {
296+
return config['LiveQuery'];
297+
},
298+
276299
setObjectController(controller: ObjectController) {
277300
requireMethods('ObjectController', ['save', 'fetch', 'destroy'], controller);
278301
config['ObjectController'] = controller;

src/EventEmitter.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,19 @@
22
* This is a simple wrapper to unify EventEmitter implementations across platforms.
33
*/
44

5-
if (process.env.PARSE_BUILD === 'react-native') {
6-
let EventEmitter = require('react-native/Libraries/vendor/emitter/EventEmitter');
7-
if (EventEmitter.default) {
8-
EventEmitter = EventEmitter.default;
5+
let EventEmitter;
6+
7+
try {
8+
if (process.env.PARSE_BUILD === 'react-native') {
9+
EventEmitter = require('react-native/Libraries/vendor/emitter/EventEmitter');
10+
if (EventEmitter.default) {
11+
EventEmitter = EventEmitter.default;
12+
}
13+
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
14+
} else {
15+
EventEmitter = require('events').EventEmitter;
916
}
10-
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
11-
module.exports = EventEmitter;
12-
} else {
13-
module.exports = require('events').EventEmitter;
17+
} catch (_) {
18+
// EventEmitter unavailable
1419
}
20+
module.exports = EventEmitter;

src/LiveQueryClient.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
/* global WebSocket */
22

33
import CoreManager from './CoreManager';
4-
import EventEmitter from './EventEmitter';
54
import ParseObject from './ParseObject';
65
import LiveQuerySubscription from './LiveQuerySubscription';
76
import { resolvingPromise } from './promiseUtils';
@@ -63,7 +62,6 @@ const generateInterval = k => {
6362

6463
/**
6564
* Creates a new LiveQueryClient.
66-
* Extends events.EventEmitter
6765
* <a href="https://nodejs.org/api/events.html#events_class_eventemitter">cloud functions</a>.
6866
*
6967
* A wrapper of a standard WebSocket client. We add several useful methods to
@@ -105,7 +103,7 @@ const generateInterval = k => {
105103
*
106104
* @alias Parse.LiveQueryClient
107105
*/
108-
class LiveQueryClient extends EventEmitter {
106+
class LiveQueryClient {
109107
attempts: number;
110108
id: number;
111109
requestId: number;
@@ -138,8 +136,6 @@ class LiveQueryClient extends EventEmitter {
138136
sessionToken,
139137
installationId,
140138
}) {
141-
super();
142-
143139
if (!serverURL || serverURL.indexOf('ws') !== 0) {
144140
throw new Error(
145141
'You need to set a proper Parse LiveQuery server url before using LiveQueryClient'
@@ -160,7 +156,11 @@ class LiveQueryClient extends EventEmitter {
160156
this.connectPromise = resolvingPromise();
161157
this.subscriptions = new Map();
162158
this.state = CLIENT_STATE.INITIALIZED;
159+
const EventEmitter = CoreManager.getEventEmitter();
160+
this.emitter = new EventEmitter();
163161

162+
this.on = this.emitter.on;
163+
this.emit = this.emitter.emit;
164164
// adding listener so process does not crash
165165
// best practice is for developer to register their own listener
166166
this.on('error', () => {});

src/LiveQuerySubscription.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import EventEmitter from './EventEmitter';
21
import CoreManager from './CoreManager';
32
import { resolvingPromise } from './promiseUtils';
43

54
/**
65
* Creates a new LiveQuery Subscription.
7-
* Extends events.EventEmitter
86
* <a href="https://nodejs.org/api/events.html#events_class_eventemitter">cloud functions</a>.
97
*
108
* <p>Response Object - Contains data from the client that made the request
@@ -84,24 +82,25 @@ import { resolvingPromise } from './promiseUtils';
8482
* subscription.on('close', () => {
8583
*
8684
* });</pre></p>
87-
*
88-
* @alias Parse.LiveQuerySubscription
8985
*/
90-
class Subscription extends EventEmitter {
86+
class Subscription {
9187
/*
9288
* @param {string} id - subscription id
9389
* @param {string} query - query to subscribe to
9490
* @param {string} sessionToken - optional session token
9591
*/
9692
constructor(id, query, sessionToken) {
97-
super();
9893
this.id = id;
9994
this.query = query;
10095
this.sessionToken = sessionToken;
10196
this.subscribePromise = resolvingPromise();
10297
this.unsubscribePromise = resolvingPromise();
10398
this.subscribed = false;
99+
const EventEmitter = CoreManager.getEventEmitter();
100+
this.emitter = new EventEmitter();
104101

102+
this.on = this.emitter.on;
103+
this.emit = this.emitter.emit;
105104
// adding listener so process does not crash
106105
// best practice is for developer to register their own listener
107106
this.on('error', () => {});

src/Parse.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import AnonymousUtils from './AnonymousUtils'
1111
import * as Cloud from './Cloud';
1212
import CLP from './ParseCLP';
1313
import CoreManager from './CoreManager';
14+
import EventEmitter from './EventEmitter';
1415
import Config from './ParseConfig'
1516
import ParseError from './ParseError'
1617
import FacebookUtils from './FacebookUtils'
@@ -76,7 +77,7 @@ interface ParseType {
7677
Session: typeof Session,
7778
Storage: typeof Storage,
7879
User: typeof User,
79-
LiveQuery: typeof LiveQuery,
80+
LiveQuery?: typeof LiveQuery,
8081
LiveQueryClient: typeof LiveQueryClient,
8182

8283
initialize(applicationId: string, javaScriptKey: string): void,
@@ -143,13 +144,12 @@ const Parse: ParseType = {
143144
Session: Session,
144145
Storage: Storage,
145146
User: User,
146-
LiveQuery: LiveQuery,
147147
LiveQueryClient: LiveQueryClient,
148+
LiveQuery: undefined,
148149
IndexedDB: undefined,
149150
Hooks: undefined,
150151
Parse: undefined,
151152

152-
153153
/**
154154
* Call this method first to set up your authentication tokens for Parse.
155155
*
@@ -179,6 +179,10 @@ const Parse: ParseType = {
179179
CoreManager.set('JAVASCRIPT_KEY', javaScriptKey);
180180
CoreManager.set('MASTER_KEY', masterKey);
181181
CoreManager.set('USE_MASTER_KEY', false);
182+
CoreManager.setIfNeeded('EventEmitter', EventEmitter);
183+
184+
Parse.LiveQuery = new LiveQuery();
185+
CoreManager.setIfNeeded('LiveQuery', Parse.LiveQuery);
182186
},
183187

184188
/**
@@ -422,7 +426,6 @@ const Parse: ParseType = {
422426
isEncryptedUserEnabled () {
423427
return this.encryptedUser;
424428
},
425-
426429
};
427430

428431
if (process.env.PARSE_BUILD === 'browser') {

0 commit comments

Comments
 (0)