Skip to content

Commit 629919e

Browse files
authored
Fix metadata sync issue for cache listeners in multi-tab (#8343)
1 parent 16d62d4 commit 629919e

File tree

4 files changed

+37
-16
lines changed

4 files changed

+37
-16
lines changed

.changeset/warm-oranges-itch.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@firebase/firestore': patch
3+
---
4+
5+
Fix an issue with metadata `fromCache` defaulting to `true` when listening to cache in multi-tabs.

packages/firestore/src/core/sync_engine_impl.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -353,9 +353,11 @@ async function allocateTargetAndMaybeListen(
353353
// not registering it in shared client state, and directly calculate initial snapshots and
354354
// subsequent updates from cache. Otherwise, register the target ID with local Firestore client
355355
// as active watch target.
356-
const status: QueryTargetState = shouldListenToRemote
357-
? syncEngineImpl.sharedClientState.addLocalQueryTarget(targetId)
358-
: 'not-current';
356+
const status: QueryTargetState =
357+
syncEngineImpl.sharedClientState.addLocalQueryTarget(
358+
targetId,
359+
/* addToActiveTargetIds= */ shouldListenToRemote
360+
);
359361

360362
let viewSnapshot;
361363
if (shouldInitializeView) {

packages/firestore/src/local/shared_client_state.ts

+21-6
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ export interface SharedClientState {
104104
* If the target id is already associated with local client, the method simply
105105
* returns its `QueryTargetState`.
106106
*/
107-
addLocalQueryTarget(targetId: TargetId): QueryTargetState;
107+
addLocalQueryTarget(
108+
targetId: TargetId,
109+
addToActiveTargetIds?: boolean
110+
): QueryTargetState;
108111

109112
/** Removes the Query Target ID association from the local client. */
110113
removeLocalQueryTarget(targetId: TargetId): void;
@@ -655,7 +658,10 @@ export class WebStorageSharedClientState implements SharedClientState {
655658
this.removeMutationState(batchId);
656659
}
657660

658-
addLocalQueryTarget(targetId: TargetId): QueryTargetState {
661+
addLocalQueryTarget(
662+
targetId: TargetId,
663+
addToActiveTargetIds: boolean = true
664+
): QueryTargetState {
659665
let queryState: QueryTargetState = 'not-current';
660666

661667
// Lookup an existing query state if the target ID was already registered
@@ -676,9 +682,13 @@ export class WebStorageSharedClientState implements SharedClientState {
676682
}
677683
}
678684

679-
this.localClientState.addQueryTarget(targetId);
680-
this.persistClientState();
685+
// If the query is listening to cache only, the target ID should not be registered with the
686+
// local Firestore client as an active watch target.
687+
if (addToActiveTargetIds) {
688+
this.localClientState.addQueryTarget(targetId);
689+
}
681690

691+
this.persistClientState();
682692
return queryState;
683693
}
684694

@@ -1110,8 +1120,13 @@ export class MemorySharedClientState implements SharedClientState {
11101120
// No op.
11111121
}
11121122

1113-
addLocalQueryTarget(targetId: TargetId): QueryTargetState {
1114-
this.localState.addQueryTarget(targetId);
1123+
addLocalQueryTarget(
1124+
targetId: TargetId,
1125+
addToActiveTargetIds: boolean = true
1126+
): QueryTargetState {
1127+
if (addToActiveTargetIds) {
1128+
this.localState.addQueryTarget(targetId);
1129+
}
11151130
return this.queryState[targetId] || 'not-current';
11161131
}
11171132

packages/firestore/test/unit/specs/listen_source_spec.test.ts

+6-7
Original file line numberDiff line numberDiff line change
@@ -491,10 +491,10 @@ describeSpec('Listens source options:', [], () => {
491491
// Listen to cache in secondary clients
492492
.client(1)
493493
.userListensToCache(query1)
494-
.expectEvents(query1, { added: [docA], fromCache: true })
494+
.expectEvents(query1, { added: [docA] })
495495
.client(2)
496496
.userListensToCache(query1)
497-
.expectEvents(query1, { added: [docA], fromCache: true })
497+
.expectEvents(query1, { added: [docA] })
498498
// Updates in the primary client notifies listeners sourcing from cache
499499
// in secondary clients.
500500
.client(0)
@@ -748,7 +748,7 @@ describeSpec('Listens source options:', [], () => {
748748
//Listen to cache in secondary client
749749
.client(1)
750750
.userListensToCache(limitToLast)
751-
.expectEvents(limitToLast, { added: [docB, docA], fromCache: true })
751+
.expectEvents(limitToLast, { added: [docB, docA] })
752752
// Watch sends document changes
753753
.client(0)
754754
.watchSends({ affects: [limit] }, docC)
@@ -794,7 +794,7 @@ describeSpec('Listens source options:', [], () => {
794794
// Listen to cache in primary client
795795
.client(0)
796796
.userListensToCache(limitToLast)
797-
.expectEvents(limitToLast, { added: [docB, docA], fromCache: true })
797+
.expectEvents(limitToLast, { added: [docB, docA] })
798798
// Watch sends document changes
799799
.watchSends({ affects: [limit] }, docC)
800800
.watchSnapshots(2000)
@@ -825,16 +825,15 @@ describeSpec('Listens source options:', [], () => {
825825
// Listen to cache in secondary client
826826
.client(1)
827827
.userListensToCache(query1)
828-
.expectEvents(query1, { added: [docA], fromCache: true })
828+
.expectEvents(query1, { added: [docA] })
829829
.client(0)
830830
.userUnlistens(query1)
831831
.userSets('collection/b', { key: 'b' })
832832
// The other listener should work as expected
833833
.client(1)
834834
.expectEvents(query1, {
835835
hasPendingWrites: true,
836-
added: [docB],
837-
fromCache: true
836+
added: [docB]
838837
})
839838
.userUnlistensToCache(query1)
840839
);

0 commit comments

Comments
 (0)