From b0abf23c6d3fd5dd7de29b69953219af5a957c9f Mon Sep 17 00:00:00 2001 From: Chris Bianca Date: Fri, 13 Apr 2018 09:58:53 +0100 Subject: [PATCH] [firestore] Add support for settings --- .../firestore/RNFirebaseFirestore.java | 21 +++++++ .../firestore/RNFirebaseFirestore.m | 22 +++++++ lib/index.d.ts | 17 ++--- lib/modules/firestore/index.js | 55 ++++++++++++---- lib/utils/index.js | 9 +++ tests/src/firebase.js | 7 +++ tests/src/tests/firestore/firestoreTests.js | 63 ++++++++++++++++--- 7 files changed, 166 insertions(+), 28 deletions(-) diff --git a/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestore.java b/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestore.java index 339cf948..ccddad12 100644 --- a/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestore.java +++ b/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestore.java @@ -199,6 +199,27 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule { ref.update(data, promise); } + @ReactMethod + public void settings(String appName, ReadableMap settings, final Promise promise) { + FirebaseFirestore firestore = getFirestoreForApp(appName); + FirebaseFirestoreSettings.Builder firestoreSettings = new FirebaseFirestoreSettings.Builder(); + if (settings.hasKey("host")) { + firestoreSettings.setHost(settings.getString("host")); + } + if (settings.hasKey("persistence")) { + firestoreSettings.setPersistenceEnabled(settings.getBoolean("persistence")); + } + if (settings.hasKey("ssl")) { + firestoreSettings.setSslEnabled(settings.getBoolean("ssl")); + } + if (settings.hasKey("timestampsInSnapshots")) { + // TODO: Not supported on Android yet + } + + firestore.setFirestoreSettings(firestoreSettings.build()); + promise.resolve(null); + } + /** * Try clean up previous transactions on reload diff --git a/ios/RNFirebase/firestore/RNFirebaseFirestore.m b/ios/RNFirebase/firestore/RNFirebaseFirestore.m index 8e9df4c0..f3a53bd4 100644 --- a/ios/RNFirebase/firestore/RNFirebaseFirestore.m +++ b/ios/RNFirebase/firestore/RNFirebaseFirestore.m @@ -338,6 +338,28 @@ RCT_EXPORT_METHOD(documentUpdate:(NSString *)appDisplayName [[self getDocumentForAppPath:appDisplayName path:path] update:data resolver:resolve rejecter:reject]; } +RCT_EXPORT_METHOD(settings:(NSString *)appDisplayName + settings:(NSDictionary *)settings + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + FIRFirestore *firestore = [RNFirebaseFirestore getFirestoreForApp:appDisplayName]; + FIRFirestoreSettings *firestoreSettings = [[FIRFirestoreSettings alloc] init]; + if (settings[@"host"]) { + firestoreSettings.host = settings[@"host"]; + } + if (settings[@"persistence"]) { + firestoreSettings.persistenceEnabled = settings[@"persistence"]; + } + if (settings[@"ssl"]) { + firestoreSettings.sslEnabled = settings[@"ssl"]; + } + if (settings[@"timestampsInSnapshots"]) { + firestoreSettings.timestampsInSnapshotsEnabled = settings[@"timestampsInSnapshots"]; + } + [firestore setSettings:firestoreSettings]; + resolve(nil); +} + /* * INTERNALS/UTILS */ diff --git a/lib/index.d.ts b/lib/index.d.ts index 2028a6a9..abb8164b 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1467,14 +1467,10 @@ declare module "react-native-firebase" { collection(collectionPath: string): CollectionReference; disableNetwork(): Promise doc(documentPath: string): DocumentReference; - enableNetwork(): Promise + enableNetwork(): Promise; + enablePersistence(enabled: boolean): Promise; runTransaction(updateFunction: (transaction: Transaction) => Promise): Promise; - /** NOT SUPPORTED YET */ - // enablePersistence(): Promise; - /** NOT SUPPORTED YET */ - // runTransaction(): Promise; - /** NOT SUPPORTED YET */ - // settings(): void; + settings(settings: Settings): Promise; } interface FirestoreStatics { @@ -1667,6 +1663,13 @@ declare module "react-native-firebase" { } } + interface Settings { + host?: string; + persistence?: boolean; + ssl?: boolean; + timestampsInSnapshots?: boolean; + } + interface Transaction { delete(docRef: DocumentReference): WriteBatch; get(documentRef: DocumentReference): Promise; diff --git a/lib/modules/firestore/index.js b/lib/modules/firestore/index.js index 3a85d8d6..ffcdb3a5 100644 --- a/lib/modules/firestore/index.js +++ b/lib/modules/firestore/index.js @@ -15,6 +15,7 @@ import Path from './Path'; import WriteBatch from './WriteBatch'; import TransactionHandler from './TransactionHandler'; import Transaction from './Transaction'; +import { isBoolean, isObject, isString } from '../../utils'; import { getNativeModule } from '../../utils/native'; import type DocumentSnapshot from './DocumentSnapshot'; @@ -37,6 +38,13 @@ type DocumentSyncEvent = { path: string, }; +type Settings = { + host?: string, + persistence?: boolean, + ssl?: boolean, + timestampsInSnapshots?: boolean, +}; + const NATIVE_EVENTS = [ 'firestore_transaction_event', 'firestore_document_sync_event', @@ -151,24 +159,49 @@ export default class Firestore extends ModuleBase { return this._transactionHandler._add(updateFunction); } + settings(settings: Settings): Promise { + if (!isObject(settings)) { + return Promise.reject( + new Error('Firestore.settings failed: settings must be an object.') + ); + } else if (settings.host && !isString(settings.host)) { + return Promise.reject( + new Error('Firestore.settings failed: settings.host must be a string.') + ); + } else if (settings.persistence && !isBoolean(settings.persistence)) { + return Promise.reject( + new Error( + 'Firestore.settings failed: settings.persistence must be boolean.' + ) + ); + } else if (settings.ssl && !isBoolean(settings.ssl)) { + return Promise.reject( + new Error('Firestore.settings failed: settings.ssl must be boolean.') + ); + } else if ( + settings.timestampsInSnapshots && + !isBoolean(settings.timestampsInSnapshots) + ) { + return Promise.reject( + new Error( + 'Firestore.settings failed: settings.timestampsInSnapshots must be boolean.' + ) + ); + } + return getNativeModule(this).settings(settings); + } + /** * ------------- * UNSUPPORTED * ------------- */ - /** - * ------------- - * MISC - * ------------- - */ - enablePersistence(): Promise { - throw new Error('Persistence is enabled by default on the Firestore SDKs'); - } - - settings(): void { - throw new Error('firebase.firestore().settings() coming soon'); + console.warn( + 'Due to restrictions in the native SDK, persistence must be configured in firebase.firestore().settings()' + ); + return Promise.resolve(); } /** diff --git a/lib/utils/index.js b/lib/utils/index.js index dc539b14..9afaa96e 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -141,6 +141,15 @@ export function isString(value: mixed): boolean %checks { return typeof value === 'string'; } +/** + * Simple is boolean check + * @param value + * @return {boolean} + */ +export function isBoolean(value: mixed): boolean %checks { + return typeof value === 'boolean'; +} + // platform checks export const isIOS = Platform.OS === 'ios'; export const isAndroid = Platform.OS === 'android'; diff --git a/tests/src/firebase.js b/tests/src/firebase.js index 785106ac..31ee4787 100644 --- a/tests/src/firebase.js +++ b/tests/src/firebase.js @@ -4,6 +4,13 @@ import firebase from 'firebase'; import RNfirebase from './../firebase'; import DatabaseContents from './tests/support/DatabaseContents'; +// Verify firestore settings works +RNfirebase.firestore().settings({ + persistence: true, + ssl: true, + timestampsInSnapshots: false, +}); + // Verify logging works RNfirebase.database.enableLogging(true); RNfirebase.database.enableLogging(false); diff --git a/tests/src/tests/firestore/firestoreTests.js b/tests/src/tests/firestore/firestoreTests.js index f501dd10..9bb65984 100644 --- a/tests/src/tests/firestore/firestoreTests.js +++ b/tests/src/tests/firestore/firestoreTests.js @@ -134,12 +134,8 @@ function firestoreTests({ before, describe, it, context, firebase }) { }); context('enablePersistence()', () => { - it('should throw an unsupported error', () => { - (() => { - firebase.native.firestore().enablePersistence(); - }).should.throw( - 'Persistence is enabled by default on the Firestore SDKs' - ); + it('should work without error', async () => { + await firebase.native.firestore().enablePersistence(); }); }); @@ -160,10 +156,57 @@ function firestoreTests({ before, describe, it, context, firebase }) { }); context('settings()', () => { - it('should throw an unsupported error', () => { - (() => { - firebase.native.firestore().settings(); - }).should.throw('firebase.firestore().settings() coming soon'); + it('should reject invalid object', async () => { + try { + await firebase.native.firestore().settings('test'); + Promise.reject(new Error('Did not error on invalid object')); + } catch (error) { + // test passed + } + }); + + it('should reject invalid host setting', async () => { + try { + await firebase.native.firestore().settings({ host: true }); + Promise.reject(new Error('Did not error on invalid `host` setting')); + } catch (error) { + // test passed + } + }); + + it('should reject invalid persistence setting', async () => { + try { + await firebase.native.firestore().settings({ persistence: 'fail' }); + Promise.reject( + new Error('Did not error on invalid `persistence` setting') + ); + } catch (error) { + // test passed + } + }); + + it('should reject invalid ssl setting', async () => { + try { + await firebase.native.firestore().settings({ ssl: 'fail' }); + Promise.reject(new Error('Did not error on invalid `ssl` setting')); + } catch (error) { + // test passed + } + }); + + it('should reject invalid timestampsInSnapshots setting', async () => { + try { + await firebase.native + .firestore() + .settings({ timestampsInSnapshots: 'fail' }); + Promise.reject( + new Error( + 'Did not error on invalid `timestampsInSnapshots` setting' + ) + ); + } catch (error) { + // test passed + } }); });