Firebaseintermediate

Firestore CRUD Operations

Type-safe Firestore repository with CRUD, real-time streams, and pagination.

#firebase#firestore#crud#streams
dart
1import 'package:cloud_firestore/cloud_firestore.dart';
2 
3class FirestoreRepository<T> {
4 final CollectionReference collection;
5 final T Function(Map<String, dynamic> data, String id) fromFirestore;
6 final Map<String, dynamic> Function(T item) toFirestore;
7 
8 FirestoreRepository({
9 required String collectionPath,
10 required this.fromFirestore,
11 required this.toFirestore,
12 }) : collection = FirebaseFirestore.instance.collection(collectionPath);
13 
14 // Create
15 Future<String> add(T item) async {
16 final ref = await collection.add(toFirestore(item));
17 return ref.id;
18 }
19 
20 Future<void> set(String id, T item) async {
21 await collection.doc(id).set(toFirestore(item));
22 }
23 
24 // Read
25 Future<T?> get(String id) async {
26 final doc = await collection.doc(id).get();
27 if (!doc.exists) return null;
28 return fromFirestore(doc.data() as Map<String, dynamic>, doc.id);
29 }
30 
31 Future<List<T>> getAll({int limit = 20}) async {
32 final snapshot = await collection.limit(limit).get();
33 return snapshot.docs
34 .map((d) => fromFirestore(d.data() as Map<String, dynamic>, d.id))
35 .toList();
36 }
37 
38 // Stream (real-time)
39 Stream<List<T>> stream({Query Function(Query q)? query}) {
40 final q = query?.call(collection) ?? collection;
41 return q.snapshots().map(
42 (snapshot) => snapshot.docs
43 .map((d) => fromFirestore(d.data() as Map<String, dynamic>, d.id))
44 .toList(),
45 );
46 }
47 
48 // Update
49 Future<void> update(String id, Map<String, dynamic> data) async {
50 await collection.doc(id).update(data);
51 }
52 
53 // Delete
54 Future<void> delete(String id) async {
55 await collection.doc(id).delete();
56 }
57}
58 
59// Usage example
60final postsRepo = FirestoreRepository<Post>(
61 collectionPath: 'posts',
62 fromFirestore: (data, id) => Post.fromFirestore(data, id),
63 toFirestore: (post) => post.toFirestore(),
64);
65 
66// Real-time stream in widget
67StreamBuilder<List<Post>>(
68 stream: postsRepo.stream(
69 query: (q) => q.where('published', isEqualTo: true).orderBy('createdAt', descending: true),
70 ),
71 builder: (context, snapshot) {
72 if (snapshot.hasError) return Text('Error: ${snapshot.error}');
73 if (!snapshot.hasData) return const CircularProgressIndicator();
74 return ListView.builder(
75 itemCount: snapshot.data!.length,
76 itemBuilder: (_, i) => PostCard(post: snapshot.data![i]),
77 );
78 },
79)