Skip to content

Commit

Permalink
feat(firestore): support waitForPendingWrites() API (invertase#4176)
Browse files Browse the repository at this point in the history
* Implement waitForPendingWrites
* Remove spurious extra typedoc doc open
* Added test
* Ran prettier and added test of rejection on user change
* Made documentation clearer

Note: This requires firebase-android-sdk bill of materials >= 22.2.0 and firebase-ios-sdk pod >= 6.8.0

Co-authored-by: Mike Hardy <github@mikehardy.net>
  • Loading branch information
markterm and mikehardy authored Aug 30, 2020
1 parent 8a20f45 commit 0b3b0a4
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ Task<Void> clearPersistence(String appName) {
return getFirestoreForApp(appName).clearPersistence();
}

Task<Void> waitForPendingWrites(String appName) {
return getFirestoreForApp(appName).waitForPendingWrites();
}

Task<Void> terminate(String appName) {
FirebaseFirestore firebaseFirestore = getFirestoreForApp(appName);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ public void clearPersistence(String appName, Promise promise) {
});
}

@ReactMethod
public void waitForPendingWrites(String appName, Promise promise) {
module.waitForPendingWrites(appName).addOnCompleteListener(task -> {
if (task.isSuccessful()) {
promise.resolve(null);
} else {
rejectPromiseFirestoreException(promise, task.getException());
}
});
}

@ReactMethod
public void disableNetwork(String appName, Promise promise) {
module.disableNetwork(appName).addOnCompleteListener(task -> {
Expand Down
56 changes: 56 additions & 0 deletions e2e/firestore.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -364,4 +364,60 @@ describe('firestore()', () => {
}
});
});

describe('wait for pending writes', () => {
it('waits for pending writes', async () => {
const waitForPromiseMs = 500;
const testTimeoutMs = 10000;

await firebase.firestore().disableNetwork();

//set up a pending write

const db = firebase.firestore();
const id = 'foobar';
const ref = db.doc(`v6/${id}`);
ref.set({ foo: 'bar' });

//waitForPendingWrites should never resolve, but unfortunately we can only
//test that this is not returning within X ms

let rejected = false;
const timedOutWithNetworkDisabled = await Promise.race([
firebase
.firestore()
.waitForPendingWrites()
.then(
() => false,
() => {
rejected = true;
},
),
Utils.sleep(waitForPromiseMs).then(() => true),
]);

should(timedOutWithNetworkDisabled).equal(true);
should(rejected).equal(false);

//if we sign in as a different user then it should reject the promise
try {
await firebase.auth().signOut();
} catch (e) {}
await firebase.auth().signInAnonymously();
should(rejected).equal(true);

//now if we enable the network then waitForPendingWrites should return immediately
await firebase.firestore().enableNetwork();

const timedOutWithNetworkEnabled = await Promise.race([
firebase
.firestore()
.waitForPendingWrites()
.then(() => false),
Utils.sleep(testTimeoutMs).then(() => true),
]);

should(timedOutWithNetworkEnabled).equal(false);
});
});
});
14 changes: 14 additions & 0 deletions ios/RNFBFirestore/RNFBFirestoreModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,20 @@ + (BOOL)requiresMainQueueSetup {
}];
}

RCT_EXPORT_METHOD(waitForPendingWrites:
(FIRApp *) firebaseApp
: (RCTPromiseResolveBlock) resolve
: (RCTPromiseRejectBlock)reject
) {
[[RNFBFirestoreCommon getFirestoreForApp:firebaseApp] waitForPendingWritesWithCompletion:^(NSError *error) {
if (error) {
[RNFBFirestoreCommon promiseRejectFirestoreException:reject error:error];
} else {
resolve(nil);
}
}];
}

RCT_EXPORT_METHOD(terminate:
(FIRApp *) firebaseApp
: (RCTPromiseResolveBlock) resolve
Expand Down
18 changes: 18 additions & 0 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1969,6 +1969,24 @@ export namespace FirebaseFirestoreTypes {
* ```
*/
clearPersistence(): Promise<void>;
/**
* Waits until all currently pending writes for the active user have been acknowledged by the
* backend.
*
* The returned Promise resolves immediately if there are no outstanding writes. Otherwise, the
* Promise waits for all previously issued writes (including those written in a previous app
* session), but it does not wait for writes that were added after the method is called. If you
* want to wait for additional writes, call `waitForPendingWrites()` again.
*
* Any outstanding `waitForPendingWrites()` Promises are rejected when the logged-in user changes.
*
* #### Example
*
*```js
* await firebase.firestore().waitForPendingWrites();
* ```
*/
waitForPendingWrites(): Promise<void>;
/**
* Typically called to ensure a new Firestore instance is initialized before calling
* `firebase.firestore().clearPersistence()`.
Expand Down
4 changes: 4 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ class FirebaseFirestoreModule extends FirebaseModule {
await this.native.clearPersistence();
}

async waitForPendingWrites() {
await this.native.waitForPendingWrites();
}

async terminate() {
await this.native.terminate();
}
Expand Down

0 comments on commit 0b3b0a4

Please sign in to comment.