Merge remote-tracking branch 'origin/master'

This commit is contained in:
Salakar
2017-10-06 14:41:26 +01:00
16 changed files with 863 additions and 451 deletions

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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,