|
|
|
|
@@ -2,7 +2,7 @@
|
|
|
|
|
* @flow
|
|
|
|
|
* Database Reference representation wrapper
|
|
|
|
|
*/
|
|
|
|
|
import Query from './query.js';
|
|
|
|
|
import Query from './query';
|
|
|
|
|
import Snapshot from './snapshot';
|
|
|
|
|
import Disconnect from './disconnect';
|
|
|
|
|
import { getLogger } from '../../utils/log';
|
|
|
|
|
@@ -41,11 +41,11 @@ const ReferenceEventTypes = {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
type DatabaseListener = {
|
|
|
|
|
listenerId: number;
|
|
|
|
|
eventName: string;
|
|
|
|
|
successCallback: Function;
|
|
|
|
|
failureCallback?: Function;
|
|
|
|
|
}
|
|
|
|
|
listenerId: number,
|
|
|
|
|
eventName: string,
|
|
|
|
|
successCallback: Function,
|
|
|
|
|
failureCallback?: Function,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @typedef {String} ReferenceLocation - Path to location in the database, relative
|
|
|
|
|
@@ -80,7 +80,11 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
_query: Query;
|
|
|
|
|
_refListeners: { [listenerId: number]: DatabaseListener };
|
|
|
|
|
|
|
|
|
|
constructor(database: Database, path: string, existingModifiers?: Array<DatabaseModifier>) {
|
|
|
|
|
constructor(
|
|
|
|
|
database: Database,
|
|
|
|
|
path: string,
|
|
|
|
|
existingModifiers?: Array<DatabaseModifier>
|
|
|
|
|
) {
|
|
|
|
|
super(path);
|
|
|
|
|
this._promise = null;
|
|
|
|
|
this._refListeners = {};
|
|
|
|
|
@@ -100,7 +104,12 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
* @returns {*}
|
|
|
|
|
*/
|
|
|
|
|
keepSynced(bool: boolean): Promise<void> {
|
|
|
|
|
return getNativeModule(this._database).keepSynced(this._getRefKey(), this.path, this._query.getModifiers(), bool);
|
|
|
|
|
return getNativeModule(this._database).keepSynced(
|
|
|
|
|
this._getRefKey(),
|
|
|
|
|
this.path,
|
|
|
|
|
this._query.getModifiers(),
|
|
|
|
|
bool
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -113,8 +122,11 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
*/
|
|
|
|
|
set(value: any, onComplete?: Function): Promise<void> {
|
|
|
|
|
return promiseOrCallback(
|
|
|
|
|
getNativeModule(this._database).set(this.path, this._serializeAnyType(value)),
|
|
|
|
|
onComplete,
|
|
|
|
|
getNativeModule(this._database).set(
|
|
|
|
|
this.path,
|
|
|
|
|
this._serializeAnyType(value)
|
|
|
|
|
),
|
|
|
|
|
onComplete
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -126,12 +138,15 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
* @param onComplete
|
|
|
|
|
* @returns {Promise}
|
|
|
|
|
*/
|
|
|
|
|
setPriority(priority: string | number | null, onComplete?: Function): Promise<void> {
|
|
|
|
|
setPriority(
|
|
|
|
|
priority: string | number | null,
|
|
|
|
|
onComplete?: Function
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
const _priority = this._serializeAnyType(priority);
|
|
|
|
|
|
|
|
|
|
return promiseOrCallback(
|
|
|
|
|
getNativeModule(this._database).setPriority(this.path, _priority),
|
|
|
|
|
onComplete,
|
|
|
|
|
onComplete
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -144,13 +159,21 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
* @param onComplete
|
|
|
|
|
* @returns {Promise}
|
|
|
|
|
*/
|
|
|
|
|
setWithPriority(value: any, priority: string | number | null, onComplete?: Function): Promise<void> {
|
|
|
|
|
setWithPriority(
|
|
|
|
|
value: any,
|
|
|
|
|
priority: string | number | null,
|
|
|
|
|
onComplete?: Function
|
|
|
|
|
): Promise<void> {
|
|
|
|
|
const _value = this._serializeAnyType(value);
|
|
|
|
|
const _priority = this._serializeAnyType(priority);
|
|
|
|
|
|
|
|
|
|
return promiseOrCallback(
|
|
|
|
|
getNativeModule(this._database).setWithPriority(this.path, _value, _priority),
|
|
|
|
|
onComplete,
|
|
|
|
|
getNativeModule(this._database).setWithPriority(
|
|
|
|
|
this.path,
|
|
|
|
|
_value,
|
|
|
|
|
_priority
|
|
|
|
|
),
|
|
|
|
|
onComplete
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -167,7 +190,7 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
|
|
|
|
|
return promiseOrCallback(
|
|
|
|
|
getNativeModule(this._database).update(this.path, value),
|
|
|
|
|
onComplete,
|
|
|
|
|
onComplete
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -181,7 +204,7 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
remove(onComplete?: Function): Promise<void> {
|
|
|
|
|
return promiseOrCallback(
|
|
|
|
|
getNativeModule(this._database).remove(this.path),
|
|
|
|
|
onComplete,
|
|
|
|
|
onComplete
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -196,10 +219,12 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
transaction(
|
|
|
|
|
transactionUpdate: Function,
|
|
|
|
|
onComplete: (error: ?Error, committed: boolean, snapshot: ?Snapshot) => *,
|
|
|
|
|
applyLocally: boolean = false,
|
|
|
|
|
applyLocally: boolean = false
|
|
|
|
|
) {
|
|
|
|
|
if (!isFunction(transactionUpdate)) {
|
|
|
|
|
return Promise.reject(new Error('Missing transactionUpdate function argument.'));
|
|
|
|
|
return Promise.reject(
|
|
|
|
|
new Error('Missing transactionUpdate function argument.')
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
@@ -213,15 +238,22 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (error) return reject(error);
|
|
|
|
|
return resolve({ committed, snapshot: new Snapshot(this, snapshotData) });
|
|
|
|
|
return resolve({
|
|
|
|
|
committed,
|
|
|
|
|
snapshot: new Snapshot(this, snapshotData),
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// start the transaction natively
|
|
|
|
|
this._database._transactionHandler.add(this, transactionUpdate, onCompleteWrapper, applyLocally);
|
|
|
|
|
this._database._transactionHandler.add(
|
|
|
|
|
this,
|
|
|
|
|
transactionUpdate,
|
|
|
|
|
onCompleteWrapper,
|
|
|
|
|
applyLocally
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @param eventName
|
|
|
|
|
@@ -234,21 +266,24 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
eventName: string = 'value',
|
|
|
|
|
successCallback: (snapshot: Object) => void,
|
|
|
|
|
cancelOrContext: (error: FirebaseError) => void,
|
|
|
|
|
context?: Object,
|
|
|
|
|
context?: Object
|
|
|
|
|
) {
|
|
|
|
|
return getNativeModule(this._database).once(this._getRefKey(), this.path, this._query.getModifiers(), eventName)
|
|
|
|
|
return getNativeModule(this._database)
|
|
|
|
|
.once(this._getRefKey(), this.path, this._query.getModifiers(), eventName)
|
|
|
|
|
.then(({ snapshot }) => {
|
|
|
|
|
const _snapshot = new Snapshot(this, snapshot);
|
|
|
|
|
|
|
|
|
|
if (isFunction(successCallback)) {
|
|
|
|
|
if (isObject(cancelOrContext)) successCallback.bind(cancelOrContext)(_snapshot);
|
|
|
|
|
if (context && isObject(context)) successCallback.bind(context)(_snapshot);
|
|
|
|
|
if (isObject(cancelOrContext))
|
|
|
|
|
successCallback.bind(cancelOrContext)(_snapshot);
|
|
|
|
|
if (context && isObject(context))
|
|
|
|
|
successCallback.bind(context)(_snapshot);
|
|
|
|
|
successCallback(_snapshot);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _snapshot;
|
|
|
|
|
})
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
.catch(error => {
|
|
|
|
|
if (isFunction(cancelOrContext)) return cancelOrContext(error);
|
|
|
|
|
return error;
|
|
|
|
|
});
|
|
|
|
|
@@ -262,19 +297,27 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
*/
|
|
|
|
|
push(value: any, onComplete?: Function): Reference | Promise<void> {
|
|
|
|
|
if (value === null || value === undefined) {
|
|
|
|
|
return new Reference(this._database, `${this.path}/${generatePushID(this._database._serverTimeOffset)}`);
|
|
|
|
|
return new Reference(
|
|
|
|
|
this._database,
|
|
|
|
|
`${this.path}/${generatePushID(this._database._serverTimeOffset)}`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const newRef = new Reference(this._database, `${this.path}/${generatePushID(this._database._serverTimeOffset)}`);
|
|
|
|
|
const newRef = new Reference(
|
|
|
|
|
this._database,
|
|
|
|
|
`${this.path}/${generatePushID(this._database._serverTimeOffset)}`
|
|
|
|
|
);
|
|
|
|
|
const promise = newRef.set(value);
|
|
|
|
|
|
|
|
|
|
// if callback provided then internally call the set promise with value
|
|
|
|
|
if (isFunction(onComplete)) {
|
|
|
|
|
return promise
|
|
|
|
|
// $FlowBug: Reports that onComplete can change to null despite the null check: https://github.com/facebook/flow/issues/1655
|
|
|
|
|
.then(() => onComplete(null, newRef))
|
|
|
|
|
// $FlowBug: Reports that onComplete can change to null despite the null check: https://github.com/facebook/flow/issues/1655
|
|
|
|
|
.catch(error => onComplete(error, null));
|
|
|
|
|
return (
|
|
|
|
|
promise
|
|
|
|
|
// $FlowBug: Reports that onComplete can change to null despite the null check: https://github.com/facebook/flow/issues/1655
|
|
|
|
|
.then(() => onComplete(null, newRef))
|
|
|
|
|
// $FlowBug: Reports that onComplete can change to null despite the null check: https://github.com/facebook/flow/issues/1655
|
|
|
|
|
.catch(error => onComplete(error, null))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// otherwise attach promise to 'thenable' reference and return the
|
|
|
|
|
@@ -327,7 +370,11 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
* @returns {Reference}
|
|
|
|
|
*/
|
|
|
|
|
orderBy(name: string, key?: string): Reference {
|
|
|
|
|
const newRef = new Reference(this._database, this.path, this._query.getModifiers());
|
|
|
|
|
const newRef = new Reference(
|
|
|
|
|
this._database,
|
|
|
|
|
this.path,
|
|
|
|
|
this._query.getModifiers()
|
|
|
|
|
);
|
|
|
|
|
newRef._query.orderBy(name, key);
|
|
|
|
|
return newRef;
|
|
|
|
|
}
|
|
|
|
|
@@ -361,7 +408,11 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
* @returns {Reference}
|
|
|
|
|
*/
|
|
|
|
|
limit(name: string, limit: number): Reference {
|
|
|
|
|
const newRef = new Reference(this._database, this.path, this._query.getModifiers());
|
|
|
|
|
const newRef = new Reference(
|
|
|
|
|
this._database,
|
|
|
|
|
this.path,
|
|
|
|
|
this._query.getModifiers()
|
|
|
|
|
);
|
|
|
|
|
newRef._query.limit(name, limit);
|
|
|
|
|
return newRef;
|
|
|
|
|
}
|
|
|
|
|
@@ -408,7 +459,11 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
* @returns {Reference}
|
|
|
|
|
*/
|
|
|
|
|
filter(name: string, value: any, key?: string): Reference {
|
|
|
|
|
const newRef = new Reference(this._database, this.path, this._query.getModifiers());
|
|
|
|
|
const newRef = new Reference(
|
|
|
|
|
this._database,
|
|
|
|
|
this.path,
|
|
|
|
|
this._query.getModifiers()
|
|
|
|
|
);
|
|
|
|
|
newRef._query.filter(name, value, key);
|
|
|
|
|
return newRef;
|
|
|
|
|
}
|
|
|
|
|
@@ -450,10 +505,12 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
* {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#isEqual}
|
|
|
|
|
*/
|
|
|
|
|
isEqual(otherRef: Reference): boolean {
|
|
|
|
|
return !!otherRef
|
|
|
|
|
&& otherRef.constructor === Reference
|
|
|
|
|
&& otherRef.key === this.key
|
|
|
|
|
&& this._query.queryIdentifier() === otherRef._query.queryIdentifier();
|
|
|
|
|
return (
|
|
|
|
|
!!otherRef &&
|
|
|
|
|
otherRef.constructor === Reference &&
|
|
|
|
|
otherRef.key === this.key &&
|
|
|
|
|
this._query.queryIdentifier() === otherRef._query.queryIdentifier()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -468,7 +525,10 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
*/
|
|
|
|
|
get parent(): Reference | null {
|
|
|
|
|
if (this.path === '/') return null;
|
|
|
|
|
return new Reference(this._database, this.path.substring(0, this.path.lastIndexOf('/')));
|
|
|
|
|
return new Reference(
|
|
|
|
|
this._database,
|
|
|
|
|
this.path.substring(0, this.path.lastIndexOf('/'))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -495,20 +555,23 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
* Access then method of promise if set
|
|
|
|
|
* @return {*}
|
|
|
|
|
*/
|
|
|
|
|
then(fnResolve: (any) => any, fnReject: (any) => any) {
|
|
|
|
|
then(fnResolve: any => any, fnReject: any => any) {
|
|
|
|
|
if (isFunction(fnResolve) && this._promise && this._promise.then) {
|
|
|
|
|
return this._promise.then.bind(this._promise)((result) => {
|
|
|
|
|
this._promise = null;
|
|
|
|
|
return fnResolve(result);
|
|
|
|
|
}, (possibleErr) => {
|
|
|
|
|
this._promise = null;
|
|
|
|
|
return this._promise.then.bind(this._promise)(
|
|
|
|
|
result => {
|
|
|
|
|
this._promise = null;
|
|
|
|
|
return fnResolve(result);
|
|
|
|
|
},
|
|
|
|
|
possibleErr => {
|
|
|
|
|
this._promise = null;
|
|
|
|
|
|
|
|
|
|
if (isFunction(fnReject)) {
|
|
|
|
|
return fnReject(possibleErr);
|
|
|
|
|
if (isFunction(fnReject)) {
|
|
|
|
|
return fnReject(possibleErr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw possibleErr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw possibleErr;
|
|
|
|
|
});
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw new Error("Cannot read property 'then' of undefined.");
|
|
|
|
|
@@ -518,9 +581,9 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
* Access catch method of promise if set
|
|
|
|
|
* @return {*}
|
|
|
|
|
*/
|
|
|
|
|
catch(fnReject: (any) => any) {
|
|
|
|
|
catch(fnReject: any => any) {
|
|
|
|
|
if (isFunction(fnReject) && this._promise && this._promise.catch) {
|
|
|
|
|
return this._promise.catch.bind(this._promise)((possibleErr) => {
|
|
|
|
|
return this._promise.catch.bind(this._promise)(possibleErr => {
|
|
|
|
|
this._promise = null;
|
|
|
|
|
return fnReject(possibleErr);
|
|
|
|
|
});
|
|
|
|
|
@@ -539,7 +602,9 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
* @return {string}
|
|
|
|
|
*/
|
|
|
|
|
_getRegistrationKey(eventType: string): string {
|
|
|
|
|
return `$${this._database.app.name}$/${this.path}$${this._query.queryIdentifier()}$${listeners}$${eventType}`;
|
|
|
|
|
return `$${this._database.app.name}$/${
|
|
|
|
|
this.path
|
|
|
|
|
}$${this._query.queryIdentifier()}$${listeners}$${eventType}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -550,7 +615,9 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
_getRefKey(): string {
|
|
|
|
|
return `$${this._database.app.name}$/${this.path}$${this._query.queryIdentifier()}`;
|
|
|
|
|
return `$${this._database.app.name}$/${
|
|
|
|
|
this.path
|
|
|
|
|
}$${this._query.queryIdentifier()}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -562,7 +629,6 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
this._promise = promise;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @param obj
|
|
|
|
|
@@ -623,34 +689,65 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
*
|
|
|
|
|
* {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#on}
|
|
|
|
|
*/
|
|
|
|
|
on(eventType: string, callback: (Snapshot) => any, cancelCallbackOrContext?: (Object) => any | Object, context?: Object): Function {
|
|
|
|
|
on(
|
|
|
|
|
eventType: string,
|
|
|
|
|
callback: Snapshot => any,
|
|
|
|
|
cancelCallbackOrContext?: Object => any | Object,
|
|
|
|
|
context?: Object
|
|
|
|
|
): Function {
|
|
|
|
|
if (!eventType) {
|
|
|
|
|
throw new Error('Query.on failed: Function called with 0 arguments. Expects at least 2.');
|
|
|
|
|
throw new Error(
|
|
|
|
|
'Query.on failed: Function called with 0 arguments. Expects at least 2.'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isString(eventType) || !ReferenceEventTypes[eventType]) {
|
|
|
|
|
throw new Error(`Query.on failed: First argument must be a valid string event type: "${Object.keys(ReferenceEventTypes).join(', ')}"`);
|
|
|
|
|
throw new Error(
|
|
|
|
|
`Query.on failed: First argument must be a valid string event type: "${Object.keys(
|
|
|
|
|
ReferenceEventTypes
|
|
|
|
|
).join(', ')}"`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!callback) {
|
|
|
|
|
throw new Error('Query.on failed: Function called with 1 argument. Expects at least 2.');
|
|
|
|
|
throw new Error(
|
|
|
|
|
'Query.on failed: Function called with 1 argument. Expects at least 2.'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isFunction(callback)) {
|
|
|
|
|
throw new Error('Query.on failed: Second argument must be a valid function.');
|
|
|
|
|
throw new Error(
|
|
|
|
|
'Query.on failed: Second argument must be a valid function.'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cancelCallbackOrContext && !isFunction(cancelCallbackOrContext) && !isObject(context) && !isObject(cancelCallbackOrContext)) {
|
|
|
|
|
throw new Error('Query.on failed: Function called with 3 arguments, but third optional argument `cancelCallbackOrContext` was not a function.');
|
|
|
|
|
if (
|
|
|
|
|
cancelCallbackOrContext &&
|
|
|
|
|
!isFunction(cancelCallbackOrContext) &&
|
|
|
|
|
!isObject(context) &&
|
|
|
|
|
!isObject(cancelCallbackOrContext)
|
|
|
|
|
) {
|
|
|
|
|
throw new Error(
|
|
|
|
|
'Query.on failed: Function called with 3 arguments, but third optional argument `cancelCallbackOrContext` was not a function.'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cancelCallbackOrContext && !isFunction(cancelCallbackOrContext) && context) {
|
|
|
|
|
throw new Error('Query.on failed: Function called with 4 arguments, but third optional argument `cancelCallbackOrContext` was not a function.');
|
|
|
|
|
if (
|
|
|
|
|
cancelCallbackOrContext &&
|
|
|
|
|
!isFunction(cancelCallbackOrContext) &&
|
|
|
|
|
context
|
|
|
|
|
) {
|
|
|
|
|
throw new Error(
|
|
|
|
|
'Query.on failed: Function called with 4 arguments, but third optional argument `cancelCallbackOrContext` was not a function.'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const eventRegistrationKey = this._getRegistrationKey(eventType);
|
|
|
|
|
const registrationCancellationKey = `${eventRegistrationKey}$cancelled`;
|
|
|
|
|
const _context = (cancelCallbackOrContext && !isFunction(cancelCallbackOrContext)) ? cancelCallbackOrContext : context;
|
|
|
|
|
const _context =
|
|
|
|
|
cancelCallbackOrContext && !isFunction(cancelCallbackOrContext)
|
|
|
|
|
? cancelCallbackOrContext
|
|
|
|
|
: context;
|
|
|
|
|
const registrationObj = {
|
|
|
|
|
eventType,
|
|
|
|
|
ref: this,
|
|
|
|
|
@@ -677,7 +774,9 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
appName: this._database.app.name,
|
|
|
|
|
eventType: `${eventType}$cancelled`,
|
|
|
|
|
eventRegistrationKey: registrationCancellationKey,
|
|
|
|
|
listener: _context ? cancelCallbackOrContext.bind(_context) : cancelCallbackOrContext,
|
|
|
|
|
listener: _context
|
|
|
|
|
? cancelCallbackOrContext.bind(_context)
|
|
|
|
|
: cancelCallbackOrContext,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -724,18 +823,29 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
if (!arguments.length) {
|
|
|
|
|
// Firebase Docs:
|
|
|
|
|
// if no eventType or callback is specified, all callbacks for the Reference will be removed.
|
|
|
|
|
return SyncTree.removeListenersForRegistrations(SyncTree.getRegistrationsByPath(this.path));
|
|
|
|
|
return SyncTree.removeListenersForRegistrations(
|
|
|
|
|
SyncTree.getRegistrationsByPath(this.path)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* VALIDATE ARGS
|
|
|
|
|
*/
|
|
|
|
|
if (eventType && (!isString(eventType) || !ReferenceEventTypes[eventType])) {
|
|
|
|
|
throw new Error(`Query.off failed: First argument must be a valid string event type: "${Object.keys(ReferenceEventTypes).join(', ')}"`);
|
|
|
|
|
if (
|
|
|
|
|
eventType &&
|
|
|
|
|
(!isString(eventType) || !ReferenceEventTypes[eventType])
|
|
|
|
|
) {
|
|
|
|
|
throw new Error(
|
|
|
|
|
`Query.off failed: First argument must be a valid string event type: "${Object.keys(
|
|
|
|
|
ReferenceEventTypes
|
|
|
|
|
).join(', ')}"`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (originalCallback && !isFunction(originalCallback)) {
|
|
|
|
|
throw new Error('Query.off failed: Function called with 2 arguments, but second optional argument was not a function.');
|
|
|
|
|
throw new Error(
|
|
|
|
|
'Query.off failed: Function called with 2 arguments, but second optional argument was not a function.'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Firebase Docs:
|
|
|
|
|
@@ -745,7 +855,11 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
// remove the callback.
|
|
|
|
|
// Remove only a single registration
|
|
|
|
|
if (eventType && originalCallback) {
|
|
|
|
|
const registration = SyncTree.getOneByPathEventListener(this.path, eventType, originalCallback);
|
|
|
|
|
const registration = SyncTree.getOneByPathEventListener(
|
|
|
|
|
this.path,
|
|
|
|
|
eventType,
|
|
|
|
|
originalCallback
|
|
|
|
|
);
|
|
|
|
|
if (!registration) return [];
|
|
|
|
|
|
|
|
|
|
// remove the paired cancellation registration if any exist
|
|
|
|
|
@@ -753,15 +867,20 @@ export default class Reference extends ReferenceBase {
|
|
|
|
|
|
|
|
|
|
// remove only the first registration to match firebase web sdk
|
|
|
|
|
// call multiple times to remove multiple registrations
|
|
|
|
|
return SyncTree.removeListenerRegistrations(originalCallback, [registration]);
|
|
|
|
|
return SyncTree.removeListenerRegistrations(originalCallback, [
|
|
|
|
|
registration,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Firebase Docs:
|
|
|
|
|
// If a callback is not specified, all callbacks for the specified eventType will be removed.
|
|
|
|
|
const registrations = SyncTree.getRegistrationsByPathEvent(this.path, eventType);
|
|
|
|
|
const registrations = SyncTree.getRegistrationsByPathEvent(
|
|
|
|
|
this.path,
|
|
|
|
|
eventType
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
SyncTree.removeListenersForRegistrations(
|
|
|
|
|
SyncTree.getRegistrationsByPathEvent(this.path, `${eventType}$cancelled`),
|
|
|
|
|
SyncTree.getRegistrationsByPathEvent(this.path, `${eventType}$cancelled`)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return SyncTree.removeListenersForRegistrations(registrations);
|
|
|
|
|
|