You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Stop pushing where clauses that target renamed subquery projections so alias remapping stays intact, preventing a bug where a where clause would not be executed correctly.
@@ -54,15 +54,21 @@ The `electricCollectionOptions` function accepts the following options:
54
54
55
55
### Persistence Handlers
56
56
57
+
Handlers are called before mutations to persist changes to your backend:
58
+
57
59
-`onInsert`: Handler called before insert operations
58
-
-`onUpdate`: Handler called before update operations
60
+
-`onUpdate`: Handler called before update operations
59
61
-`onDelete`: Handler called before delete operations
60
62
61
-
## Persistence Handlers
63
+
Each handler should return `{ txid }` to wait for synchronization. For cases where your API can not return txids, use the `awaitMatch` utility function.
64
+
65
+
## Persistence Handlers & Synchronization
66
+
67
+
Handlers persist mutations to the backend and wait for Electric to sync the changes back. This prevents UI glitches where optimistic updates would be removed and then re-added. TanStack DB blocks sync data until the mutation is confirmed, ensuring smooth user experience.
62
68
63
-
Handlers can be defined to run on mutations. They are useful to send mutations to the backend and confirming them once Electric delivers the corresponding transactions. Until confirmation, TanStack DB blocks sync data for the collection to prevent race conditions. To avoid any delays, it’s important to use a matching strategy.
69
+
### 1. Using Txid (Recommended)
64
70
65
-
The most reliable strategy is for the backend to include the transaction ID (txid) in its response, allowing the client to match each mutation with Electric’s transaction identifiers for precise confirmation. If no strategy is provided, client mutations are automatically confirmed after three seconds.
71
+
The recommended approach uses PostgreSQL transaction IDs (txids) for precise matching. The backend returns a txid, and the client waits for that specific txid to appear in the Electric stream.
For quick prototyping or when you're confident about timing, you can use a simple timeout. This is crude but works as almost always the data will be synced back in under 2 seconds:
For more advanced use cases, you can create custom actions that can do multiple mutations across collections transactionally. In this case, you need to explicitly await for the transaction ID using `utils.awaitTxId()`.
239
+
For more advanced use cases, you can create custom actions that can do multiple mutations across collections transactionally. You can use the utility methods to wait for synchronization with different strategies:
A frequent issue developers encounter is that `awaitTxId` (or the transaction's `isPersisted.promise`) stalls indefinitely, eventually timing out with no error messages. The data persists correctly to the database, but the optimistic mutation never resolves.
362
+
363
+
**Root Cause:** This happens when the transaction ID (txid) returned from your API doesn't match the actual transaction ID of the mutation in Postgres. This mismatch occurs when you query `pg_current_xact_id()`**outside** the same transaction that performs the mutation.
364
+
365
+
### Enable Debug Logging
366
+
367
+
To diagnose txid issues, enable debug logging in your browser console:
368
+
369
+
```javascript
370
+
localStorage.debug='ts/db:electric'
371
+
```
372
+
373
+
This will show you when mutations start waiting for txids and when txids arrive from Electric's sync stream.
374
+
375
+
This is powered by the [debug](https://www.npmjs.com/package/debug) package.
376
+
377
+
**When txids DON'T match (common bug):**
378
+
```
379
+
ts/db:electric awaitTxId called with txid 124
380
+
ts/db:electric new txids synced from pg [123]
381
+
// Stalls forever - 124 never arrives!
382
+
```
383
+
384
+
In this example, the mutation happened in transaction 123, but you queried `pg_current_xact_id()` in a separate transaction (124) that ran after the mutation. The client waits for 124 which will never arrive.
385
+
386
+
**When txids DO match (correct):**
387
+
```
388
+
ts/db:electric awaitTxId called with txid 123
389
+
ts/db:electric new txids synced from pg [123]
390
+
ts/db:electric awaitTxId found match for txid 123
391
+
// Resolves immediately!
392
+
```
393
+
394
+
### The Solution: Query txid Inside the Transaction
395
+
396
+
You **must** call `pg_current_xact_id()` inside the same transaction as your mutation:
397
+
398
+
**❌ Wrong - txid queried outside transaction:**
399
+
```typescript
400
+
// DON'T DO THIS
401
+
asyncfunction createTodo(data) {
402
+
const txid =awaitgenerateTxId(sql) // Wrong: separate transaction
0 commit comments