Skip to content

Commit 6d408cd

Browse files
committed
Fixed db bug
1 parent 585d188 commit 6d408cd

File tree

4 files changed

+163
-88
lines changed

4 files changed

+163
-88
lines changed

android/src/main/java/io/fullstack/firestack/FirestackUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ public static WritableMap dataSnapshotToMap(String name,
5353
DataSnapshot dataSnapshot) {
5454
WritableMap data = Arguments.createMap();
5555

56-
data.putString("path", path);
5756
data.putString("key", dataSnapshot.getKey());
5857
data.putBoolean("exists", dataSnapshot.exists());
5958
data.putBoolean("hasChildren", dataSnapshot.hasChildren());
@@ -92,6 +91,7 @@ public static WritableMap dataSnapshotToMap(String name,
9291
WritableMap eventMap = Arguments.createMap();
9392
eventMap.putString("eventName", name);
9493
eventMap.putMap("snapshot", data);
94+
eventMap.putString("path", path);
9595
return eventMap;
9696
}
9797

ios/Firestack/FirestackDatabase.m

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -170,19 +170,20 @@ - (void) setListeningOn:(NSString *) name
170170
{
171171
NSMutableDictionary *listeners = [_listeners mutableCopy];
172172
[listeners setValue:@(handle) forKey:name];
173-
self.listeners = listeners;
173+
_listeners = listeners;
174174
}
175175

176176
- (void) unsetListeningOn:(NSString *) name
177177
{
178178
NSMutableDictionary *listeners = [_listeners mutableCopy];
179179
[listeners removeObjectForKey:name];
180-
self.listeners = listeners;
180+
_listeners = listeners;
181181
}
182182

183183
- (BOOL) isListeningTo:(NSString *) name
184184
{
185-
return [_listeners valueForKey:name] != nil;
185+
id listener = [_listeners valueForKey:name];
186+
return listener != nil;
186187
}
187188

188189
- (BOOL) hasListeners
@@ -350,7 +351,7 @@ @implementation FirestackDatabase
350351
{
351352
FirestackDBReference *r = [self getDBHandle:path];
352353
FIRDatabaseQuery *query = [r getQueryWithModifiers:modifiers];
353-
354+
354355
if (![r isListeningTo:eventName]) {
355356
id withBlock = ^(FIRDataSnapshot * _Nonnull snapshot) {
356357
NSDictionary *props =
@@ -375,12 +376,19 @@ @implementation FirestackDatabase
375376
withCancelBlock:errorBlock];
376377
[r setEventHandler:handle
377378
forName:eventName];
378-
}
379-
380-
callback(@[[NSNull null], @{
379+
380+
[self saveDBHandle:path dbRef:r];
381+
382+
callback(@[[NSNull null], @{
381383
@"result": @"success",
382-
@"handle": path
384+
@"handle": @(handle)
383385
}]);
386+
} else {
387+
callback(@{
388+
@"result": @"exists",
389+
@"msg": @"Listener already exists"
390+
});
391+
}
384392
}
385393

386394
RCT_EXPORT_METHOD(onOnce:(NSString *) path
@@ -397,6 +405,7 @@ @implementation FirestackDatabase
397405
NSDictionary *props = [self snapshotToDict:snapshot];
398406
callback(@[[NSNull null], @{
399407
@"eventName": name,
408+
@"path": path,
400409
@"snapshot": props
401410
}]);
402411
}
@@ -414,17 +423,16 @@ @implementation FirestackDatabase
414423
callback:(RCTResponseSenderBlock) callback)
415424
{
416425
FirestackDBReference *r = [self getDBHandle:path];
417-
418426
if (eventName == nil || [eventName isEqualToString:@""]) {
419427
[r cleanup];
420428
} else {
421-
if ([r isListeningTo:eventName]) {
422-
[r removeEventHandler:eventName];
423-
}
429+
[r removeEventHandler:eventName];
424430
if (![r hasListeners]) {
425431
[self removeDBHandle:path];
426432
}
427433
}
434+
435+
[self saveDBHandle:path dbRef:r];
428436

429437
callback(@[[NSNull null], @{
430438
@"result": @"success",

lib/modules/database.js

Lines changed: 90 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ class DatabaseRef extends ReferenceBase {
121121

122122
this.db = db;
123123
this.query = new DatabaseQuery(this);
124+
this.listeners = {};
124125

125126
// Aliases
126127
this.get = this.getAt;
@@ -184,9 +185,13 @@ class DatabaseRef extends ReferenceBase {
184185
const path = this.dbPath();
185186
const modifiers = this.dbModifiers();
186187
return this.db.on(path, evt, cb)
187-
.then((subscription) => {
188+
.then(({callback, subscriptions}) => {
188189
return promisify('on', FirestackDatabase)(path, modifiers, evt)
189-
.then(() => subscription);
190+
.then(() => {
191+
this.listeners[evt] = subscriptions;
192+
callback(this);
193+
return subscriptions;
194+
})
190195
});
191196
}
192197

@@ -200,7 +205,24 @@ class DatabaseRef extends ReferenceBase {
200205
off(evt='') {
201206
const path = this.dbPath();
202207
return this.db.off(path, evt)
203-
.then(() => promisify('off', FirestackDatabase)(path, evt));
208+
.then(({callback, subscriptions}) => {
209+
return promisify('off', FirestackDatabase)(path, evt)
210+
.then(() => {
211+
this.listeners[evt]
212+
delete this.listeners[evt];
213+
callback(this);
214+
return subscriptions;
215+
})
216+
})
217+
.catch(err => {
218+
console.error('Never get here', err);
219+
})
220+
}
221+
222+
cleanup() {
223+
let promises = Object.keys(this.listeners)
224+
.map(key => this.off(key))
225+
return Promise.all(promises);
204226
}
205227

206228
// Modifiers
@@ -289,7 +311,8 @@ export class Database extends Base {
289311
this.log.debug('Created new Database instance', this.options);
290312

291313
this.persistenceEnabled = false;
292-
this.listener = null;
314+
this.successListener = null;
315+
this.errorListener = null;
293316
this.refs = {};
294317
}
295318

@@ -317,69 +340,97 @@ export class Database extends Base {
317340

318341
handleDatabaseEvent(evt) {
319342
const body = evt.body;
320-
const path = evt.path;
343+
const path = body.path;
321344
const evtName = body.eventName;
322345

323346
const subscriptions = dbSubscriptions[path];
324347

325348
if (subscriptions) {
326-
const cb = subscriptions[evtName];
327-
if (cb && typeof(cb) === 'function') {
328-
const snap = new DataSnapshot(this, body.snapshot);
329-
this.log.debug('database_event received', path, evtName, snap);
330-
cb(snap, body);
331-
}
349+
const cbs = subscriptions[evtName];
350+
cbs.forEach(cb => {
351+
if (cb && typeof(cb) === 'function') {
352+
const snap = new DataSnapshot(this, body.snapshot);
353+
this.log.debug('database_event received', path, evtName, snap);
354+
cb(snap, body);
355+
}
356+
});
332357
}
333358
}
334359

360+
handleDatabaseError(evt) {
361+
this.log.debug('handleDatabaseError ->', evt);
362+
}
363+
335364
on(path, evt, cb) {
336365
const key = this._pathKey(path);
337366

338-
if (!this.listener) {
339-
this.listener = FirestackDatabaseEvt
367+
if (!dbSubscriptions[key]) {
368+
dbSubscriptions[key] = {};
369+
}
370+
371+
if (!dbSubscriptions[key][evt]) {
372+
dbSubscriptions[key][evt] = [];
373+
}
374+
dbSubscriptions[key][evt].push(cb);
375+
376+
if (!this.successListener) {
377+
this.successListener = FirestackDatabaseEvt
340378
.addListener(
341379
'database_event',
342380
this.handleDatabaseEvent.bind(this));
343381
}
344382

345-
if (!dbSubscriptions[key]) {
346-
dbSubscriptions[key] = {};
383+
if (!this.errorListener) {
384+
this.errorListener = FirestackDatabaseEvt
385+
.addListener(
386+
'database_error',
387+
this.handleDatabaseError.bind(this));
347388
}
348389

349-
dbSubscriptions[key][evt] = cb;
350-
return Promise.resolve(this.listener);
390+
const callback = (ref) => {
391+
const key = this._pathKey(path);
392+
this.refs[key] = ref;
393+
}
394+
const subscriptions = [this.successListener, this.errorListener];
395+
return Promise.resolve({callback, subscriptions});
351396
}
352397

353398
off(path, evt) {
354-
if (this.listener) {
355-
const key = this._pathKey(path);
356-
// Remove subscription
357-
if (dbSubscriptions[key]) {
358-
if (dbSubscriptions[key][evt]) {
359-
delete dbSubscriptions[key][evt];
399+
const key = this._pathKey(path);
400+
// Remove subscription
401+
if (dbSubscriptions[key]) {
402+
if (dbSubscriptions[key][evt]) {
403+
delete dbSubscriptions[key][evt];
404+
}
405+
if (Object.keys(dbSubscriptions[key]).length <= 0) {
406+
// there are no more subscriptions
407+
// so we can unwatch
408+
delete dbSubscriptions[key]
409+
}
410+
if (Object.keys(dbSubscriptions).length == 0) {
411+
if (this.successListener) {
412+
this.successListener.remove();
413+
this.successListener = null;
360414
}
361-
362-
if (Object.keys(dbSubscriptions).length <= 0) {
363-
// there are no more subscriptions
364-
// so we can unwatch
365-
this.listener.remove();
366-
delete dbSubscriptions[key]
415+
if (this.errorListener) {
416+
this.errorListener.remove();
417+
this.errorListener = null;
367418
}
368419
}
369420
}
370-
return Promise.resolve(this.listener);
421+
const callback = (ref) => {
422+
const key = this._pathKey(path);
423+
delete this.refs[key];
424+
}
425+
const subscriptions = [this.successListener, this.errorListener];
426+
return Promise.resolve({callback, subscriptions});
371427
}
372428

373429
cleanup() {
374-
Object.keys(dbSubscriptions).forEach(key => {
375-
Object.keys(dbSubscriptions[key]).forEach(evt => {
376-
delete dbSubscriptions[key][evt];
377-
})
378-
});
379-
this.listener.remove();
380-
Object.keys(this.refs).forEach(path => {
381-
delete this.refs[path];
382-
});
430+
let promises = Object.keys(this.refs)
431+
.map(key => this.refs[key])
432+
.map(ref => ref.cleanup())
433+
return Promise.all(promises);
383434
}
384435

385436
release(...path) {

0 commit comments

Comments
 (0)