[firestore] Add FieldPath support to DocumentReference and WriteBatch update methods
This commit is contained in:
parent
5e062868fc
commit
3dacb35291
|
@ -4,6 +4,8 @@
|
|||
*/
|
||||
import CollectionReference from './CollectionReference';
|
||||
import DocumentSnapshot from './DocumentSnapshot';
|
||||
import FieldPath from './FieldPath';
|
||||
import { mergeFieldPathData } from './utils';
|
||||
import { buildNativeMap } from './utils/serialize';
|
||||
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
|
||||
import { getLogger } from '../../utils/log';
|
||||
|
@ -192,10 +194,13 @@ export default class DocumentReference {
|
|||
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`);
|
||||
if (isString(key)) {
|
||||
data[key] = value;
|
||||
} else if (key instanceof FieldPath) {
|
||||
data = mergeFieldPathData(data, key._segments, value);
|
||||
} else {
|
||||
throw new Error(`DocumentReference.update failed: Argument at index ${i} must be a string or FieldPath`);
|
||||
}
|
||||
data[key] = value;
|
||||
}
|
||||
}
|
||||
const nativeData = buildNativeMap(data);
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* @flow
|
||||
* WriteBatch representation wrapper
|
||||
*/
|
||||
import FieldPath from './FieldPath';
|
||||
import { mergeFieldPathData } from './utils';
|
||||
import { buildNativeMap } from './utils/serialize';
|
||||
import { isObject, isString } from '../../utils';
|
||||
import { getNativeModule } from '../../utils/native';
|
||||
|
@ -67,19 +69,22 @@ export default class WriteBatch {
|
|||
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.');
|
||||
throw new Error('WriteBatch.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.');
|
||||
throw new Error('WriteBatch.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`);
|
||||
if (isString(key)) {
|
||||
data[key] = value;
|
||||
} else if (key instanceof FieldPath) {
|
||||
data = mergeFieldPathData(data, key._segments, value);
|
||||
} else {
|
||||
throw new Error(`WriteBatch.update failed: Argument at index ${i} must be a string or FieldPath`);
|
||||
}
|
||||
data[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
const buildFieldPathData = (segments: string[], value: any): Object => {
|
||||
if (segments.length === 1) {
|
||||
return {
|
||||
[segments[0]]: value,
|
||||
};
|
||||
}
|
||||
return {
|
||||
[segments[0]]: buildFieldPathData(segments.slice(1), value),
|
||||
};
|
||||
};
|
||||
|
||||
export const mergeFieldPathData = (data: Object, segments: string[], value: any): Object => {
|
||||
if (segments.length === 1) {
|
||||
return {
|
||||
...data,
|
||||
[segments[0]]: value,
|
||||
};
|
||||
} else if (data[segments[0]]) {
|
||||
return {
|
||||
...data,
|
||||
[segments[0]]: mergeFieldPathData(data[segments[0]], segments.slice(1), value),
|
||||
};
|
||||
}
|
||||
return {
|
||||
...data,
|
||||
[segments[0]]: buildFieldPathData(segments.slice(1), value),
|
||||
};
|
||||
};
|
|
@ -66,9 +66,7 @@ function documentReferenceTests({ describe, it, context, firebase }) {
|
|||
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('doesn\'t call callback when the ref is updated with the same value', async () => {
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
|
@ -101,9 +99,7 @@ function documentReferenceTests({ describe, it, context, firebase }) {
|
|||
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('allows binding multiple callbacks to the same ref', async () => {
|
||||
// Setup
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
|
@ -153,9 +149,7 @@ function documentReferenceTests({ describe, it, context, firebase }) {
|
|||
unsubscribeA();
|
||||
unsubscribeB();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('listener stops listening when unsubscribed', async () => {
|
||||
// Setup
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
|
@ -228,9 +222,7 @@ function documentReferenceTests({ describe, it, context, firebase }) {
|
|||
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' };
|
||||
|
@ -266,9 +258,7 @@ function documentReferenceTests({ describe, it, context, firebase }) {
|
|||
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('supports observer', async () => {
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
|
@ -308,9 +298,7 @@ function documentReferenceTests({ describe, it, context, firebase }) {
|
|||
|
||||
unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
context('onSnapshot()', () => {
|
||||
it('supports options and observer', async () => {
|
||||
const docRef = firebase.native.firestore().doc('document-tests/doc1');
|
||||
const currentDataValue = { name: 'doc1' };
|
||||
|
@ -361,9 +349,7 @@ function documentReferenceTests({ describe, it, context, firebase }) {
|
|||
doc.data().name.should.equal('doc2');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('set()', () => {
|
||||
it('should merge Document', () => {
|
||||
return firebase.native.firestore()
|
||||
.doc('document-tests/doc1')
|
||||
|
@ -374,9 +360,7 @@ function documentReferenceTests({ describe, it, context, firebase }) {
|
|||
doc.data().merge.should.equal('merge');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('set()', () => {
|
||||
it('should overwrite Document', () => {
|
||||
return firebase.native.firestore()
|
||||
.doc('document-tests/doc1')
|
||||
|
@ -398,9 +382,7 @@ function documentReferenceTests({ describe, it, context, firebase }) {
|
|||
doc.data().name.should.equal('updated');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('update()', () => {
|
||||
it('should update Document using key/value pairs', () => {
|
||||
return firebase.native.firestore()
|
||||
.doc('document-tests/doc1')
|
||||
|
@ -410,6 +392,40 @@ function documentReferenceTests({ describe, it, context, firebase }) {
|
|||
doc.data().name.should.equal('updated');
|
||||
});
|
||||
});
|
||||
|
||||
it('should update Document using FieldPath/value pair', () => {
|
||||
return firebase.native.firestore()
|
||||
.doc('document-tests/doc1')
|
||||
.update(new firebase.native.firestore.FieldPath('name'), 'Name')
|
||||
.then(async () => {
|
||||
const doc = await firebase.native.firestore().doc('document-tests/doc1').get();
|
||||
doc.data().name.should.equal('Name');
|
||||
});
|
||||
});
|
||||
|
||||
it('should update Document using nested FieldPath and value pair', () => {
|
||||
return firebase.native.firestore()
|
||||
.doc('document-tests/doc1')
|
||||
.update(new firebase.native.firestore.FieldPath('nested', 'name'), 'Nested Name')
|
||||
.then(async () => {
|
||||
const doc = await firebase.native.firestore().doc('document-tests/doc1').get();
|
||||
doc.data().nested.name.should.equal('Nested Name');
|
||||
});
|
||||
});
|
||||
|
||||
it('should update Document using multiple FieldPath/value pairs', () => {
|
||||
return firebase.native.firestore()
|
||||
.doc('document-tests/doc1')
|
||||
.update(
|
||||
new firebase.native.firestore.FieldPath('nested', 'firstname'), 'First Name',
|
||||
new firebase.native.firestore.FieldPath('nested', 'lastname'), 'Last Name',
|
||||
)
|
||||
.then(async () => {
|
||||
const doc = await firebase.native.firestore().doc('document-tests/doc1').get();
|
||||
doc.data().nested.firstname.should.equal('First Name');
|
||||
doc.data().nested.lastname.should.equal('Last Name');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('types', () => {
|
||||
|
@ -422,9 +438,7 @@ function documentReferenceTests({ describe, it, context, firebase }) {
|
|||
const doc = await docRef.get();
|
||||
should.equal(doc.data().field, true);
|
||||
});
|
||||
});
|
||||
|
||||
context('types', () => {
|
||||
it('should handle Date field', async () => {
|
||||
const date = new Date();
|
||||
const docRef = firebase.native.firestore().doc('document-tests/reference');
|
||||
|
@ -437,9 +451,7 @@ function documentReferenceTests({ describe, it, context, firebase }) {
|
|||
should.equal(doc.data().field.toISOString(), date.toISOString());
|
||||
should.equal(doc.data().field.getTime(), date.getTime());
|
||||
});
|
||||
});
|
||||
|
||||
context('types', () => {
|
||||
it('should handle DocumentReference field', async () => {
|
||||
const docRef = firebase.native.firestore().doc('document-tests/reference');
|
||||
await docRef.set({
|
||||
|
@ -449,9 +461,7 @@ function documentReferenceTests({ describe, it, context, firebase }) {
|
|||
const doc = await docRef.get();
|
||||
should.equal(doc.data().field.path, 'test/field');
|
||||
});
|
||||
});
|
||||
|
||||
context('types', () => {
|
||||
it('should handle GeoPoint field', async () => {
|
||||
const docRef = firebase.native.firestore().doc('document-tests/reference');
|
||||
await docRef.set({
|
||||
|
|
|
@ -37,6 +37,13 @@ function firestoreTests({ describe, it, context, firebase }) {
|
|||
.set(sfRef, { name: 'San Francisco' })
|
||||
.update(nycRef, { population: 1000000 })
|
||||
.update(sfRef, 'name', 'San Fran')
|
||||
.update(sfRef, new firebase.native.firestore.FieldPath('name'), 'San Fran FieldPath')
|
||||
.update(sfRef, new firebase.native.firestore.FieldPath('nested', 'name'), 'Nested Nme')
|
||||
.update(
|
||||
sfRef,
|
||||
new firebase.native.firestore.FieldPath('nested', 'firstname'), 'First Name',
|
||||
new firebase.native.firestore.FieldPath('nested', 'lastname'), 'Last Name',
|
||||
)
|
||||
.set(lRef, { population: 3000000 }, { merge: true })
|
||||
.delete(ayRef)
|
||||
.commit()
|
||||
|
@ -53,7 +60,9 @@ function firestoreTests({ describe, it, context, firebase }) {
|
|||
nycDoc.data().population.should.equal(1000000);
|
||||
|
||||
const sfDoc = await sfRef.get();
|
||||
sfDoc.data().name.should.equal('San Fran');
|
||||
sfDoc.data().name.should.equal('San Fran FieldPath');
|
||||
sfDoc.data().nested.firstname.should.equal('First Name');
|
||||
sfDoc.data().nested.lastname.should.equal('Last Name');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue