Skip to content
This repository was archived by the owner on Apr 4, 2023. It is now read-only.

Commit 43e0fd0

Browse files
Merge remote-tracking branch 'origin/master'
2 parents 9dab2b9 + bc1c560 commit 43e0fd0

3 files changed

Lines changed: 51 additions & 8 deletions

File tree

docs/DATABASE.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,9 @@ same time.
416416
You can look at the [docs](https://firebase.google.com/docs/reference/js/firebase.database.Reference#transaction) for more information.
417417

418418
Note that a return value of `null` will delete the value at this location whereas returning
419-
undefined will abort the transaction. On success a promise is returned containing
419+
undefined will not modify the data at this location. Firebase web aborts the transaction when
420+
given an undefined, but due to technically difficulties we just return transaction success which
421+
results in committed = true. On transaction complete a promise is returned containing
420422
{committed:boolean, snapshot: DataSnapshot} and an error will be returned if the transaciton
421423
failed.
422424

@@ -463,6 +465,25 @@ firebaseWebApi.database().ref(path).transaction(currentValue => {
463465
return ++currentValue; // increment the value
464466
}
465467
})
468+
469+
// Based off Firebase simple blog post. You can also treat the
470+
// data as an object and return an updated version of post
471+
firebaseWebApi.database().ref(path).transaction(function(post) {
472+
if (post) {
473+
console.log("Post Object looks like: " + JSON.stringify(post));
474+
if (post.stars && post.stars[uid]) {
475+
post.starCount--;
476+
post.stars[uid] = null;
477+
} else {
478+
post.starCount++;
479+
if (!post.stars) {
480+
post.stars = {};
481+
}
482+
post.stars[uid] = true;
483+
}
484+
}
485+
return post;
486+
});
466487
```
467488
</details>
468489

src/firebase.android.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1807,14 +1807,22 @@ firebase.transaction = (path: string, transactionUpdate: (currentState) => any,
18071807
const dbRef: com.google.firebase.database.DatabaseReference = firebase.instance.child(path);
18081808
const handler: com.google.firebase.database.Transaction.Handler = new com.google.firebase.database.Transaction.Handler({
18091809
doTransaction: (mutableData: com.google.firebase.database.MutableData) => {
1810-
const desiredValue = transactionUpdate(mutableData.getValue());
1810+
const desiredValue = transactionUpdate(firebase.toJsObject(mutableData.getValue()));
18111811
// Java does not have undefined, but web transactions use undefined to detect if an abort() is desired.
18121812
if (desiredValue === undefined) {
1813-
return com.google.firebase.database.Transaction.abort();
1814-
} else {
1815-
mutableData.setValue(firebase.toValue(desiredValue));
1813+
// Same problem as iOS. The very first call to runTransaction will see that we get undefined
1814+
// and immediately abort the transaction which results in us failing to update the value. Subsequent
1815+
// calls are working fine unlike in iOS which always fail.
1816+
1817+
// TLDR: Abort would be ideal, but atm it can result in a failed update (when it shouln't)
1818+
// Returning success fixes this but makes our { committed: always true }...
1819+
1820+
// return com.google.firebase.database.Transaction.abort();
18161821
return com.google.firebase.database.Transaction.success(mutableData);
18171822
}
1823+
mutableData.setValue(firebase.toValue(desiredValue));
1824+
return com.google.firebase.database.Transaction.success(mutableData);
1825+
18181826
},
18191827
onComplete: (databaseError: com.google.firebase.database.DatabaseError, commited: boolean, snapshot: com.google.firebase.database.DataSnapshot) => {
18201828
databaseError !== null ? reject(databaseError.getMessage()) :

src/firebase.ios.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as firebaseMessaging from "./messaging/messaging";
99
import * as application from "tns-core-modules/application/application";
1010
import { ios as iOSUtils } from "tns-core-modules/utils/utils";
1111
import * as firebaseFunctions from './functions/functions';
12-
import { firestore, User, OnDisconnect as OnDisconnectBase, transaction, DataSnapshot } from "./firebase";
12+
import { firestore, User, OnDisconnect as OnDisconnectBase, DataSnapshot } from "./firebase";
1313
import { firebaseUtils } from "./utils";
1414

1515
firebase._gIDAuthentication = null;
@@ -1546,9 +1546,23 @@ firebase.transaction = (path: string, transactionUpdate: (currentState) => any,
15461546

15471547
dbRef.runTransactionBlockAndCompletionBlock(
15481548
(mutableData: FIRMutableData): FIRTransactionResult => {
1549-
const desiredValue = transactionUpdate(mutableData.value);
1549+
const desiredValue = transactionUpdate(firebaseUtils.toJsObject(mutableData.value));
15501550
if (desiredValue === undefined) {
1551-
return FIRTransactionResult.abort();
1551+
// The problem case : user returns undefined when the the value we give them (mutableData) is null.
1552+
// This is a valid case as the user will want to abort if he thinks theres no data, BUT mutualData
1553+
// is usually null when runTransaction is called the first time(which is why its called multiple times).
1554+
// Result: we would abort and the transaction terminates, but the real data didn't have a chance to come in
1555+
// for the function to be called a second time.
1556+
// Even in the ios simple blog example their complete block is called twice with committed first being false
1557+
// followed by a second one saying committed is true... So with this implementation I favored having an "incorrect"
1558+
// committed boolean, but have the correct updated value
1559+
1560+
// TLDR: if user returns undefined then we may never execute his function with the correct input
1561+
// For now the way to resolve this is to call success with the original value (so we don't modify anything)
1562+
// And then the user will get his expected value, but { committed: always true }....
1563+
1564+
// return FIRTransactionResult.abort();
1565+
return FIRTransactionResult.successWithValue(mutableData);
15521566
} else {
15531567
mutableData.value = desiredValue;
15541568
return FIRTransactionResult.successWithValue(mutableData);

0 commit comments

Comments
 (0)