mirror of
https://github.com/zhigang1992/react-native-firebase.git
synced 2026-04-23 12:06:47 +08:00
merge master into omer_links
This commit is contained in:
@@ -5,12 +5,21 @@
|
||||
import CollectionReference from './CollectionReference';
|
||||
import DocumentSnapshot from './DocumentSnapshot';
|
||||
import Path from './Path';
|
||||
import { firestoreAutoId } from '../../utils';
|
||||
import { firestoreAutoId, isFunction, isObject, isString } from '../../utils';
|
||||
|
||||
export type WriteOptions = {
|
||||
merge?: boolean,
|
||||
}
|
||||
|
||||
type DocumentListenOptions = {
|
||||
includeMetadataChanges: boolean,
|
||||
}
|
||||
|
||||
type Observer = {
|
||||
next: (DocumentSnapshot) => void,
|
||||
error?: (Object) => void,
|
||||
}
|
||||
|
||||
/**
|
||||
* @class DocumentReference
|
||||
*/
|
||||
@@ -60,13 +69,64 @@ export default class DocumentReference {
|
||||
.then(result => new DocumentSnapshot(this._firestore, result));
|
||||
}
|
||||
|
||||
onSnapshot(onNext: Function, onError?: Function): () => void {
|
||||
// TODO: Validation
|
||||
onSnapshot(
|
||||
optionsOrObserverOrOnNext: DocumentListenOptions | Observer | (DocumentSnapshot) => void,
|
||||
observerOrOnNextOrOnError?: Observer | (DocumentSnapshot) => void | (Object) => void,
|
||||
onError?: (Object) => void
|
||||
) {
|
||||
let observer = {};
|
||||
let docListenOptions = {};
|
||||
// Called with: onNext, ?onError
|
||||
if (isFunction(optionsOrObserverOrOnNext)) {
|
||||
observer.next = optionsOrObserverOrOnNext;
|
||||
if (observerOrOnNextOrOnError && !isFunction(observerOrOnNextOrOnError)) {
|
||||
throw new Error('DocumentReference.onSnapshot failed: Second argument must be a valid function.');
|
||||
}
|
||||
observer.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.');
|
||||
}
|
||||
observer = optionsOrObserverOrOnNext;
|
||||
} else {
|
||||
throw new Error('DocumentReference.onSnapshot failed: Observer.next must be a valid function.');
|
||||
}
|
||||
} else if (optionsOrObserverOrOnNext.includeMetadataChanges) {
|
||||
docListenOptions = optionsOrObserverOrOnNext;
|
||||
// Called with: Options, onNext, ?onError
|
||||
if (isFunction(observerOrOnNextOrOnError)) {
|
||||
observer.next = observerOrOnNextOrOnError;
|
||||
if (onError && !isFunction(onError)) {
|
||||
throw new Error('DocumentReference.onSnapshot failed: Third argument must be a valid function.');
|
||||
}
|
||||
observer.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 = observerOrOnNextOrOnError;
|
||||
} 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, nativeDocumentSnapshot);
|
||||
onNext(documentSnapshot);
|
||||
observer.next(documentSnapshot);
|
||||
};
|
||||
|
||||
// Listen to snapshot events
|
||||
@@ -76,16 +136,16 @@ export default class DocumentReference {
|
||||
);
|
||||
|
||||
// Listen for snapshot error events
|
||||
if (onError) {
|
||||
if (observer.error) {
|
||||
this._firestore.on(
|
||||
this._firestore._getAppEventName(`onDocumentSnapshotError:${listenerId}`),
|
||||
onError,
|
||||
observer.error,
|
||||
);
|
||||
}
|
||||
|
||||
// Add the native listener
|
||||
this._firestore._native
|
||||
.documentOnSnapshot(this.path, listenerId);
|
||||
.documentOnSnapshot(this.path, listenerId, docListenOptions);
|
||||
|
||||
// Return an unsubscribe method
|
||||
return this._offDocumentSnapshot.bind(this, listenerId, listener);
|
||||
@@ -96,7 +156,25 @@ export default class DocumentReference {
|
||||
.documentSet(this.path, data, writeOptions);
|
||||
}
|
||||
|
||||
update(data: Object): Promise<void> {
|
||||
update(...args: Object | string[]): Promise<void> {
|
||||
let data = {};
|
||||
if (args.length === 1) {
|
||||
if (!isObject(args[0])) {
|
||||
throw new Error('DocumentReference.update failed: If using a single argument, it must be an object.');
|
||||
}
|
||||
data = args[0];
|
||||
} else if (args.length % 2 === 1) {
|
||||
throw new Error('DocumentReference.update failed: Must have either a single object argument, or equal numbers of key/value pairs.');
|
||||
} else {
|
||||
for (let i = 0; i < args.length; i += 2) {
|
||||
const key = args[i];
|
||||
const value = args[i + 1];
|
||||
if (!isString(key)) {
|
||||
throw new Error(`DocumentReference.update failed: Argument at index ${i} must be a string`);
|
||||
}
|
||||
data[key] = value;
|
||||
}
|
||||
}
|
||||
return this._firestore._native
|
||||
.documentUpdate(this.path, data);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
import DocumentSnapshot from './DocumentSnapshot';
|
||||
import Path from './Path';
|
||||
import QuerySnapshot from './QuerySnapshot';
|
||||
import INTERNALS from '../../internals';
|
||||
import { firestoreAutoId } from '../../utils';
|
||||
import { firestoreAutoId, isFunction, isObject } from '../../utils';
|
||||
|
||||
const DIRECTIONS = {
|
||||
ASC: 'ASCENDING',
|
||||
@@ -44,6 +43,15 @@ type QueryOptions = {
|
||||
startAt?: any[],
|
||||
}
|
||||
export type Operator = '<' | '<=' | '=' | '==' | '>' | '>=';
|
||||
type QueryListenOptions = {
|
||||
includeQueryMetadataChanges: boolean,
|
||||
includeQueryMetadataChanges: boolean,
|
||||
}
|
||||
|
||||
type Observer = {
|
||||
next: (DocumentSnapshot) => void,
|
||||
error?: (Object) => void,
|
||||
}
|
||||
|
||||
/**
|
||||
* @class Query
|
||||
@@ -116,13 +124,65 @@ export default class Query {
|
||||
this._fieldOrders, options);
|
||||
}
|
||||
|
||||
onSnapshot(onNext: () => any, onError?: () => any): () => void {
|
||||
// TODO: Validation
|
||||
onSnapshot(
|
||||
optionsOrObserverOrOnNext: QueryListenOptions | Observer | (DocumentSnapshot) => void,
|
||||
observerOrOnNextOrOnError?: Observer | (DocumentSnapshot) => void | (Object) => void,
|
||||
onError?: (Object) => void,
|
||||
) {
|
||||
let observer = {};
|
||||
let queryListenOptions = {};
|
||||
// Called with: onNext, ?onError
|
||||
if (isFunction(optionsOrObserverOrOnNext)) {
|
||||
observer.next = optionsOrObserverOrOnNext;
|
||||
if (observerOrOnNextOrOnError && !isFunction(observerOrOnNextOrOnError)) {
|
||||
throw new Error('Query.onSnapshot failed: Second argument must be a valid function.');
|
||||
}
|
||||
observer.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('Query.onSnapshot failed: Observer.error must be a valid function.');
|
||||
}
|
||||
observer = optionsOrObserverOrOnNext;
|
||||
} else {
|
||||
throw new Error('Query.onSnapshot failed: Observer.next must be a valid function.');
|
||||
}
|
||||
} else if (optionsOrObserverOrOnNext.includeDocumentMetadataChanges || optionsOrObserverOrOnNext.includeQueryMetadataChanges) {
|
||||
queryListenOptions = optionsOrObserverOrOnNext;
|
||||
// Called with: Options, onNext, ?onError
|
||||
if (isFunction(observerOrOnNextOrOnError)) {
|
||||
observer.next = observerOrOnNextOrOnError;
|
||||
if (onError && !isFunction(onError)) {
|
||||
throw new Error('Query.onSnapshot failed: Third argument must be a valid function.');
|
||||
}
|
||||
observer.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('Query.onSnapshot failed: Observer.error must be a valid function.');
|
||||
}
|
||||
observer = observerOrOnNextOrOnError;
|
||||
} else {
|
||||
throw new Error('Query.onSnapshot failed: Observer.next must be a valid function.');
|
||||
}
|
||||
} else {
|
||||
throw new Error('Query.onSnapshot failed: Second argument must be a function or observer.');
|
||||
}
|
||||
} else {
|
||||
throw new Error('Query.onSnapshot failed: First argument must be a function, observer or options.');
|
||||
}
|
||||
} else {
|
||||
throw new Error('Query.onSnapshot failed: Called with invalid arguments.');
|
||||
}
|
||||
|
||||
const listenerId = firestoreAutoId();
|
||||
|
||||
const listener = (nativeQuerySnapshot) => {
|
||||
const querySnapshot = new QuerySnapshot(this._firestore, this, nativeQuerySnapshot);
|
||||
onNext(querySnapshot);
|
||||
observer.next(querySnapshot);
|
||||
};
|
||||
|
||||
// Listen to snapshot events
|
||||
@@ -132,10 +192,10 @@ export default class Query {
|
||||
);
|
||||
|
||||
// Listen for snapshot error events
|
||||
if (onError) {
|
||||
if (observer.error) {
|
||||
this._firestore.on(
|
||||
this._firestore._getAppEventName(`onQuerySnapshotError:${listenerId}`),
|
||||
onError,
|
||||
observer.error,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -146,7 +206,8 @@ export default class Query {
|
||||
this._fieldFilters,
|
||||
this._fieldOrders,
|
||||
this._queryOptions,
|
||||
listenerId
|
||||
listenerId,
|
||||
queryListenOptions,
|
||||
);
|
||||
|
||||
// Return an unsubscribe method
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* WriteBatch representation wrapper
|
||||
*/
|
||||
import DocumentReference from './DocumentReference';
|
||||
import { isObject, isString } from '../../utils';
|
||||
|
||||
import type { WriteOptions } from './DocumentReference';
|
||||
|
||||
@@ -58,11 +59,27 @@ export default class WriteBatch {
|
||||
return this;
|
||||
}
|
||||
|
||||
// TODO: Update to new method signature
|
||||
update(docRef: DocumentReference, data: Object): WriteBatch {
|
||||
update(docRef: DocumentReference, ...args: Object | string[]): WriteBatch {
|
||||
// TODO: Validation
|
||||
// validate.isDocumentReference('docRef', docRef);
|
||||
// validate.isDocument('data', data, true);
|
||||
let data = {};
|
||||
if (args.length === 1) {
|
||||
if (!isObject(args[0])) {
|
||||
throw new Error('DocumentReference.update failed: If using two arguments, the second must be an object.');
|
||||
}
|
||||
data = args[0];
|
||||
} else if (args.length % 2 === 1) {
|
||||
throw new Error('DocumentReference.update failed: Must have a document reference, followed by either a single object argument, or equal numbers of key/value pairs.');
|
||||
} else {
|
||||
for (let i = 0; i < args.length; i += 2) {
|
||||
const key = args[i];
|
||||
const value = args[i + 1];
|
||||
if (!isString(key)) {
|
||||
throw new Error(`DocumentReference.update failed: Argument at index ${i + 1} must be a string`);
|
||||
}
|
||||
data[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
this._writes.push({
|
||||
data,
|
||||
|
||||
@@ -25,7 +25,7 @@ const WILL_PRESENT_RESULT = {
|
||||
None: 'UNNotificationPresentationOptionNone',
|
||||
};
|
||||
|
||||
const FirebaseMessaging = NativeModules.FirebaseMessaging;
|
||||
const FirebaseMessaging = NativeModules.RNFirebaseMessaging;
|
||||
|
||||
/**
|
||||
* IOS only finish function
|
||||
|
||||
131
lib/modules/utils/index.js
Normal file
131
lib/modules/utils/index.js
Normal file
@@ -0,0 +1,131 @@
|
||||
// @flow
|
||||
import { NativeModules } from 'react-native';
|
||||
// import { version as ReactVersion } from 'react';
|
||||
// import ReactNativeVersion from 'react-native/Libraries/Core/ReactNativeVersion';
|
||||
|
||||
import INTERNALS from './../../internals';
|
||||
import { isIOS } from './../../utils';
|
||||
import PACKAGE from './../../../package.json';
|
||||
|
||||
const FirebaseCoreModule = NativeModules.RNFirebase;
|
||||
|
||||
export default class RNFirebaseUtils {
|
||||
static _NAMESPACE = 'utils';
|
||||
static _NATIVE_DISABLED = true;
|
||||
static _NATIVE_MODULE = 'RNFirebaseUtils';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
checkPlayServicesAvailability() {
|
||||
if (isIOS) return null;
|
||||
|
||||
const code = this.playServicesAvailability.code;
|
||||
|
||||
if (!this.playServicesAvailability.isAvailable) {
|
||||
if (INTERNALS.OPTIONS.promptOnMissingPlayServices && this.playServicesAvailability.isUserResolvableError) {
|
||||
this.promptForPlayServices();
|
||||
} else {
|
||||
const error = INTERNALS.STRINGS.ERROR_PLAY_SERVICES(code);
|
||||
if (INTERNALS.OPTIONS.errorOnMissingPlayServices) {
|
||||
if (code === 2) console.warn(error); // only warn if it exists but may need an update
|
||||
else throw new Error(error);
|
||||
} else {
|
||||
console.warn(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
promptForPlayServices() {
|
||||
if (isIOS) return null;
|
||||
return FirebaseCoreModule.promptForPlayServices();
|
||||
}
|
||||
|
||||
resolutionForPlayServices() {
|
||||
if (isIOS) return null;
|
||||
return FirebaseCoreModule.resolutionForPlayServices();
|
||||
}
|
||||
|
||||
makePlayServicesAvailable() {
|
||||
if (isIOS) return null;
|
||||
return FirebaseCoreModule.makePlayServicesAvailable();
|
||||
}
|
||||
|
||||
get sharedEventEmitter(): Object {
|
||||
return INTERNALS.SharedEventEmitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the global logging level for all logs.
|
||||
*
|
||||
* @param booleanOrDebugString
|
||||
*/
|
||||
set logLevel(booleanOrDebugString) {
|
||||
INTERNALS.OPTIONS.logLevel = booleanOrDebugString;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of all current database registrations id strings
|
||||
*/
|
||||
get databaseRegistrations(): Array<string> {
|
||||
return Object.keys(INTERNALS.SyncTree._reverseLookup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call with a registration id string to get the details off this reg
|
||||
*/
|
||||
get getDatabaseRegistrationDetails(): Function {
|
||||
return INTERNALS.SyncTree.getRegistration.bind(INTERNALS.SyncTree);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts an array or a single string of registration ids.
|
||||
* This will remove the refs on both the js and native sides and their listeners.
|
||||
* @return {function(this:T)}
|
||||
*/
|
||||
get removeDatabaseRegistration(): Function {
|
||||
return INTERNALS.SyncTree.removeListenersForRegistrations.bind(INTERNALS.SyncTree);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns props from the android GoogleApiAvailability sdk
|
||||
* @android
|
||||
* @return {RNFirebase.GoogleApiAvailabilityType|{isAvailable: boolean, status: number}}
|
||||
*/
|
||||
get playServicesAvailability(): GoogleApiAvailabilityType {
|
||||
return FirebaseCoreModule.playServicesAvailability || { isAvailable: true, status: 0 };
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/Disable throwing an error or warning on detecting a play services problem
|
||||
* @android
|
||||
* @param bool
|
||||
*/
|
||||
set errorOnMissingPlayServices(bool: Boolean) {
|
||||
INTERNALS.OPTIONS.errorOnMissingPlayServices = bool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/Disable automatic prompting of the play services update dialog
|
||||
* @android
|
||||
* @param bool
|
||||
*/
|
||||
set promptOnMissingPlayServices(bool: Boolean) {
|
||||
INTERNALS.OPTIONS.promptOnMissingPlayServices = bool;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const statics = {
|
||||
DEFAULT_APP_NAME: INTERNALS.STRINGS.DEFAULT_APP_NAME,
|
||||
// VERSIONS: {
|
||||
// react: ReactVersion,
|
||||
// 'react-native': Object.values(ReactNativeVersion.version).slice(0, 3).join('.'),
|
||||
// 'react-native-firebase': PACKAGE.version,
|
||||
// },
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user