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

Commit 48a99cc

Browse files
Batch and Transaction Operation in FireStore #667
1 parent a556314 commit 48a99cc

File tree

8 files changed

+64
-73
lines changed

8 files changed

+64
-73
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
[Firebase iOS SDK Changelog](https://firebase.google.com/support/release-notes/ios)
44
[Firebase Android SDK Changelog](https://firebase.google.com/support/release-notes/android)
55

6+
## 6.5.0 (2018, August ?)
7+
[Fixes & Enhancements](https://github.com/EddyVerbruggen/nativescript-plugin-firebase/milestone/65?closed=1)
8+
9+
610
## 6.4.1 (2018, July 28)
711
[Fixes & Enhancements](https://github.com/EddyVerbruggen/nativescript-plugin-firebase/milestone/64?closed=1)
812

demo-ng/app/tabs/firestore/firestore.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
<Button text="Where, Order, Limit" (tap)="firestoreWhereOrderLimit()" class="button"></Button>
2626
<Button text="Where array_contains" (tap)="firestoreWhereCityHasALake()" class="button"></Button>
2727
<Button text="Delete" (tap)="firestoreDelete()" class="button"></Button>
28-
<!--<Button text="Transactional update" (tap)="transactionalUpdate()" class="button"></Button>-->
28+
<Button text="Transactional update (iOS)" (tap)="transactionalUpdate()" class="button"></Button>
2929
<Button text="Write batch" (tap)="writeBatch()" class="button"></Button>
3030
</StackLayout>
3131
</ScrollView>

demo-ng/app/tabs/firestore/firestore.component.ts

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -286,13 +286,25 @@ export class FirestoreComponent {
286286
const path = "/companies";
287287
firebase.database().ref(path)
288288
.once("value")
289-
.then(result => {
290-
console.log(`${result.key} => ${JSON.stringify(result.val())}`);
291-
})
289+
.then(result => console.log(`${result.key} => ${JSON.stringify(result.val())}`))
292290
.catch(error => console.log("doWebGetValueForCompanies error: " + error));
293291
}
294292

295-
/*
293+
public writeBatch(): void {
294+
// one batch can update multiple docs
295+
const sfDocRef: firestore.DocumentReference = firebase.firestore().collection("cities").doc("SF");
296+
const sacDocRef: firestore.DocumentReference = firebase.firestore().collection("cities").doc("SAC");
297+
298+
firebase.firestore().batch()
299+
.set(sfDocRef, {capital: false}, {merge: true})
300+
// .delete(sfDocRef) // Want to verify batches are atomic? With this line enabled, the next line will fail and the entire batch is rolled back correctly 👍
301+
.update(sfDocRef, {population: 860100})
302+
.update(sacDocRef, {population: 6500100})
303+
.commit()
304+
.then(() => console.log(`Batch successfully committed`))
305+
.catch(error => console.log("Batch error: " + error));
306+
}
307+
296308
public transactionalUpdate(): void {
297309
const sfDocRef: firestore.DocumentReference = firebase.firestore().collection("cities").doc("SF");
298310

@@ -304,7 +316,6 @@ export class FirestoreComponent {
304316
const newPopulation = sfDoc.data().population + 1;
305317
console.log(`Updating city 'SF' to a new population of: ${newPopulation}, and flipping the 'capital' state to ${sfDoc.data().capital}.`);
306318

307-
// this should fail
308319
transaction
309320
.set(sfDocRef, {capital: !sfDoc.data().capital}, {merge: true})
310321
// .delete(sfDocRef) // with this line enabled, the next line will fail and the entire tx is rolled back 👍
@@ -315,20 +326,4 @@ export class FirestoreComponent {
315326
.then(() => console.log(`Transaction successfully committed`))
316327
.catch(error => console.log("doTransaction error: " + error));
317328
}
318-
*/
319-
320-
public writeBatch(): void {
321-
// one batch can update multiple docs
322-
const sfDocRef: firestore.DocumentReference = firebase.firestore().collection("cities").doc("SF");
323-
const sacDocRef: firestore.DocumentReference = firebase.firestore().collection("cities").doc("SAC");
324-
325-
firebase.firestore().batch()
326-
.set(sfDocRef, {capital: false}, {merge: true})
327-
// .delete(sfDocRef) // Want to verify batches are atomic? With this line enabled, the next line will fail and the entire batch is rolled back correctly 👍
328-
.update(sfDocRef, {population: 860100})
329-
.update(sacDocRef, {population: 6500100})
330-
.commit()
331-
.then(() => console.log(`Batch successfully committed`))
332-
.catch(error => console.log("Batch error: " + error));
333-
}
334329
}

docs/FIRESTORE.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ query
237237
});
238238
```
239239

240-
### `batch()`
240+
### Batched Writes: `batch()`
241241
To perform a (mixed) sequence of `set`, `update`, and/or `delete` operations in an atomic fashion
242242
(everything is rolled back if 1 operation fails), use the `batch` feature.
243243

@@ -263,5 +263,32 @@ firebase.firestore().batch()
263263
.update(sanFranciscoDocumentReference, {population: 7})
264264
.commit()
265265
.then(() => console.log("Batch successfully committed"))
266-
.catch(error => console.log("Batch error: " + error));
266+
.catch(error => console.log(`Batch error: ${error}`));
267+
```
268+
269+
### Transactional Updates: `runTransaction()` (iOS only)
270+
> There's a technical hurdle which prevents this from working on Android.
271+
272+
In contrast to `batch` you can `runTransaction` to also be able to use `get`, but only use `get`
273+
before calling `set`, `update`, or `delete` (or the transaction will fail).
274+
275+
```typescript
276+
const sanFranciscoDocumentReference: firestore.DocumentReference = firebase.firestore().collection("cities").doc("SF");
277+
278+
firebase.firestore().runTransaction(transaction => {
279+
const doc = transaction.get(sanFranciscoDocumentReference);
280+
if (!doc.exists) {
281+
console.log("City SF doesn't exist");
282+
} else {
283+
const newPopulation = doc.data().population + 1;
284+
console.log(`Updating city 'SF' to a new population of: ${newPopulation}, and flipping the 'capital' state to ${sfDoc.data().capital}.`);
285+
286+
transaction
287+
.set(sanFranciscoDocumentReference, {capital: !doc.data().capital}, {merge: true})
288+
.update(sanFranciscoDocumentReference, {population: newPopulation})
289+
}
290+
return null;
291+
})
292+
.then(() => console.log("Transaction successfully committed"))
293+
.catch(error => console.log(`Transaction error: ${error}`));
267294
```

src/app/firestore/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ export module firestore {
1616
return firebase.firestore.GeoPoint(latitude, longitude);
1717
}
1818

19-
// runTransaction<T>(updateFunction: (transaction: firebase.firestore.Transaction) => Promise<any>): Promise<void> {
20-
// return firebase.firestore.runTransaction(updateFunction);
21-
// }
19+
runTransaction<T>(updateFunction: (transaction: firebase.firestore.Transaction) => Promise<any>): Promise<void> {
20+
return firebase.firestore.runTransaction(updateFunction);
21+
}
2222

2323
batch(): firebase.firestore.WriteBatch {
2424
return firebase.firestore.batch();

src/firebase.android.ts

Lines changed: 10 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2161,6 +2161,13 @@ firebase.firestore.batch = (): firestore.WriteBatch => {
21612161
return batch;
21622162
};
21632163

2164+
firebase.firestore.runTransaction = (updateFunction: (transaction: firestore.Transaction) => Promise<any>): Promise<void> => {
2165+
return new Promise((resolve, reject) => {
2166+
// Why? See the note in the commented 'runTransaction' function below.
2167+
reject("Not supported on Android. If you need a x-platform implementation, use 'batch' instead.");
2168+
});
2169+
};
2170+
21642171
/*
21652172
class FirestoreTransaction implements firestore.Transaction {
21662173
@@ -2172,7 +2179,6 @@ class FirestoreTransaction implements firestore.Transaction {
21722179
};
21732180
21742181
public set = (documentRef: firestore.DocumentReference, data: firestore.DocumentData, options?: firestore.SetOptions): firestore.Transaction => {
2175-
console.log(">>> in tx.set");
21762182
if (options && options.merge) {
21772183
this.nativeTransaction.set(documentRef.android, firebase.toValue(data), com.google.firebase.firestore.SetOptions.merge());
21782184
} else {
@@ -2182,13 +2188,11 @@ class FirestoreTransaction implements firestore.Transaction {
21822188
};
21832189
21842190
public update = (documentRef: firestore.DocumentReference, data: firestore.UpdateData): firestore.Transaction => {
2185-
console.log(">>> in tx.update");
21862191
this.nativeTransaction.update(documentRef.android, firebase.toValue(data));
21872192
return this;
21882193
};
21892194
21902195
public delete = (documentRef: firestore.DocumentReference): firestore.Transaction => {
2191-
console.log(">>> in tx.delete");
21922196
this.nativeTransaction.delete(documentRef.android);
21932197
return this;
21942198
}
@@ -2209,49 +2213,16 @@ firebase.firestore.runTransaction = (updateFunction: (transaction: firestore.Tra
22092213
}
22102214
});
22112215
2212-
const l = new java.util.ArrayList();
2213-
l.add("foooo");
2214-
l.add("barrr");
2215-
org.nativescript.plugins.firebase.FirebaseFirestore.STATE = onSuccessListenert; // for this assignment to 'stick', this needs to be a real Java object
2216-
org.nativescript.plugins.firebase.FirebaseFirestore.UPDATE_FUNCTION = updateFunction;
2217-
console.log(">>> STATE: " + org.nativescript.plugins.firebase.FirebaseFirestore.STATE);
2218-
console.log(">>> UPDATE_FUNCTION: " + org.nativescript.plugins.firebase.FirebaseFirestore.UPDATE_FUNCTION);
2219-
2220-
let worker;
2221-
if (global['TNS_WEBPACK']) {
2222-
const WorkerScript = require('nativescript-worker-loader!./android-firestoretx-worker.js');
2223-
worker = new WorkerScript();
2224-
} else {
2225-
worker = new Worker('./android-firestoretx-worker.js');
2226-
}
2227-
2228-
(<any>global).theUpdateFunction = updateFunction;
2229-
2230-
worker.onmessage = msg => {
2231-
console.log(">>> msg from worker, stringified: " + JSON.stringify(msg));
2232-
};
2233-
2234-
worker.onerror = err => {
2235-
console.log(">>> worker err: " + JSON.stringify(err));
2236-
};
2237-
2238-
worker.postMessage({
2239-
in: "innn",
2240-
someArray: l,
2241-
onSuccessListenert: onSuccessListenert
2242-
// updateFunction: updateFunction
2243-
});
2244-
22452216
const onSuccessListener = new com.google.android.gms.tasks.OnSuccessListener({
2246-
onSuccess: resolve // TODO does this syntax work? if so: refactor other instances... otherwise use: onSuccess: () => resolve()
2217+
onSuccess: () => resolve()
22472218
});
22482219
22492220
const onFailureListener = new com.google.android.gms.tasks.OnFailureListener({
22502221
onFailure: exception => reject(exception.getMessage())
22512222
});
22522223
2253-
// TODO apply is called from java to js, so that makes it run on the main/UI thread.. so doesn't work
2254-
// .. can we share native objects via appcontext (for a worker)?
2224+
// NOTE: Here's the problem: 'apply' is called from java to js, so that makes it run on the main/UI thread,
2225+
// which is not allowed by Firebase.. so doesn't work in {N}
22552226
const txFunction = new com.google.firebase.firestore.Transaction.Function({
22562227
apply: (nativeTransaction: com.google.firebase.firestore.Transaction) => {
22572228
const tx = new firebase.firestore.Transaction(nativeTransaction);
@@ -2262,8 +2233,6 @@ firebase.firestore.runTransaction = (updateFunction: (transaction: firestore.Tra
22622233
com.google.firebase.firestore.FirebaseFirestore.getInstance().runTransaction(txFunction)
22632234
.addOnSuccessListener(onSuccessListener)
22642235
.addOnFailureListener(onFailureListener);
2265-
2266-
// org.nativescript.plugins.firebase.FirebaseFirestore.runTransaction(txFunction, onSuccessListener, onFailureListener);
22672236
});
22682237
};
22692238
*/

src/firebase.d.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -771,15 +771,13 @@ export namespace firestore {
771771
static documentId(): FieldPath;
772772
}
773773

774-
/*
775774
export interface Transaction {
776775
get(documentRef: DocumentReference): DocumentSnapshot;
777776
set(documentRef: DocumentReference, data: DocumentData, options?: SetOptions): Transaction;
778777
update(documentRef: DocumentReference, data: UpdateData): Transaction;
779778
update(documentRef: DocumentReference, field: string | FieldPath, value: any, ...moreFieldsAndValues: any[]): Transaction;
780779
delete(documentRef: DocumentReference): Transaction;
781780
}
782-
*/
783781

784782
export interface WriteBatch {
785783
set(documentRef: DocumentReference, data: DocumentData, options?: SetOptions): WriteBatch;
@@ -813,7 +811,7 @@ export namespace firestore {
813811

814812
function update(collectionPath: string, documentPath: string, document: any): Promise<void>;
815813

816-
// function runTransaction(updateFunction: (transaction: firestore.Transaction) => Promise<any>): Promise<void>;
814+
function runTransaction(updateFunction: (transaction: firestore.Transaction) => Promise<any>): Promise<void>;
817815

818816
function batch(): firestore.WriteBatch;
819817
}

src/firebase.ios.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2146,7 +2146,6 @@ firebase.firestore.batch = (): firestore.WriteBatch => {
21462146
return new firebase.firestore.WriteBatch(FIRFirestore.firestore().batch());
21472147
};
21482148

2149-
/*
21502149
firebase.firestore.Transaction = (nativeTransaction: FIRTransaction): firestore.Transaction => {
21512150
class FirestoreTransaction implements firestore.Transaction {
21522151
constructor() {
@@ -2188,7 +2187,6 @@ firebase.firestore.runTransaction = (updateFunction: (transaction: firestore.Tra
21882187
(result, error: NSError) => error ? reject(error.localizedDescription) : resolve());
21892188
});
21902189
};
2191-
*/
21922190

21932191
firebase.firestore.collection = (collectionPath: string): firestore.CollectionReference => {
21942192
try {

0 commit comments

Comments
 (0)