Commit 01452bf
Fix: deleted items not disappearing from live queries with
* fix: emit delete events when subscribing with includeInitialState: false
When subscribing to a collection with includeInitialState: false,
delete events were being filtered out because the sentKeys set was
empty. This affected live queries with limit/offset where users
would subscribe to get future changes after already loading
initial data via preload() or values().
Changes:
- Add skipFiltering flag separate from loadedInitialState to allow
filtering to be skipped while still allowing requestSnapshot to work
- Call markAllStateAsSeen() when includeInitialState is explicitly false
- Change internal subscriptions to not pass includeInitialState: false
explicitly, so they can be distinguished from user subscriptions
- Add tests for optimistic delete behavior with limit
Fixes the issue where deleted items would not disappear from live
queries when using .limit() and subscribing with includeInitialState: false.
* debug: add extensive logging to track delete event flow
This is a DEBUG BUILD with [TanStack-DB-DEBUG] logs to help track down
why delete events may not be reaching subscribers when using limit/offset.
The debug logs cover:
- subscribeChanges: when subscriptions are created
- emitEvents: when events are emitted to subscriptions
- Subscription.emitEvents: when individual subscriptions receive events
- filterAndFlipChanges: when events are filtered or passed through
- recomputeOptimisticState: when optimistic state is recomputed and events emitted
- sendChangesToPipeline: when changes flow through the D2 pipeline
- applyChanges: when D2 pipeline outputs to the live query collection
To use: Filter browser console for "[TanStack-DB-DEBUG]"
Also includes the fix for includeInitialState: false not emitting deletes.
* ci: apply automated fixes
* debug: add more logging to track delete event flow in live queries
Add comprehensive debug logging to:
- createFilteredCallback in change-events.ts for whereExpression filtering
- sendChangesToInput for D2 pipeline input
- subscribeToOrderedChanges for orderBy/limit path
- splitUpdates for update event handling
- recomputeOptimisticState for pending sync key filtering
This additional logging helps track where delete events may be filtered
out when using live queries with limit/offset and where clauses.
* ci: apply automated fixes
* debug: add logging to graph scheduling and execution
Add debug logging to track:
- scheduleGraphRun: when graph run is scheduled
- executeGraphRun: when graph run executes or returns early
- maybeRunGraph: when graph actually runs, pending work status
This helps diagnose issues where deletes are sent to D2 pipeline
but never appear in the output (applyChanges not called).
* ci: apply automated fixes
* debug: add detailed logging to D2 reduce and topK operators
Add debug logging to track:
- ReduceOperator: input processing, key handling, and result output
- topK: consolidation, sorting, slicing, and result details
Also add two new test cases:
1. Test delete from different page (page 1 delete while viewing page 2)
- Verifies items shift correctly when delete occurs on earlier page
2. Test delete beyond TopK window (no-op case)
- Verifies deleting item outside window doesn't affect results
These tests and debug logs will help diagnose issues where deleted
items don't disappear from live queries when using limit/offset.
* ci: apply automated fixes
* debug: add more detailed logging to D2 graph and subscription
Add additional debug logging to help diagnose delete issues:
D2 graph (d2.ts):
- Log when run() starts and completes with step count
- Log pendingWork() results with operator IDs
- Log when operators have pending work in step()
Output operator (output.ts):
- Log when run is called with message count
- Log items in each message being processed
Subscription (subscription.ts):
- Log trackSentKeys with keys being added
- Show total sentKeys count
This should help diagnose scenarios where delete events are sent
to D2 but no applyChanges output is produced.
* ci: apply automated fixes
* debug: add operator type logging to trace D2 pipeline
Add operatorType property to Operator base class and log it when
operators run. This will help identify which operators are processing
the delete and where the data is being lost.
Also add detailed logging to LinearUnaryOperator.run() to show:
- Input message count
- Input/output item counts
- Sample of input and output items
This should reveal exactly which operator is dropping the delete.
* debug: add logging to TopKWithFractionalIndexOperator
This is the key operator for orderBy+limit queries. Add detailed logging to:
- run(): Show message count and index size
- processElement(): Show key, multiplicity changes, and action (INSERT/DELETE/NO_CHANGE)
- processElement result: Show moveIn/moveOut keys
This should reveal exactly why deletes aren't producing output changes
when the item exists in the TopK index.
* ci: apply automated fixes
* fix: filter duplicate inserts in subscription to prevent D2 multiplicity issues
When an item is inserted multiple times without a delete in between,
D2 multiplicity goes above 1. Then when a single delete arrives,
multiplicity goes from 2 to 1 (not 0), so TopK doesn't emit a DELETE event.
This fix:
1. Filters out duplicate inserts in filterAndFlipChanges when key already in sentKeys
2. Removes keys from sentKeys on delete in both filterAndFlipChanges and trackSentKeys
3. Updates test expectation to reflect correct behavior (2 events instead of 3)
Root cause: Multiple subscriptions or sync mechanisms could send duplicate
insert events for the same key, causing D2 to track multiplicity > 1.
* fix: add D2 input level deduplication to prevent multiplicity > 1
The previous fix in CollectionSubscription.filterAndFlipChanges was only
catching duplicates at the subscription level. But each live query has its
own CollectionSubscriber with its own D2 pipeline.
This fix adds a sentToD2Keys set in CollectionSubscriber to track which
keys have been sent to the D2 input, preventing duplicate inserts at the
D2 level regardless of which code path triggers them.
Also clears the tracking on truncate events.
* docs: add detailed changeset for delete fix
* ci: apply automated fixes
* chore: remove debug logging from D2 pipeline and subscription code
Remove all TanStack-DB-DEBUG console statements that were added during
investigation of the deleted items not disappearing from live queries bug.
The fix for duplicate D2 inserts is preserved - just removing the verbose
debug output now that the issue is resolved.
* debug: add logging to trace source of duplicate D2 inserts
Add targeted debug logging to understand where duplicate inserts originate:
1. recomputeOptimisticState: Track what events are generated and when
2. CollectionSubscription.filterAndFlipChanges: Trace filtering decisions
3. CollectionSubscriber.sendChangesToPipeline: Track D2-level deduplication
This will help determine if duplicates come from:
- Multiple calls to recomputeOptimisticState for the same key
- Overlap between initial snapshot and change events
- Multiple code paths feeding the D2 pipeline
* ci: apply automated fixes
* fix: prevent race condition in snapshot loading by adding keys to sentKeys before callback
The race condition occurred because snapshot methods (requestSnapshot, requestLimitedSnapshot)
added keys to sentKeys AFTER calling the callback, while filterAndFlipChanges added keys
BEFORE. If a change event arrived during callback execution, it would not see the keys
in sentKeys yet, allowing duplicate inserts.
Changes:
- Add keys to sentKeys BEFORE calling callback in requestSnapshot and requestLimitedSnapshot
- Remove redundant D2-level deduplication (sentToD2Keys) - subscription-level filtering is sufficient
- Remove debug logging added during investigation
* docs: update changeset to reflect race condition fix
* cleanup
* simplify changeset
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Sam Willis <sam.willis@gmail.com>.limit() (#1044)1 parent 5eb8300 commit 01452bf
5 files changed
Lines changed: 672 additions & 9 deletions
File tree
- .changeset
- packages/db
- src/collection
- tests
- query
Lines changed: 11 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
109 | 109 | | |
110 | 110 | | |
111 | 111 | | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
112 | 116 | | |
113 | 117 | | |
114 | 118 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
55 | 60 | | |
56 | 61 | | |
57 | 62 | | |
| |||
244 | 249 | | |
245 | 250 | | |
246 | 251 | | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
247 | 259 | | |
248 | 260 | | |
249 | 261 | | |
| |||
367 | 379 | | |
368 | 380 | | |
369 | 381 | | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
370 | 389 | | |
371 | 390 | | |
372 | 391 | | |
| |||
441 | 460 | | |
442 | 461 | | |
443 | 462 | | |
| 463 | + | |
444 | 464 | | |
445 | 465 | | |
446 | | - | |
447 | | - | |
| 466 | + | |
| 467 | + | |
448 | 468 | | |
449 | 469 | | |
450 | 470 | | |
451 | 471 | | |
452 | 472 | | |
453 | 473 | | |
454 | 474 | | |
455 | | - | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
456 | 478 | | |
457 | 479 | | |
458 | 480 | | |
459 | 481 | | |
460 | 482 | | |
461 | 483 | | |
462 | 484 | | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
463 | 498 | | |
464 | 499 | | |
465 | 500 | | |
466 | 501 | | |
467 | 502 | | |
468 | 503 | | |
469 | 504 | | |
470 | | - | |
471 | | - | |
472 | | - | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
473 | 508 | | |
474 | 509 | | |
475 | 510 | | |
476 | 511 | | |
477 | | - | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
478 | 519 | | |
479 | 520 | | |
480 | 521 | | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
481 | 531 | | |
482 | 532 | | |
483 | 533 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1193 | 1193 | | |
1194 | 1194 | | |
1195 | 1195 | | |
1196 | | - | |
1197 | | - | |
| 1196 | + | |
| 1197 | + | |
| 1198 | + | |
| 1199 | + | |
1198 | 1200 | | |
1199 | 1201 | | |
1200 | 1202 | | |
| |||
0 commit comments