Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
7b68d2c660
|
@ -57,9 +57,10 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
|
|||
|
||||
@ReactMethod
|
||||
public void collectionOnSnapshot(String appName, String path, ReadableArray filters,
|
||||
ReadableArray orders, ReadableMap options, String listenerId) {
|
||||
ReadableArray orders, ReadableMap options, String listenerId,
|
||||
ReadableMap queryListenOptions) {
|
||||
RNFirebaseFirestoreCollectionReference ref = getCollectionForAppPath(appName, path, filters, orders, options);
|
||||
ref.onSnapshot(listenerId);
|
||||
ref.onSnapshot(listenerId, queryListenOptions);
|
||||
}
|
||||
|
||||
|
||||
|
@ -145,9 +146,10 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
|
|||
}
|
||||
|
||||
@ReactMethod
|
||||
public void documentOnSnapshot(String appName, String path, String listenerId) {
|
||||
public void documentOnSnapshot(String appName, String path, String listenerId,
|
||||
ReadableMap docListenOptions) {
|
||||
RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
|
||||
ref.onSnapshot(listenerId);
|
||||
ref.onSnapshot(listenerId, docListenOptions);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
|
|
|
@ -12,10 +12,12 @@ import com.facebook.react.bridge.ReadableMap;
|
|||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.google.android.gms.tasks.OnCompleteListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
import com.google.firebase.firestore.DocumentListenOptions;
|
||||
import com.google.firebase.firestore.EventListener;
|
||||
import com.google.firebase.firestore.FirebaseFirestoreException;
|
||||
import com.google.firebase.firestore.ListenerRegistration;
|
||||
import com.google.firebase.firestore.Query;
|
||||
import com.google.firebase.firestore.QueryListenOptions;
|
||||
import com.google.firebase.firestore.QuerySnapshot;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
@ -71,7 +73,7 @@ public class RNFirebaseFirestoreCollectionReference {
|
|||
}
|
||||
}
|
||||
|
||||
public void onSnapshot(final String listenerId) {
|
||||
public void onSnapshot(final String listenerId, final ReadableMap queryListenOptions) {
|
||||
if (!collectionSnapshotListeners.containsKey(listenerId)) {
|
||||
final EventListener<QuerySnapshot> listener = new EventListener<QuerySnapshot>() {
|
||||
@Override
|
||||
|
@ -87,7 +89,19 @@ public class RNFirebaseFirestoreCollectionReference {
|
|||
}
|
||||
}
|
||||
};
|
||||
ListenerRegistration listenerRegistration = this.query.addSnapshotListener(listener);
|
||||
QueryListenOptions options = new QueryListenOptions();
|
||||
if (queryListenOptions != null) {
|
||||
if (queryListenOptions.hasKey("includeDocumentMetadataChanges")
|
||||
&& queryListenOptions.getBoolean("includeDocumentMetadataChanges")) {
|
||||
options.includeDocumentMetadataChanges();
|
||||
}
|
||||
if (queryListenOptions.hasKey("includeQueryMetadataChanges")
|
||||
&& queryListenOptions.getBoolean("includeQueryMetadataChanges")) {
|
||||
options.includeQueryMetadataChanges();
|
||||
}
|
||||
}
|
||||
|
||||
ListenerRegistration listenerRegistration = this.query.addSnapshotListener(options, listener);
|
||||
collectionSnapshotListeners.put(listenerId, listenerRegistration);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.facebook.react.bridge.ReadableMap;
|
|||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.google.android.gms.tasks.OnCompleteListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
import com.google.firebase.firestore.DocumentListenOptions;
|
||||
import com.google.firebase.firestore.DocumentReference;
|
||||
import com.google.firebase.firestore.DocumentSnapshot;
|
||||
import com.google.firebase.firestore.EventListener;
|
||||
|
@ -85,7 +86,7 @@ public class RNFirebaseFirestoreDocumentReference {
|
|||
}
|
||||
}
|
||||
|
||||
public void onSnapshot(final String listenerId) {
|
||||
public void onSnapshot(final String listenerId, final ReadableMap docListenOptions) {
|
||||
if (!documentSnapshotListeners.containsKey(listenerId)) {
|
||||
final EventListener<DocumentSnapshot> listener = new EventListener<DocumentSnapshot>() {
|
||||
@Override
|
||||
|
@ -101,7 +102,11 @@ public class RNFirebaseFirestoreDocumentReference {
|
|||
}
|
||||
}
|
||||
};
|
||||
ListenerRegistration listenerRegistration = this.ref.addSnapshotListener(listener);
|
||||
DocumentListenOptions options = new DocumentListenOptions();
|
||||
if (docListenOptions != null && docListenOptions.hasKey("includeMetadataChanges") && docListenOptions.getBoolean("includeMetadataChanges")) {
|
||||
options.includeMetadataChanges();
|
||||
}
|
||||
ListenerRegistration listenerRegistration = this.ref.addSnapshotListener(options, listener);
|
||||
documentSnapshotListeners.put(listenerId, listenerRegistration);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@ declare module "react-native-firebase" {
|
|||
|
||||
static initializeApp(options?: any | RNFirebase.configurationOptions, name?: string): FireBase;
|
||||
|
||||
static app(name?: string): FireBase;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,9 +42,10 @@ RCT_EXPORT_METHOD(collectionOnSnapshot:(NSString *) appName
|
|||
filters:(NSArray *) filters
|
||||
orders:(NSArray *) orders
|
||||
options:(NSDictionary *) options
|
||||
listenerId:(nonnull NSString *) listenerId) {
|
||||
listenerId:(nonnull NSString *) listenerId
|
||||
queryListenOptions:(NSDictionary *) queryListenOptions) {
|
||||
RNFirebaseFirestoreCollectionReference *ref = [self getCollectionForAppPath:appName path:path filters:filters orders:orders options:options];
|
||||
[ref onSnapshot:listenerId];
|
||||
[ref onSnapshot:listenerId queryListenOptions:queryListenOptions];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(documentBatch:(NSString *) appName
|
||||
|
@ -128,9 +129,10 @@ RCT_EXPORT_METHOD(documentOffSnapshot:(NSString *) appName
|
|||
|
||||
RCT_EXPORT_METHOD(documentOnSnapshot:(NSString *) appName
|
||||
path:(NSString *) path
|
||||
listenerId:(nonnull NSString *) listenerId) {
|
||||
listenerId:(nonnull NSString *) listenerId
|
||||
docListenOptions:(NSDictionary *) docListenOptions) {
|
||||
RNFirebaseFirestoreDocumentReference *ref = [self getDocumentForAppPath:appName path:path];
|
||||
[ref onSnapshot:listenerId];
|
||||
[ref onSnapshot:listenerId docListenOptions:docListenOptions];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(documentSet:(NSString *) appName
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
- (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter app:(NSString *)app path:(NSString *)path filters:(NSArray *)filters orders:(NSArray *)orders options:(NSDictionary *)options;
|
||||
- (void)get:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
|
||||
+ (void)offSnapshot:(NSString *)listenerId;
|
||||
- (void)onSnapshot:(NSString *)listenerId;
|
||||
- (void)onSnapshot:(NSString *)listenerId queryListenOptions:(NSDictionary *) queryListenOptions;
|
||||
+ (NSDictionary *)snapshotToDictionary:(FIRQuerySnapshot *)querySnapshot;
|
||||
@end
|
||||
|
||||
|
|
|
@ -49,7 +49,8 @@ static NSMutableDictionary *_listeners;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)onSnapshot:(NSString *) listenerId {
|
||||
- (void)onSnapshot:(NSString *) listenerId
|
||||
queryListenOptions:(NSDictionary *) queryListenOptions {
|
||||
if (_listeners[listenerId] == nil) {
|
||||
id listenerBlock = ^(FIRQuerySnapshot * _Nullable snapshot, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
|
@ -63,7 +64,18 @@ static NSMutableDictionary *_listeners;
|
|||
[self handleQuerySnapshotEvent:listenerId querySnapshot:snapshot];
|
||||
}
|
||||
};
|
||||
id<FIRListenerRegistration> listener = [_query addSnapshotListener:listenerBlock];
|
||||
|
||||
FIRQueryListenOptions *options = [[FIRQueryListenOptions alloc] init];
|
||||
if (queryListenOptions) {
|
||||
if (queryListenOptions[@"includeDocumentMetadataChanges"]) {
|
||||
[options includeDocumentMetadataChanges:TRUE];
|
||||
}
|
||||
if (queryListenOptions[@"includeQueryMetadataChanges"]) {
|
||||
[options includeQueryMetadataChanges:TRUE];
|
||||
}
|
||||
}
|
||||
|
||||
id<FIRListenerRegistration> listener = [_query addSnapshotListenerWithOptions:options listener:listenerBlock];
|
||||
_listeners[listenerId] = listener;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
- (void)delete:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
|
||||
- (void)get:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
|
||||
+ (void)offSnapshot:(NSString *)listenerId;
|
||||
- (void)onSnapshot:(NSString *)listenerId;
|
||||
- (void)onSnapshot:(NSString *)listenerId docListenOptions:(NSDictionary *) docListenOptions;
|
||||
- (void)set:(NSDictionary *)data options:(NSDictionary *)options resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
|
||||
- (void)update:(NSDictionary *)data resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
|
||||
- (BOOL)hasListeners;
|
||||
|
|
|
@ -61,7 +61,8 @@ static NSMutableDictionary *_listeners;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)onSnapshot:(NSString *) listenerId {
|
||||
- (void)onSnapshot:(NSString *) listenerId
|
||||
docListenOptions:(NSDictionary *) docListenOptions {
|
||||
if (_listeners[listenerId] == nil) {
|
||||
id listenerBlock = ^(FIRDocumentSnapshot * _Nullable snapshot, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
|
@ -75,8 +76,11 @@ static NSMutableDictionary *_listeners;
|
|||
[self handleDocumentSnapshotEvent:listenerId documentSnapshot:snapshot];
|
||||
}
|
||||
};
|
||||
|
||||
id<FIRListenerRegistration> listener = [_ref addSnapshotListener:listenerBlock];
|
||||
FIRDocumentListenOptions *options = [[FIRDocumentListenOptions alloc] init];
|
||||
if (docListenOptions && docListenOptions[@"includeMetadataChanges"]) {
|
||||
[options includeMetadataChanges:TRUE];
|
||||
}
|
||||
id<FIRListenerRegistration> listener = [_ref addSnapshotListenerWithOptions:options listener:listenerBlock];
|
||||
_listeners[listenerId] = listener;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -129,30 +129,30 @@ PODS:
|
|||
- nanopb/decode (0.3.8)
|
||||
- nanopb/encode (0.3.8)
|
||||
- Protobuf (3.4.0)
|
||||
- React (0.49.0-rc.6):
|
||||
- React/Core (= 0.49.0-rc.6)
|
||||
- React/BatchedBridge (0.49.0-rc.6):
|
||||
- React (0.49.1):
|
||||
- React/Core (= 0.49.1)
|
||||
- React/BatchedBridge (0.49.1):
|
||||
- React/Core
|
||||
- React/cxxreact_legacy
|
||||
- React/Core (0.49.0-rc.6):
|
||||
- yoga (= 0.49.0-rc.6.React)
|
||||
- React/cxxreact_legacy (0.49.0-rc.6):
|
||||
- React/Core (0.49.1):
|
||||
- yoga (= 0.49.1.React)
|
||||
- React/cxxreact_legacy (0.49.1):
|
||||
- React/jschelpers_legacy
|
||||
- React/fishhook (0.49.0-rc.6)
|
||||
- React/jschelpers_legacy (0.49.0-rc.6)
|
||||
- React/RCTBlob (0.49.0-rc.6):
|
||||
- React/fishhook (0.49.1)
|
||||
- React/jschelpers_legacy (0.49.1)
|
||||
- React/RCTBlob (0.49.1):
|
||||
- React/Core
|
||||
- React/RCTNetwork (0.49.0-rc.6):
|
||||
- React/RCTNetwork (0.49.1):
|
||||
- React/Core
|
||||
- React/RCTText (0.49.0-rc.6):
|
||||
- React/RCTText (0.49.1):
|
||||
- React/Core
|
||||
- React/RCTWebSocket (0.49.0-rc.6):
|
||||
- React/RCTWebSocket (0.49.1):
|
||||
- React/Core
|
||||
- React/fishhook
|
||||
- React/RCTBlob
|
||||
- RNFirebase (3.0.0):
|
||||
- React
|
||||
- yoga (0.49.0-rc.6.React)
|
||||
- yoga (0.49.1.React)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Firebase/AdMob
|
||||
|
@ -207,9 +207,9 @@ SPEC CHECKSUMS:
|
|||
leveldb-library: 10fb39c39e243db4af1828441162405bbcec1404
|
||||
nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3
|
||||
Protobuf: 03eef2ee0b674770735cf79d9c4d3659cf6908e8
|
||||
React: e6ef6a41ec6dd1b7941417d60ca582bf5e9c739d
|
||||
RNFirebase: 2ceda3aef595ea1379bf5bfcc1cd9ee7d6c05d3b
|
||||
yoga: f9485d2ebf0ca773db2d727ea71b1aa8c9f3e075
|
||||
React: cf892fb84b7d06bf5fea7f328e554c6dcabe85ee
|
||||
RNFirebase: 901a473c68fcbaa28125c56a911923f2fbe5d61b
|
||||
yoga: 3abf02d6d9aeeb139b4c930eb1367feae690a35a
|
||||
|
||||
PODFILE CHECKSUM: b5674be55653f5dda937c8b794d0479900643d45
|
||||
|
||||
|
|
|
@ -53,262 +53,360 @@ function collectionReferenceTests({ describe, it, context, firebase }) {
|
|||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('calls callback with the initial data and then when document changes', () => {
|
||||
return new Promise(async (resolve) => {
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const newDocValue = { name: 'updated' };
|
||||
it('calls callback with the initial data and then when document changes', async () => {
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const newDocValue = { name: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callback(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callback(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDocValue);
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDocValue);
|
||||
callback.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
|
||||
resolve();
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDocValue);
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDocValue);
|
||||
callback.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('calls callback with the initial data and then when document is added', () => {
|
||||
return new Promise(async (resolve) => {
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const newDocValue = { name: 'updated' };
|
||||
it('calls callback with the initial data and then when document is added', async () => {
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const newDocValue = { name: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callback(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callback(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDocValue);
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc2');
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(currentDocValue);
|
||||
callback.should.be.calledWith(newDocValue);
|
||||
callback.should.be.calledThrice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
|
||||
resolve();
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDocValue);
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc2');
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(currentDocValue);
|
||||
callback.should.be.calledWith(newDocValue);
|
||||
callback.should.be.calledThrice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('doesn\'t call callback when the ref is updated with the same value', async () => {
|
||||
return new Promise(async (resolve) => {
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = collectionRef.onSnapshot((snapshot) => {
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callback(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDocValue);
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
await docRef.set(currentDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledOnce(); // Callback is not called again
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('allows binding multiple callbacks to the same ref', async () => {
|
||||
// Setup
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const newDocValue = { name: 'updated' };
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeA = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callbackA(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeB = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callbackB(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(currentDocValue);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(currentDocValue);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(newDocValue);
|
||||
callbackB.should.be.calledWith(newDocValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribeA();
|
||||
unsubscribeB();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('listener stops listening when unsubscribed', async () => {
|
||||
// Setup
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const newDocValue = { name: 'updated' };
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeA = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callbackA(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeB = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callbackB(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(currentDocValue);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(currentDocValue);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(newDocValue);
|
||||
callbackB.should.be.calledWith(newDocValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Unsubscribe A
|
||||
|
||||
unsubscribeA();
|
||||
|
||||
await docRef.set(currentDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackB.should.be.calledWith(currentDocValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
|
||||
// Unsubscribe B
|
||||
|
||||
unsubscribeB();
|
||||
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('supports options and callback', async () => {
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const newDocValue = { name: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = collectionRef.onSnapshot({ includeQueryMetadataChanges: true, includeDocumentMetadataChanges: true }, (snapshot) => {
|
||||
snapshot.forEach(doc => callback(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDocValue);
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDocValue);
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('supports observer', async () => {
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const newDocValue = { name: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
const observer = {
|
||||
next: (snapshot) => {
|
||||
snapshot.forEach(doc => callback(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDocValue);
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
await docRef.set(currentDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledOnce(); // Callback is not called again
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
|
||||
resolve();
|
||||
},
|
||||
};
|
||||
unsubscribe = collectionRef.onSnapshot(observer);
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDocValue);
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDocValue);
|
||||
callback.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('allows binding multiple callbacks to the same ref', () => {
|
||||
return new Promise(async (resolve) => {
|
||||
// Setup
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const newDocValue = { name: 'updated' };
|
||||
it('supports options and observer', async () => {
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const newDocValue = { name: 'updated' };
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeA = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callbackA(doc.data()));
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
const observer = {
|
||||
next: (snapshot) => {
|
||||
snapshot.forEach(doc => callback(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeB = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callbackB(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(currentDocValue);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(currentDocValue);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(newDocValue);
|
||||
callbackB.should.be.calledWith(newDocValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribeA();
|
||||
unsubscribeB();
|
||||
|
||||
resolve();
|
||||
},
|
||||
};
|
||||
unsubscribe = collectionRef.onSnapshot({ includeQueryMetadataChanges: true, includeDocumentMetadataChanges: true }, observer);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('listener stops listening when unsubscribed', () => {
|
||||
return new Promise(async (resolve) => {
|
||||
// Setup
|
||||
const collectionRef = firebase.native.firestore().collection('document-tests');
|
||||
const currentDocValue = { name: 'doc1' };
|
||||
const newDocValue = { name: 'updated' };
|
||||
callback.should.be.calledWith(currentDocValue);
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeA = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callbackA(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeB = collectionRef.onSnapshot((snapshot) => {
|
||||
snapshot.forEach(doc => callbackB(doc.data()));
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(currentDocValue);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(currentDocValue);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(newDocValue);
|
||||
callbackB.should.be.calledWith(newDocValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Unsubscribe A
|
||||
|
||||
unsubscribeA();
|
||||
|
||||
await docRef.set(currentDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackB.should.be.calledWith(currentDocValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
|
||||
// Unsubscribe B
|
||||
|
||||
unsubscribeB();
|
||||
|
||||
await docRef.set(newDocValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
|
||||
resolve();
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDocValue);
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import sinon from 'sinon';
|
|||
import 'should-sinon';
|
||||
import should from 'should';
|
||||
|
||||
function collectionReferenceTests({ describe, it, context, firebase }) {
|
||||
function documentReferenceTests({ describe, it, context, firebase }) {
|
||||
describe('DocumentReference', () => {
|
||||
context('class', () => {
|
||||
it('should return instance methods', () => {
|
||||
|
@ -29,219 +29,324 @@ function collectionReferenceTests({ describe, it, context, firebase }) {
|
|||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('calls callback with the initial data and then when value changes', () => {
|
||||
return new Promise(async (resolve) => {
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
it('calls callback with the initial data and then when value changes', async () => {
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = docRef.onSnapshot((snapshot) => {
|
||||
callback(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = docRef.onSnapshot((snapshot) => {
|
||||
callback(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDataValue);
|
||||
|
||||
// Update the document
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDataValue);
|
||||
callback.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
|
||||
resolve();
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDataValue);
|
||||
|
||||
// Update the document
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDataValue);
|
||||
callback.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('doesn\'t call callback when the ref is updated with the same value', async () => {
|
||||
return new Promise(async (resolve) => {
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = docRef.onSnapshot((snapshot) => {
|
||||
callback(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDataValue);
|
||||
|
||||
await docRef.set(currentDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledOnce(); // Callback is not called again
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('allows binding multiple callbacks to the same ref', async () => {
|
||||
// Setup
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeA = docRef.onSnapshot((snapshot) => {
|
||||
callbackA(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeB = docRef.onSnapshot((snapshot) => {
|
||||
callbackB(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(currentDataValue);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(currentDataValue);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(newDataValue);
|
||||
callbackB.should.be.calledWith(newDataValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribeA();
|
||||
unsubscribeB();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('listener stops listening when unsubscribed', async () => {
|
||||
// Setup
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeA = docRef.onSnapshot((snapshot) => {
|
||||
callbackA(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeB = docRef.onSnapshot((snapshot) => {
|
||||
callbackB(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(currentDataValue);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(currentDataValue);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(newDataValue);
|
||||
callbackB.should.be.calledWith(newDataValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Unsubscribe A
|
||||
|
||||
unsubscribeA();
|
||||
|
||||
await docRef.set(currentDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackB.should.be.calledWith(currentDataValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
|
||||
// Unsubscribe B
|
||||
|
||||
unsubscribeB();
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('supports options and callbacks', async () => {
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = docRef.onSnapshot((snapshot) => {
|
||||
callback(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribe = docRef.onSnapshot({ includeMetadataChanges: true }, (snapshot) => {
|
||||
callback(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDataValue);
|
||||
callback.should.be.calledWith(currentDataValue);
|
||||
|
||||
await docRef.set(currentDataValue);
|
||||
// Update the document
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledOnce(); // Callback is not called again
|
||||
callback.should.be.calledWith(newDataValue);
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
|
||||
resolve();
|
||||
});
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('allows binding multiple callbacks to the same ref', () => {
|
||||
return new Promise(async (resolve) => {
|
||||
// Setup
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
it('supports observer', async () => {
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeA = docRef.onSnapshot((snapshot) => {
|
||||
callbackA(snapshot.data());
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
const observer = {
|
||||
next: (snapshot) => {
|
||||
callback(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeB = docRef.onSnapshot((snapshot) => {
|
||||
callbackB(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(currentDataValue);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(currentDataValue);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(newDataValue);
|
||||
callbackB.should.be.calledWith(newDataValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribeA();
|
||||
unsubscribeB();
|
||||
|
||||
resolve();
|
||||
},
|
||||
};
|
||||
unsubscribe = docRef.onSnapshot(observer);
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDataValue);
|
||||
|
||||
// Update the document
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDataValue);
|
||||
callback.should.be.calledTwice();
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('listener stops listening when unsubscribed', () => {
|
||||
return new Promise(async (resolve) => {
|
||||
// Setup
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
it('supports options and observer', async () => {
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
const newDataValue = { name: 'updated' };
|
||||
|
||||
const callbackA = sinon.spy();
|
||||
const callbackB = sinon.spy();
|
||||
const callback = sinon.spy();
|
||||
|
||||
// Test
|
||||
let unsubscribeA;
|
||||
let unsubscribeB;
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeA = docRef.onSnapshot((snapshot) => {
|
||||
callbackA(snapshot.data());
|
||||
// Test
|
||||
|
||||
let unsubscribe;
|
||||
await new Promise((resolve2) => {
|
||||
const observer = {
|
||||
next: (snapshot) => {
|
||||
callback(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
unsubscribeB = docRef.onSnapshot((snapshot) => {
|
||||
callbackB(snapshot.data());
|
||||
resolve2();
|
||||
});
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(currentDataValue);
|
||||
callbackA.should.be.calledOnce();
|
||||
|
||||
callbackB.should.be.calledWith(currentDataValue);
|
||||
callbackB.should.be.calledOnce();
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledWith(newDataValue);
|
||||
callbackB.should.be.calledWith(newDataValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledTwice();
|
||||
|
||||
// Unsubscribe A
|
||||
|
||||
unsubscribeA();
|
||||
|
||||
await docRef.set(currentDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackB.should.be.calledWith(currentDataValue);
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
|
||||
// Unsubscribe B
|
||||
|
||||
unsubscribeB();
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
callbackA.should.be.calledTwice();
|
||||
callbackB.should.be.calledThrice();
|
||||
|
||||
resolve();
|
||||
},
|
||||
};
|
||||
unsubscribe = docRef.onSnapshot({ includeMetadataChanges: true }, observer);
|
||||
});
|
||||
|
||||
callback.should.be.calledWith(currentDataValue);
|
||||
|
||||
// Update the document
|
||||
|
||||
await docRef.set(newDataValue);
|
||||
|
||||
await new Promise((resolve2) => {
|
||||
setTimeout(() => resolve2(), 5);
|
||||
});
|
||||
|
||||
// Assertions
|
||||
|
||||
callback.should.be.calledWith(newDataValue);
|
||||
|
||||
// Tear down
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -283,10 +388,22 @@ function collectionReferenceTests({ describe, it, context, firebase }) {
|
|||
});
|
||||
|
||||
context('update()', () => {
|
||||
it('should update Document', () => {
|
||||
it('should update Document using object', () => {
|
||||
return firebase.native.firestore()
|
||||
.doc('document-tests/doc1')
|
||||
.set({ name: 'updated' })
|
||||
.update({ name: 'updated' })
|
||||
.then(async () => {
|
||||
const doc = await firebase.native.firestore().doc('document-tests/doc1').get();
|
||||
doc.data().name.should.equal('updated');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('update()', () => {
|
||||
it('should update Document using key/value pairs', () => {
|
||||
return firebase.native.firestore()
|
||||
.doc('document-tests/doc1')
|
||||
.update('name', 'updated')
|
||||
.then(async () => {
|
||||
const doc = await firebase.native.firestore().doc('document-tests/doc1').get();
|
||||
doc.data().name.should.equal('updated');
|
||||
|
@ -296,4 +413,4 @@ function collectionReferenceTests({ describe, it, context, firebase }) {
|
|||
});
|
||||
}
|
||||
|
||||
export default collectionReferenceTests;
|
||||
export default documentReferenceTests;
|
||||
|
|
|
@ -36,7 +36,7 @@ function firestoreTests({ describe, it, context, firebase }) {
|
|||
.set(nycRef, { name: 'New York City' })
|
||||
.set(sfRef, { name: 'San Francisco' })
|
||||
.update(nycRef, { population: 1000000 })
|
||||
.update(sfRef, { name: 'San Fran' })
|
||||
.update(sfRef, 'name', 'San Fran')
|
||||
.set(lRef, { population: 3000000 }, { merge: true })
|
||||
.delete(ayRef)
|
||||
.commit()
|
||||
|
|
Loading…
Reference in New Issue