Skip to content

Commit 4b7ea97

Browse files
committed
feat: add comprehensive examples for BulkWriter usage and error handling
1 parent 6944f62 commit 4b7ea97

File tree

1 file changed

+259
-0
lines changed
  • packages/dart_firebase_admin/example/lib

1 file changed

+259
-0
lines changed

packages/dart_firebase_admin/example/lib/main.dart

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'package:dart_firebase_admin/auth.dart';
22
import 'package:dart_firebase_admin/dart_firebase_admin.dart';
33
import 'package:dart_firebase_admin/functions.dart';
44
import 'package:dart_firebase_admin/messaging.dart';
5+
import 'package:googleapis_firestore/googleapis_firestore.dart';
56

67
Future<void> main() async {
78
final admin = FirebaseApp.initializeApp();
@@ -118,6 +119,264 @@ Future<void> firestoreExample(FirebaseApp admin) async {
118119
} catch (e) {
119120
print('> Error with multiple databases: $e');
120121
}
122+
123+
// Example 4: BulkWriter - Basic Usage
124+
print('\n### BulkWriter Examples ###\n');
125+
print('> Basic BulkWriter usage...\n');
126+
127+
try {
128+
final bulkWriter = firestore.bulkWriter();
129+
130+
// Queue multiple write operations
131+
final futures = <Future<WriteResult>>[];
132+
for (var i = 0; i < 10; i++) {
133+
futures.add(
134+
bulkWriter.set(firestore.collection('bulk-demo').doc('item-$i'), {
135+
'name': 'Item $i',
136+
'index': i,
137+
'createdAt': DateTime.now().toIso8601String(),
138+
}),
139+
);
140+
}
141+
142+
// Close and wait for all operations to complete
143+
await bulkWriter.close();
144+
145+
print('> Successfully wrote 10 documents in bulk\n');
146+
} catch (e) {
147+
print('> Error with BulkWriter: $e');
148+
}
149+
150+
// Example 5: BulkWriter - Advanced with Error Handling
151+
print('> BulkWriter with error handling and retry logic...\n');
152+
153+
try {
154+
final bulkWriter = firestore.bulkWriter();
155+
156+
var successCount = 0;
157+
var errorCount = 0;
158+
159+
// Set up success callback
160+
bulkWriter.onWriteResult((ref, result) {
161+
successCount++;
162+
print(' ✓ Success: ${ref.path} at ${result.writeTime}');
163+
});
164+
165+
// Set up error callback with custom retry logic
166+
bulkWriter.onWriteError((error) {
167+
errorCount++;
168+
print(' ✗ Error: ${error.documentRef.path} - ${error.message}');
169+
170+
// Retry on transient errors, but not more than 3 times
171+
if (error.failedAttempts < 3 &&
172+
(error.code.name == 'unavailable' || error.code.name == 'aborted')) {
173+
print(' → Retrying (attempt ${error.failedAttempts + 1})...');
174+
return true; // Retry
175+
}
176+
return false; // Don't retry
177+
});
178+
179+
// Mix of operations: create, set, update, delete
180+
await bulkWriter.create(firestore.collection('orders').doc('order-1'), {
181+
'status': 'pending',
182+
'total': 99.99,
183+
});
184+
185+
await bulkWriter.set(firestore.collection('orders').doc('order-2'), {
186+
'status': 'completed',
187+
'total': 149.99,
188+
});
189+
190+
// Update existing doc (create it first to avoid error)
191+
final orderRef = firestore.collection('orders').doc('order-3');
192+
await orderRef.set({'status': 'processing'});
193+
194+
await bulkWriter.update(orderRef, {
195+
FieldPath(const ['status']): 'shipped',
196+
FieldPath(const ['shippedAt']): DateTime.now().toIso8601String(),
197+
});
198+
199+
await bulkWriter.delete(
200+
firestore.collection('orders').doc('order-to-delete'),
201+
);
202+
203+
await bulkWriter.close();
204+
205+
print('\n> BulkWriter completed:');
206+
print(' - Successful writes: $successCount');
207+
print(' - Failed writes: $errorCount\n');
208+
} catch (e) {
209+
print('> Error with advanced BulkWriter: $e');
210+
}
211+
212+
// Example 6: BulkWriter - Large Batch Processing
213+
print('> BulkWriter processing 100+ documents...\n');
214+
215+
try {
216+
final bulkWriter = firestore.bulkWriter();
217+
final startTime = DateTime.now();
218+
219+
// Process 100 documents efficiently
220+
final futures = <Future<WriteResult>>[];
221+
for (var i = 0; i < 100; i++) {
222+
futures.add(
223+
bulkWriter.set(firestore.collection('analytics').doc('event-$i'), {
224+
'eventType': i % 5 == 0 ? 'pageview' : 'click',
225+
'userId': 'user-${i % 10}',
226+
'timestamp': DateTime.now().toIso8601String(),
227+
'metadata': {'index': i, 'batch': i ~/ 20},
228+
}),
229+
);
230+
}
231+
232+
await bulkWriter.close();
233+
final duration = DateTime.now().difference(startTime);
234+
235+
print('> Processed 100 documents in ${duration.inMilliseconds}ms\n');
236+
} catch (e) {
237+
print('> Error with large batch: $e');
238+
}
239+
240+
// Example 7: BulkWriter - Flush Pattern for Real-time Updates
241+
print('> BulkWriter with flush pattern...\n');
242+
243+
try {
244+
final bulkWriter = firestore.bulkWriter();
245+
246+
// Batch 1: User updates
247+
for (var i = 0; i < 5; i++) {
248+
await bulkWriter.set(firestore.collection('users-batch').doc('user-$i'), {
249+
'name': 'User $i',
250+
'status': 'active',
251+
});
252+
}
253+
254+
// Flush ensures all writes up to this point complete
255+
await bulkWriter.flush();
256+
print(' ✓ Batch 1 flushed (5 user updates)');
257+
258+
// Batch 2: Settings updates (after batch 1 completes)
259+
for (var i = 0; i < 3; i++) {
260+
await bulkWriter.set(firestore.collection('settings').doc('setting-$i'), {
261+
'key': 'setting-$i',
262+
'value': i * 10,
263+
});
264+
}
265+
266+
await bulkWriter.flush();
267+
print(' ✓ Batch 2 flushed (3 settings updates)');
268+
269+
await bulkWriter.close();
270+
print('> Flush pattern completed\n');
271+
} catch (e) {
272+
print('> Error with flush pattern: $e');
273+
}
274+
275+
// Example 8: BulkWriter - Data Migration Pattern
276+
print('> BulkWriter for data migration...\n');
277+
278+
try {
279+
final bulkWriter = firestore.bulkWriter();
280+
281+
// Simulate migrating data from one collection to another
282+
final sourceCollection = firestore.collection('old-data');
283+
final targetCollection = firestore.collection('new-data');
284+
285+
// Create some source data first
286+
for (var i = 0; i < 5; i++) {
287+
await sourceCollection.doc('old-$i').set({
288+
'legacyField': 'value-$i',
289+
'oldFormat': true,
290+
});
291+
}
292+
293+
// Read from source and write to target with transformation
294+
final sourceSnapshot = await sourceCollection.get();
295+
296+
for (final doc in sourceSnapshot.docs) {
297+
final oldData = doc.data() as Map<String, dynamic>;
298+
299+
// Transform data to new format
300+
final newData = {
301+
'newField': oldData['legacyField'],
302+
'migrated': true,
303+
'migratedAt': DateTime.now().toIso8601String(),
304+
'originalId': doc.id,
305+
};
306+
307+
await bulkWriter.set(targetCollection.doc(doc.id), newData);
308+
}
309+
310+
await bulkWriter.close();
311+
print('> Migrated ${sourceSnapshot.docs.length} documents\n');
312+
} catch (e) {
313+
print('> Error with data migration: $e');
314+
}
315+
316+
// Example 9: BulkWriter - Transaction-like Cleanup
317+
print('> BulkWriter with cleanup pattern...\n');
318+
319+
try {
320+
final bulkWriter = firestore.bulkWriter();
321+
322+
var operationsTracked = 0;
323+
324+
bulkWriter.onWriteResult((ref, result) {
325+
operationsTracked++;
326+
});
327+
328+
// Create temp documents
329+
for (var i = 0; i < 5; i++) {
330+
await bulkWriter.set(firestore.collection('temp-data').doc('temp-$i'), {
331+
'temporary': true,
332+
'createdAt': DateTime.now().toIso8601String(),
333+
});
334+
}
335+
336+
await bulkWriter.flush();
337+
print(' ✓ Created 5 temporary documents');
338+
339+
// Do some work...
340+
await Future<void>.delayed(const Duration(milliseconds: 100));
341+
342+
// Clean up temp documents
343+
for (var i = 0; i < 5; i++) {
344+
await bulkWriter.delete(firestore.collection('temp-data').doc('temp-$i'));
345+
}
346+
347+
await bulkWriter.close();
348+
print(' ✓ Cleaned up temporary documents');
349+
print('> Total operations: $operationsTracked\n');
350+
} catch (e) {
351+
print('> Error with cleanup pattern: $e');
352+
}
353+
354+
// Example 10: BulkWriter - Rate Limiting Demonstration
355+
print('> BulkWriter automatic rate limiting...\n');
356+
357+
try {
358+
final bulkWriter = firestore.bulkWriter();
359+
360+
print(' Queueing 500 operations (will be automatically rate-limited)...');
361+
362+
final startTime = DateTime.now();
363+
364+
// Queue many operations - BulkWriter will automatically rate limit
365+
for (var i = 0; i < 500; i++) {
366+
await bulkWriter.set(
367+
firestore.collection('rate-limit-demo').doc('doc-$i'),
368+
{'index': i, 'timestamp': DateTime.now().toIso8601String()},
369+
);
370+
}
371+
372+
await bulkWriter.close();
373+
374+
final duration = DateTime.now().difference(startTime);
375+
print(' ✓ Completed 500 operations in ${duration.inSeconds}s');
376+
print(' (BulkWriter automatically batched and rate-limited)\n');
377+
} catch (e) {
378+
print('> Error with rate limiting demo: $e');
379+
}
121380
}
122381

123382
// ignore: unreachable_from_main

0 commit comments

Comments
 (0)