Implementation Overview

What you need to implement to use Talon

Implementation Overview

To use Talon, you need to implement two interfaces that connect it to your databases.

Required Implementations

┌─────────────────────────────────────────────────────────────┐
│                         TALON                                │
│                                                              │
│  Handles: Sync logic, HLC, conflict resolution, streams     │
│                                                              │
├──────────────────────────┬───────────────────────────────────┤
│                          │                                   │
│  OfflineDatabase         │  ServerDatabase                   │
│  (you implement)         │  (you implement)                  │
│                          │                                   │
│  ┌────────────────────┐  │  ┌─────────────────────────────┐ │
│  │ sqflite / Drift /  │  │  │ Supabase / Firebase /       │ │
│  │ Hive / Isar        │  │  │ REST API / GraphQL          │ │
│  └────────────────────┘  │  └─────────────────────────────┘ │
│                          │                                   │
└──────────────────────────┴───────────────────────────────────┘

OfflineDatabase

Connects Talon to your local database:

MethodPurpose
init()Create tables
applyMessageToLocalDataTable()Update your data
applyMessageToLocalMessageTable()Store messages
getExistingTimestamp()Query for conflicts
getUnsyncedMessages()Get messages to sync
markMessagesAsSynced()Update sync status
readLastSyncedServerTimestamp()Track sync progress
saveLastSyncedServerTimestamp()Save sync progress

Full OfflineDatabase Guide →

ServerDatabase

Connects Talon to your backend:

MethodPurpose
getMessagesFromServer()Pull changes
sendMessageToServer()Push single change
sendMessagesToServer()Push batch (optional)
subscribeToServerMessages()Real-time updates

Full ServerDatabase Guide →

Estimated Setup

ComponentLines of CodeTime
OfflineDatabase~100-15030 min
ServerDatabase~50-10020 min
Schema setup~3010 min
Total~200-300~1 hour

Quick Reference

Minimal OfflineDatabase

class MyOfflineDatabase extends OfflineDatabase {
  final Database db;
  MyOfflineDatabase(this.db);

  @override
  Future<void> init() async {
    await db.execute(TalonSchema.messagesTableSql);
  }

  @override
  Future<bool> applyMessageToLocalDataTable(Message message) async {
    // UPDATE your_table SET column = value WHERE id = row
    return true;
  }

  @override
  Future<bool> applyMessageToLocalMessageTable(Message message) async {
    await db.insert('talon_messages', message.toMap());
    return true;
  }

  @override
  Future<String?> getExistingTimestamp({
    required String table, required String row, required String column,
  }) async {
    // Query for existing HLC timestamp
    return null;
  }

  @override
  Future<List<Message>> getUnsyncedMessages() async {
    final rows = await db.query('talon_messages', where: 'hasBeenSynced = 0');
    return rows.map((r) => Message.fromMap(r)).toList();
  }

  @override
  Future<void> markMessagesAsSynced(List<String> ids) async {
    // UPDATE talon_messages SET hasBeenSynced = 1 WHERE id IN (...)
  }

  @override
  Future<int?> readLastSyncedServerTimestamp() async => null;

  @override
  Future<void> saveLastSyncedServerTimestamp(int timestamp) async {}
}

Minimal ServerDatabase

class MyServerDatabase extends ServerDatabase {
  final SupabaseClient supabase;
  MyServerDatabase(this.supabase);

  @override
  Future<List<Message>> getMessagesFromServer({
    required int? lastSyncedServerTimestamp,
    required String clientId,
    required String userId,
  }) async {
    final response = await supabase
        .from('messages')
        .select()
        .eq('user_id', userId)
        .neq('client_id', clientId)
        .gt('server_timestamp', lastSyncedServerTimestamp ?? 0);
    return response.map((r) => Message.fromMap(r)).toList();
  }

  @override
  Future<bool> sendMessageToServer({required Message message}) async {
    try {
      await supabase.from('messages').insert(message.toMap());
      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 supabase
        .from('messages')
        .stream(primaryKey: ['id'])
        .listen((rows) {
          onMessagesReceived(rows.map((r) => Message.fromMap(r)).toList());
        });
  }
}

Next Steps

  1. Database Schema - Create the messages table
  2. OfflineDatabase - Complete local implementation
  3. ServerDatabase - Connect to your backend