Skip to content

Commit 089e208

Browse files
Amphaaldplewis
authored andcommitted
Fixes LiveQuery behavior on multiple subscriptions (#758)
* Fixes LiveQuery behavior on multiple subscriptions * initial test and cleanup * Massive cleanup * improve coverage * quick nits
1 parent aceea03 commit 089e208

File tree

10 files changed

+406
-155
lines changed

10 files changed

+406
-155
lines changed

integration/server.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ const api = new ParseServer({
99
appId: 'integration',
1010
masterKey: 'notsosecret',
1111
serverURL: 'http://localhost:1337/parse', // Don't forget to change to https if needed
12-
cloud: `${__dirname}/cloud/main.js`
12+
cloud: `${__dirname}/cloud/main.js`,
13+
liveQuery: {
14+
classNames: ['TestObject', 'DiffObject'],
15+
},
16+
startLiveQueryServer: true,
1317
});
1418

1519
// Serve the Parse API on the /parse URL prefix
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const clear = require('./clear');
5+
const Parse = require('../../node');
6+
7+
const TestObject = Parse.Object.extend('TestObject');
8+
const DiffObject = Parse.Object.extend('DiffObject');
9+
10+
describe('Parse LiveQuery', () => {
11+
beforeEach((done) => {
12+
Parse.initialize('integration');
13+
Parse.CoreManager.set('SERVER_URL', 'http://localhost:1337/parse');
14+
Parse.Storage._clear();
15+
clear().then(done).catch(done.fail);
16+
});
17+
18+
it('can subscribe to query', async () => {
19+
const object = new TestObject();
20+
await object.save();
21+
22+
const query = new Parse.Query(TestObject);
23+
query.equalTo('objectId', object.id);
24+
const subscription = await query.subscribe();
25+
26+
subscription.on('update', object => {
27+
assert.equal(object.get('foo'), 'bar');
28+
})
29+
object.set({ foo: 'bar' });
30+
await object.save();
31+
});
32+
33+
it('can subscribe to multiple queries', async (done) => {
34+
const objectA = new TestObject();
35+
const objectB = new TestObject();
36+
await Parse.Object.saveAll([objectA, objectB]);
37+
38+
const queryA = new Parse.Query(TestObject);
39+
const queryB = new Parse.Query(TestObject);
40+
queryA.equalTo('objectId', objectA.id);
41+
queryB.equalTo('objectId', objectB.id);
42+
const subscriptionA = await queryA.subscribe();
43+
const subscriptionB = await queryB.subscribe();
44+
let count = 0;
45+
subscriptionA.on('update', object => {
46+
count++;
47+
assert.equal(object.get('foo'), 'bar');
48+
})
49+
subscriptionB.on('update', object => {
50+
count++;
51+
assert.equal(object.get('foo'), 'baz');
52+
})
53+
await objectA.save({ foo: 'bar' });
54+
await objectB.save({ foo: 'baz' });
55+
56+
setTimeout(() => {
57+
assert.equal(count, 2);
58+
done();
59+
}, 100);
60+
});
61+
62+
it('can subscribe to multiple queries different class', async (done) => {
63+
const objectA = new TestObject();
64+
const objectB = new DiffObject();
65+
await Parse.Object.saveAll([objectA, objectB]);
66+
67+
const queryA = new Parse.Query(TestObject);
68+
const queryB = new Parse.Query(DiffObject);
69+
queryA.equalTo('objectId', objectA.id);
70+
queryB.equalTo('objectId', objectB.id);
71+
const subscriptionA = await queryA.subscribe();
72+
const subscriptionB = await queryB.subscribe();
73+
let count = 0;
74+
subscriptionA.on('update', object => {
75+
count++;
76+
assert.equal(object.get('foo'), 'bar');
77+
})
78+
subscriptionB.on('update', object => {
79+
count++;
80+
assert.equal(object.get('foo'), 'baz');
81+
})
82+
await objectA.save({ foo: 'bar' });
83+
await objectB.save({ foo: 'baz' });
84+
85+
setTimeout(() => {
86+
expect(count).toBe(2);
87+
done();
88+
}, 1000);
89+
});
90+
91+
it('can unsubscribe to multiple queries different class', async (done) => {
92+
const objectA = new TestObject();
93+
const objectB = new DiffObject();
94+
await Parse.Object.saveAll([objectA, objectB]);
95+
96+
const queryA = new Parse.Query(TestObject);
97+
const queryB = new Parse.Query(DiffObject);
98+
queryA.equalTo('objectId', objectA.id);
99+
queryB.equalTo('objectId', objectB.id);
100+
const subscriptionA = await queryA.subscribe();
101+
const subscriptionB = await queryB.subscribe();
102+
let count = 0;
103+
subscriptionA.on('update', () => {
104+
count++;
105+
})
106+
subscriptionB.on('update', object => {
107+
count++;
108+
assert.equal(object.get('foo'), 'baz');
109+
})
110+
subscriptionA.unsubscribe();
111+
await objectA.save({ foo: 'bar' });
112+
await objectB.save({ foo: 'baz' });
113+
114+
setTimeout(() => {
115+
assert.equal(count, 1);
116+
done();
117+
}, 1000);
118+
});
119+
120+
it('can unsubscribe with await to multiple queries different class', async (done) => {
121+
const objectA = new TestObject();
122+
const objectB = new DiffObject();
123+
await Parse.Object.saveAll([objectA, objectB]);
124+
125+
const queryA = new Parse.Query(TestObject);
126+
const queryB = new Parse.Query(DiffObject);
127+
queryA.equalTo('objectId', objectA.id);
128+
queryB.equalTo('objectId', objectB.id);
129+
const subscriptionA = await queryA.subscribe();
130+
const subscriptionB = await queryB.subscribe();
131+
let count = 0;
132+
subscriptionA.on('update', () => {
133+
count++;
134+
})
135+
subscriptionB.on('update', object => {
136+
count++;
137+
assert.equal(object.get('foo'), 'baz');
138+
})
139+
await subscriptionA.unsubscribe();
140+
await objectA.save({ foo: 'bar' });
141+
await objectB.save({ foo: 'baz' });
142+
143+
setTimeout(() => {
144+
assert.equal(count, 1);
145+
done();
146+
}, 1000);
147+
});
148+
});

integration/test/helper.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
const ParseServer = require('parse-server').ParseServer;
2+
13
jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
24
beforeAll((done) => {
35
const { app } = require('../server');
4-
app.listen(1337, () => {
6+
const httpServer = require('http').createServer(app);
7+
8+
httpServer.listen(1337, () => {
59
console.log('parse-server running on port 1337.');
610
done();
711
});
12+
ParseServer.createLiveQueryServer(httpServer);
813
});

src/CoreManager.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -393,10 +393,9 @@ module.exports = {
393393

394394
setLiveQueryController(controller: any) {
395395
requireMethods('LiveQueryController', [
396-
'subscribe',
397-
'unsubscribe',
398-
'open',
399-
'close',
396+
'setDefaultLiveQueryClient',
397+
'getDefaultLiveQueryClient',
398+
'_clearCachedDefaultClient',
400399
], controller);
401400
config['LiveQueryController'] = controller;
402401
},

src/LiveQueryClient.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,6 @@ class LiveQueryClient extends EventEmitter {
209209
this.socket.send(JSON.stringify(subscribeRequest));
210210
});
211211

212-
// adding listener so process does not crash
213-
// best practice is for developer to register their own listener
214-
subscription.on('error', () => {});
215-
216212
return subscription;
217213
}
218214

src/LiveQuerySubscription.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,16 @@ class Subscription extends EventEmitter {
101101
this.id = id;
102102
this.query = query;
103103
this.sessionToken = sessionToken;
104+
105+
// adding listener so process does not crash
106+
// best practice is for developer to register their own listener
107+
this.on('error', () => {});
104108
}
105109

106110
/**
107-
* closes the subscription
111+
* Close the subscription
108112
*/
109-
unsubscribe() {
113+
unsubscribe(): Promise {
110114
return CoreManager.getLiveQueryController().getDefaultLiveQueryClient().then((liveQueryClient) => {
111115
liveQueryClient.unsubscribe(this);
112116
this.emit('close');

0 commit comments

Comments
 (0)