It would be a good idea to update documenation with handling this scenario. Here is AI generated info:
Drift Watch Streams with PowerSync Optional Sync Mode
The Problem
When using Drift with PowerSync's optional sync mode (local-only tables with viewName override), Drift's watch() streams don't receive table update notifications. This causes watched queries to never re-execute when data changes.
Why This Happens
PowerSync's optional sync mode uses a pattern where local-only tables have different internal names than their user-facing view names:
// In PowerSync schema
Table.localOnly(
'local_items', // Internal table name
[...columns],
viewName: 'items', // User-facing view name (different!)
)
This creates a table name mismatch in the update notification flow:
- SQLite stores data in physical table:
ps_data_local__local_items
- PowerSync converts to friendly name:
"local_items"
- SqliteAsyncDriftConnection receives notification:
{"local_items"}
- Drift is listening for updates to:
"items" (the viewName)
"local_items" ≠ "items" → NO MATCH → Watch stream never updates!
Why Synced Mode Works
In synced mode, the table name and view name are the same:
Table(
'items', // Internal table name
[...columns],
viewName: 'items', // Same as table name
)
So notifications arrive as "items" and Drift is listening for "items" → MATCH!
The Solution
Use the transformTableUpdates parameter in SqliteAsyncDriftConnection to convert the internal table names to their corresponding view names:
import 'package:drift/drift.dart' show TableUpdate;
import 'package:drift_sqlite_async/drift_sqlite_async.dart';
final connection = SqliteAsyncDriftConnection(
powerSyncDatabase,
transformTableUpdates: (notification) {
// Convert local_* table names to their viewName equivalents
// e.g., local_items → items, local_labels → labels
return notification.tables.map((tableName) {
if (tableName.startsWith('local_')) {
// Remove 'local_' prefix to match the viewName
return TableUpdate(tableName.substring(6));
}
return TableUpdate(tableName);
}).toSet();
},
);
final database = AppDatabase(connection);
How It Works
- Notification arrives:
{"local_items"}
transformTableUpdates converts: "local_items" → "items"
- Drift receives:
{"items"}
- Drift is listening for:
{"items"}
- MATCH! → Watch stream re-executes query
Complete Example with PowerSync Optional Sync
// schema.dart - PowerSync schema with optional sync
Schema makeSchema({required bool synced}) {
String localViewName(String table) {
return synced ? 'inactive_local_$table' : table;
}
return Schema([
// Local-only tables with viewName override
Table.localOnly(
'local_items',
[...columns],
viewName: localViewName('items'), // "items" when synced=false
),
Table.localOnly(
'local_labels',
[...columns],
viewName: localViewName('labels'),
),
// ... more tables
]);
}
// database_providers.dart - Drift connection with fix
final driftDatabaseProvider = Provider<AppDatabase>((ref) {
final powerSync = ref.watch(powerSyncInstanceProvider);
return AppDatabase(
SqliteAsyncDriftConnection(
powerSync,
transformTableUpdates: (notification) {
return notification.tables.map((tableName) {
if (tableName.startsWith('local_')) {
return TableUpdate(tableName.substring(6));
}
return TableUpdate(tableName);
}).toSet();
},
),
);
});
Key Takeaways
| Scenario |
Table Name |
View Name |
Notification |
Drift Expects |
Result |
| Synced mode |
items |
items |
items |
items |
✅ Works |
| Local-only (no fix) |
local_items |
items |
local_items |
items |
❌ Fails |
| Local-only (with fix) |
local_items |
items |
items (transformed) |
items |
✅ Works |
The transformTableUpdates parameter exists specifically for this use case: mapping internal table names to user-facing names when they differ.
It would be a good idea to update documenation with handling this scenario. Here is AI generated info:
Drift Watch Streams with PowerSync Optional Sync Mode
The Problem
When using Drift with PowerSync's optional sync mode (local-only tables with
viewNameoverride), Drift'swatch()streams don't receive table update notifications. This causes watched queries to never re-execute when data changes.Why This Happens
PowerSync's optional sync mode uses a pattern where local-only tables have different internal names than their user-facing view names:
This creates a table name mismatch in the update notification flow:
ps_data_local__local_items"local_items"{"local_items"}"items"(the viewName)"local_items" ≠ "items"→ NO MATCH → Watch stream never updates!Why Synced Mode Works
In synced mode, the table name and view name are the same:
So notifications arrive as
"items"and Drift is listening for"items"→ MATCH!The Solution
Use the
transformTableUpdatesparameter inSqliteAsyncDriftConnectionto convert the internal table names to their corresponding view names:How It Works
{"local_items"}transformTableUpdatesconverts:"local_items"→"items"{"items"}{"items"}Complete Example with PowerSync Optional Sync
Key Takeaways
itemsitemsitemsitemslocal_itemsitemslocal_itemsitemslocal_itemsitemsitems(transformed)itemsThe
transformTableUpdatesparameter exists specifically for this use case: mapping internal table names to user-facing names when they differ.