@dream11mobile/react-native-firebase
Version:
A well tested, feature rich Firebase implementation for React Native, supporting iOS & Android. Individual module support for Admob, Analytics, Auth, Crash Reporting, Cloud Firestore, Database, Dynamic Links, Functions, Messaging (FCM), Remote Config, Sto
176 lines (140 loc) • 6.7 kB
JavaScript
/**
*
* DocumentReference representation wrapper
*/
import SnapshotError from './SnapshotError';
import DocumentSnapshot from './DocumentSnapshot';
import CollectionReference from './CollectionReference';
import { parseUpdateArgs } from './utils';
import { buildNativeMap } from './utils/serialize';
import { getNativeModule } from '../../utils/native';
import { firestoreAutoId, isFunction, isObject } from '../../utils';
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
/**
* @class DocumentReference
*/
export default class DocumentReference {
constructor(firestore, documentPath) {
this._documentPath = documentPath;
this._firestore = firestore;
}
get firestore() {
return this._firestore;
}
get id() {
return this._documentPath.id;
}
get parent() {
const parentPath = this._documentPath.parent(); // $FlowExpectedError: parentPath can never be null
return new CollectionReference(this._firestore, parentPath);
}
get path() {
return this._documentPath.relativeName;
}
collection(collectionPath) {
const path = this._documentPath.child(collectionPath);
if (!path.isCollection) {
throw new Error('Argument "collectionPath" must point to a collection.');
}
return new CollectionReference(this._firestore, path);
}
delete() {
return getNativeModule(this._firestore).documentDelete(this.path);
}
get(options) {
if (options) {
if (!isObject(options)) {
return Promise.reject(new Error('DocumentReference.get failed: First argument must be an object.'));
}
if (options.source && options.source !== 'default' && options.source !== 'server' && options.source !== 'cache') {
return Promise.reject(new Error('DocumentReference.get failed: GetOptions.source must be one of `default`, `server` or `cache`.'));
}
}
return getNativeModule(this._firestore).documentGet(this.path, options).then(result => new DocumentSnapshot(this._firestore, result));
}
onSnapshot(optionsOrObserverOrOnNext, observerOrOnNextOrOnError, onError) {
let observer;
let docListenOptions = {}; // Called with: onNext, ?onError
if (isFunction(optionsOrObserverOrOnNext)) {
if (observerOrOnNextOrOnError && !isFunction(observerOrOnNextOrOnError)) {
throw new Error('DocumentReference.onSnapshot failed: Second argument must be a valid function.');
} // $FlowExpectedError: Not coping with the overloaded method signature
observer = {
next: optionsOrObserverOrOnNext,
error: observerOrOnNextOrOnError
};
} else if (optionsOrObserverOrOnNext && isObject(optionsOrObserverOrOnNext)) {
// Called with: Observer
if (optionsOrObserverOrOnNext.next) {
if (isFunction(optionsOrObserverOrOnNext.next)) {
if (optionsOrObserverOrOnNext.error && !isFunction(optionsOrObserverOrOnNext.error)) {
throw new Error('DocumentReference.onSnapshot failed: Observer.error must be a valid function.');
} // $FlowExpectedError: Not coping with the overloaded method signature
observer = {
next: optionsOrObserverOrOnNext.next,
error: optionsOrObserverOrOnNext.error
};
} else {
throw new Error('DocumentReference.onSnapshot failed: Observer.next must be a valid function.');
}
} else if (Object.prototype.hasOwnProperty.call(optionsOrObserverOrOnNext, 'includeMetadataChanges')) {
docListenOptions = optionsOrObserverOrOnNext; // Called with: Options, onNext, ?onError
if (isFunction(observerOrOnNextOrOnError)) {
if (onError && !isFunction(onError)) {
throw new Error('DocumentReference.onSnapshot failed: Third argument must be a valid function.');
} // $FlowExpectedError: Not coping with the overloaded method signature
observer = {
next: observerOrOnNextOrOnError,
error: onError
}; // Called with Options, Observer
} else if (observerOrOnNextOrOnError && isObject(observerOrOnNextOrOnError) && observerOrOnNextOrOnError.next) {
if (isFunction(observerOrOnNextOrOnError.next)) {
if (observerOrOnNextOrOnError.error && !isFunction(observerOrOnNextOrOnError.error)) {
throw new Error('DocumentReference.onSnapshot failed: Observer.error must be a valid function.');
}
observer = {
next: observerOrOnNextOrOnError.next,
error: observerOrOnNextOrOnError.error
};
} else {
throw new Error('DocumentReference.onSnapshot failed: Observer.next must be a valid function.');
}
} else {
throw new Error('DocumentReference.onSnapshot failed: Second argument must be a function or observer.');
}
} else {
throw new Error('DocumentReference.onSnapshot failed: First argument must be a function, observer or options.');
}
} else {
throw new Error('DocumentReference.onSnapshot failed: Called with invalid arguments.');
}
const listenerId = firestoreAutoId();
const listener = nativeDocumentSnapshot => {
const documentSnapshot = new DocumentSnapshot(this.firestore, nativeDocumentSnapshot);
observer.next(documentSnapshot);
}; // Listen to snapshot events
const snapshotSubscription = SharedEventEmitter.addListener(getAppEventName(this._firestore, `onDocumentSnapshot:${listenerId}`), listener);
let unsubscribe; // listen for snapshot error events
const errorSubscription = SharedEventEmitter.addListener(getAppEventName(this._firestore, `onDocumentSnapshotError:${listenerId}`), e => {
if (unsubscribe) unsubscribe();
const error = new SnapshotError(e);
if (observer.error) observer.error(error);else this.firestore.log.error(error);
}); // Add the native listener
getNativeModule(this._firestore).documentOnSnapshot(this.path, listenerId, docListenOptions); // return an unsubscribe method
unsubscribe = () => {
snapshotSubscription.remove();
errorSubscription.remove(); // cancel native listener
getNativeModule(this._firestore).documentOffSnapshot(this.path, listenerId);
};
return unsubscribe;
}
set(data, options) {
const nativeData = buildNativeMap(data);
return getNativeModule(this._firestore).documentSet(this.path, nativeData, options);
}
update(...args) {
const data = parseUpdateArgs(args, 'DocumentReference.update');
const nativeData = buildNativeMap(data);
return getNativeModule(this._firestore).documentUpdate(this.path, nativeData);
}
}