Firebase
Firebase integration guide for Talon
Firebase Integration
This guide shows how to integrate Talon with Firebase Firestore.
Overview
Firebase Firestore works well with Talon:
- Real-time listeners for subscriptions
- Batch writes for efficient sync
- Offline support built-in
Schema
Create a messages collection:
// Firestore security rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /messages/{messageId} {
allow read: if request.auth != null
&& resource.data.user_id == request.auth.uid;
allow create: if request.auth != null
&& request.resource.data.user_id == request.auth.uid;
}
}
}
Implementation
class FirebaseServerDatabase extends ServerDatabase {
final FirebaseFirestore _firestore;
FirebaseServerDatabase(this._firestore);
@override
Future<List<Message>> getMessagesFromServer({
required int? lastSyncedServerTimestamp,
required String clientId,
required String userId,
}) async {
var query = _firestore
.collection('messages')
.where('user_id', isEqualTo: userId)
.where('client_id', isNotEqualTo: clientId);
if (lastSyncedServerTimestamp != null) {
query = query.where('server_timestamp',
isGreaterThan: lastSyncedServerTimestamp);
}
final snapshot = await query.orderBy('server_timestamp').get();
return snapshot.docs.map((doc) {
final data = doc.data();
return Message(
id: doc.id,
table: data['table_name'],
row: data['row'],
column: data['column'],
dataType: data['data_type'] ?? '',
value: data['value'],
serverTimestamp: data['server_timestamp'],
localTimestamp: data['local_timestamp'],
userId: data['user_id'],
clientId: data['client_id'],
hasBeenApplied: false,
hasBeenSynced: true,
);
}).toList();
}
@override
Future<bool> sendMessageToServer({required Message message}) async {
try {
await _firestore.collection('messages').doc(message.id).set({
'table_name': message.table,
'row': message.row,
'column': message.column,
'data_type': message.dataType,
'value': message.value,
'local_timestamp': message.localTimestamp,
'user_id': message.userId,
'client_id': message.clientId,
'server_timestamp': FieldValue.serverTimestamp(),
});
return true;
} catch (e) {
return false;
}
}
@override
StreamSubscription subscribeToServerMessages({
required String clientId,
required String userId,
required int? lastSyncedServerTimestamp,
required void Function(List<Message>) onMessagesReceived,
}) {
return _firestore
.collection('messages')
.where('user_id', isEqualTo: userId)
.snapshots()
.listen((snapshot) {
final messages = snapshot.docs
.where((doc) => doc.data()['client_id'] != clientId)
.map((doc) {
final data = doc.data();
return Message(
id: doc.id,
table: data['table_name'],
// ... other fields
);
})
.toList();
if (messages.isNotEmpty) {
onMessagesReceived(messages);
}
});
}
}