@firebase/database 0.13.4 → 0.13.5-20220816211541
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/index.esm2017.js +91 -113
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm5.js +94 -114
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +94 -114
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/index.standalone.js +93 -113
- package/dist/index.standalone.js.map +1 -1
- package/dist/node-esm/index.node.esm.js +91 -113
- package/dist/node-esm/index.node.esm.js.map +1 -1
- package/dist/node-esm/src/core/Repo.d.ts +6 -5
- package/dist/node-esm/src/core/SyncTree.d.ts +9 -30
- package/dist/node-esm/test/helpers/util.d.ts +10 -4
- package/dist/src/core/Repo.d.ts +6 -5
- package/dist/src/core/SyncTree.d.ts +9 -30
- package/dist/test/helpers/util.d.ts +10 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Unreleased
|
|
2
2
|
|
|
3
|
+
## 0.13.5-20220816211541
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`a5d9e1083`](https://github.com/firebase/firebase-js-sdk/commit/a5d9e10831c2877e9d15c8a33b15557e4251c4de) [#6497](https://github.com/firebase/firebase-js-sdk/pull/6497) - Fix issue with how get results for filtered queries are added to cache.
|
|
8
|
+
Fix issue with events not getting propagated to listeners by get.
|
|
9
|
+
|
|
10
|
+
* [`fcd4b8ac3`](https://github.com/firebase/firebase-js-sdk/commit/fcd4b8ac36636a60d83cd3370969ff9192f9e6ad) [#6508](https://github.com/firebase/firebase-js-sdk/pull/6508) - Fixed faulty transaction bug causing filtered index queries to override default queries.
|
|
11
|
+
|
|
3
12
|
## 0.13.4
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/dist/index.esm2017.js
CHANGED
|
@@ -4,7 +4,7 @@ import { stringify, jsonEval, contains, assert, isNodeSdk, base64, stringToByteA
|
|
|
4
4
|
import { Logger, LogLevel } from '@firebase/logger';
|
|
5
5
|
|
|
6
6
|
const name = "@firebase/database";
|
|
7
|
-
const version = "0.13.
|
|
7
|
+
const version = "0.13.5-20220816211541";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @license
|
|
@@ -9135,7 +9135,7 @@ function viewProcessorApplyServerMerge(viewProcessor, viewCache, path, changedCh
|
|
|
9135
9135
|
});
|
|
9136
9136
|
viewMergeTree.children.inorderTraversal((childKey, childMergeTree) => {
|
|
9137
9137
|
const isUnknownDeepMerge = !viewCache.serverCache.isCompleteForChild(childKey) &&
|
|
9138
|
-
childMergeTree.value ===
|
|
9138
|
+
childMergeTree.value === null;
|
|
9139
9139
|
if (!serverNode.hasChild(childKey) && !isUnknownDeepMerge) {
|
|
9140
9140
|
const serverChild = viewCache.serverCache
|
|
9141
9141
|
.getNode()
|
|
@@ -9774,9 +9774,11 @@ function syncTreeApplyTaggedListenComplete(syncTree, path, tag) {
|
|
|
9774
9774
|
*
|
|
9775
9775
|
* @param eventRegistration - If null, all callbacks are removed.
|
|
9776
9776
|
* @param cancelError - If a cancelError is provided, appropriate cancel events will be returned.
|
|
9777
|
+
* @param skipListenerDedup - When performing a `get()`, we don't add any new listeners, so no
|
|
9778
|
+
* deduping needs to take place. This flag allows toggling of that behavior
|
|
9777
9779
|
* @returns Cancel events, if cancelError was provided.
|
|
9778
9780
|
*/
|
|
9779
|
-
function syncTreeRemoveEventRegistration(syncTree, query, eventRegistration, cancelError) {
|
|
9781
|
+
function syncTreeRemoveEventRegistration(syncTree, query, eventRegistration, cancelError, skipListenerDedup = false) {
|
|
9780
9782
|
// Find the syncPoint first. Then deal with whether or not it has matching listeners
|
|
9781
9783
|
const path = query._path;
|
|
9782
9784
|
const maybeSyncPoint = syncTree.syncPointTree_.get(path);
|
|
@@ -9793,48 +9795,52 @@ function syncTreeRemoveEventRegistration(syncTree, query, eventRegistration, can
|
|
|
9793
9795
|
}
|
|
9794
9796
|
const removed = removedAndEvents.removed;
|
|
9795
9797
|
cancelEvents = removedAndEvents.events;
|
|
9796
|
-
|
|
9797
|
-
|
|
9798
|
-
|
|
9799
|
-
|
|
9800
|
-
|
|
9801
|
-
|
|
9802
|
-
|
|
9803
|
-
|
|
9804
|
-
|
|
9805
|
-
|
|
9806
|
-
|
|
9807
|
-
if (removingDefault && !covered) {
|
|
9808
|
-
const subtree = syncTree.syncPointTree_.subtree(path);
|
|
9809
|
-
// There are potentially child listeners. Determine what if any listens we need to send before executing the
|
|
9810
|
-
// removal
|
|
9811
|
-
if (!subtree.isEmpty()) {
|
|
9812
|
-
// We need to fold over our subtree and collect the listeners to send
|
|
9813
|
-
const newViews = syncTreeCollectDistinctViewsForSubTree_(subtree);
|
|
9814
|
-
// Ok, we've collected all the listens we need. Set them up.
|
|
9815
|
-
for (let i = 0; i < newViews.length; ++i) {
|
|
9816
|
-
const view = newViews[i], newQuery = view.query;
|
|
9817
|
-
const listener = syncTreeCreateListenerForView_(syncTree, view);
|
|
9818
|
-
syncTree.listenProvider_.startListening(syncTreeQueryForListening_(newQuery), syncTreeTagForQuery_(syncTree, newQuery), listener.hashFn, listener.onComplete);
|
|
9819
|
-
}
|
|
9820
|
-
}
|
|
9821
|
-
}
|
|
9822
|
-
// If we removed anything and we're not covered by a higher up listen, we need to stop listening on this query
|
|
9823
|
-
// The above block has us covered in terms of making sure we're set up on listens lower in the tree.
|
|
9824
|
-
// Also, note that if we have a cancelError, it's already been removed at the provider level.
|
|
9825
|
-
if (!covered && removed.length > 0 && !cancelError) {
|
|
9826
|
-
// If we removed a default, then we weren't listening on any of the other queries here. Just cancel the one
|
|
9827
|
-
// default. Otherwise, we need to iterate through and cancel each individual query
|
|
9828
|
-
if (removingDefault) {
|
|
9829
|
-
// We don't tag default listeners
|
|
9830
|
-
const defaultTag = null;
|
|
9831
|
-
syncTree.listenProvider_.stopListening(syncTreeQueryForListening_(query), defaultTag);
|
|
9832
|
-
}
|
|
9833
|
-
else {
|
|
9834
|
-
removed.forEach((queryToRemove) => {
|
|
9835
|
-
const tagToRemove = syncTree.queryToTagMap.get(syncTreeMakeQueryKey_(queryToRemove));
|
|
9836
|
-
syncTree.listenProvider_.stopListening(syncTreeQueryForListening_(queryToRemove), tagToRemove);
|
|
9798
|
+
if (!skipListenerDedup) {
|
|
9799
|
+
/**
|
|
9800
|
+
* We may have just removed one of many listeners and can short-circuit this whole process
|
|
9801
|
+
* We may also not have removed a default listener, in which case all of the descendant listeners should already be
|
|
9802
|
+
* properly set up.
|
|
9803
|
+
*/
|
|
9804
|
+
// Since indexed queries can shadow if they don't have other query constraints, check for loadsAllData(), instead of
|
|
9805
|
+
// queryId === 'default'
|
|
9806
|
+
const removingDefault = -1 !==
|
|
9807
|
+
removed.findIndex(query => {
|
|
9808
|
+
return query._queryParams.loadsAllData();
|
|
9837
9809
|
});
|
|
9810
|
+
const covered = syncTree.syncPointTree_.findOnPath(path, (relativePath, parentSyncPoint) => syncPointHasCompleteView(parentSyncPoint));
|
|
9811
|
+
if (removingDefault && !covered) {
|
|
9812
|
+
const subtree = syncTree.syncPointTree_.subtree(path);
|
|
9813
|
+
// There are potentially child listeners. Determine what if any listens we need to send before executing the
|
|
9814
|
+
// removal
|
|
9815
|
+
if (!subtree.isEmpty()) {
|
|
9816
|
+
// We need to fold over our subtree and collect the listeners to send
|
|
9817
|
+
const newViews = syncTreeCollectDistinctViewsForSubTree_(subtree);
|
|
9818
|
+
// Ok, we've collected all the listens we need. Set them up.
|
|
9819
|
+
for (let i = 0; i < newViews.length; ++i) {
|
|
9820
|
+
const view = newViews[i], newQuery = view.query;
|
|
9821
|
+
const listener = syncTreeCreateListenerForView_(syncTree, view);
|
|
9822
|
+
syncTree.listenProvider_.startListening(syncTreeQueryForListening_(newQuery), syncTreeTagForQuery(syncTree, newQuery), listener.hashFn, listener.onComplete);
|
|
9823
|
+
}
|
|
9824
|
+
}
|
|
9825
|
+
// Otherwise there's nothing below us, so nothing we need to start listening on
|
|
9826
|
+
}
|
|
9827
|
+
// If we removed anything and we're not covered by a higher up listen, we need to stop listening on this query
|
|
9828
|
+
// The above block has us covered in terms of making sure we're set up on listens lower in the tree.
|
|
9829
|
+
// Also, note that if we have a cancelError, it's already been removed at the provider level.
|
|
9830
|
+
if (!covered && removed.length > 0 && !cancelError) {
|
|
9831
|
+
// If we removed a default, then we weren't listening on any of the other queries here. Just cancel the one
|
|
9832
|
+
// default. Otherwise, we need to iterate through and cancel each individual query
|
|
9833
|
+
if (removingDefault) {
|
|
9834
|
+
// We don't tag default listeners
|
|
9835
|
+
const defaultTag = null;
|
|
9836
|
+
syncTree.listenProvider_.stopListening(syncTreeQueryForListening_(query), defaultTag);
|
|
9837
|
+
}
|
|
9838
|
+
else {
|
|
9839
|
+
removed.forEach((queryToRemove) => {
|
|
9840
|
+
const tagToRemove = syncTree.queryToTagMap.get(syncTreeMakeQueryKey_(queryToRemove));
|
|
9841
|
+
syncTree.listenProvider_.stopListening(syncTreeQueryForListening_(queryToRemove), tagToRemove);
|
|
9842
|
+
});
|
|
9843
|
+
}
|
|
9838
9844
|
}
|
|
9839
9845
|
}
|
|
9840
9846
|
// Now, clear all of the tags we're tracking for the removed listens
|
|
@@ -9842,30 +9848,6 @@ function syncTreeRemoveEventRegistration(syncTree, query, eventRegistration, can
|
|
|
9842
9848
|
}
|
|
9843
9849
|
return cancelEvents;
|
|
9844
9850
|
}
|
|
9845
|
-
/**
|
|
9846
|
-
* This function was added to support non-listener queries,
|
|
9847
|
-
* specifically for use in repoGetValue. It sets up all the same
|
|
9848
|
-
* local cache data-structures (SyncPoint + View) that are
|
|
9849
|
-
* needed for listeners without installing an event registration.
|
|
9850
|
-
* If `query` is not `loadsAllData`, it will also provision a tag for
|
|
9851
|
-
* the query so that query results can be merged into the sync
|
|
9852
|
-
* tree using existing logic for tagged listener queries.
|
|
9853
|
-
*
|
|
9854
|
-
* @param syncTree - Synctree to add the query to.
|
|
9855
|
-
* @param query - Query to register
|
|
9856
|
-
* @returns tag as a string if query is not a default query, null if query is not.
|
|
9857
|
-
*/
|
|
9858
|
-
function syncTreeRegisterQuery(syncTree, query) {
|
|
9859
|
-
const { syncPoint, serverCache, writesCache, serverCacheComplete } = syncTreeRegisterSyncPoint(query, syncTree);
|
|
9860
|
-
const view = syncPointGetView(syncPoint, query, writesCache, serverCache, serverCacheComplete);
|
|
9861
|
-
if (!syncPoint.views.has(query._queryIdentifier)) {
|
|
9862
|
-
syncPoint.views.set(query._queryIdentifier, view);
|
|
9863
|
-
}
|
|
9864
|
-
if (!query._queryParams.loadsAllData()) {
|
|
9865
|
-
return syncTreeTagForQuery_(syncTree, query);
|
|
9866
|
-
}
|
|
9867
|
-
return null;
|
|
9868
|
-
}
|
|
9869
9851
|
/**
|
|
9870
9852
|
* Apply new server data for the specified tagged query.
|
|
9871
9853
|
*
|
|
@@ -9906,11 +9888,11 @@ function syncTreeApplyTaggedQueryMerge(syncTree, path, changedChildren, tag) {
|
|
|
9906
9888
|
}
|
|
9907
9889
|
}
|
|
9908
9890
|
/**
|
|
9909
|
-
*
|
|
9910
|
-
*
|
|
9911
|
-
*
|
|
9891
|
+
* Add an event callback for the specified query.
|
|
9892
|
+
*
|
|
9893
|
+
* @returns Events to raise.
|
|
9912
9894
|
*/
|
|
9913
|
-
function
|
|
9895
|
+
function syncTreeAddEventRegistration(syncTree, query, eventRegistration, skipSetupListener = false) {
|
|
9914
9896
|
const path = query._path;
|
|
9915
9897
|
let serverCache = null;
|
|
9916
9898
|
let foundAncestorDefaultView = false;
|
|
@@ -9959,24 +9941,8 @@ function syncTreeRegisterSyncPoint(query, syncTree) {
|
|
|
9959
9941
|
syncTree.tagToQueryMap.set(tag, queryKey);
|
|
9960
9942
|
}
|
|
9961
9943
|
const writesCache = writeTreeChildWrites(syncTree.pendingWriteTree_, path);
|
|
9962
|
-
return {
|
|
9963
|
-
syncPoint,
|
|
9964
|
-
writesCache,
|
|
9965
|
-
serverCache,
|
|
9966
|
-
serverCacheComplete,
|
|
9967
|
-
foundAncestorDefaultView,
|
|
9968
|
-
viewAlreadyExists
|
|
9969
|
-
};
|
|
9970
|
-
}
|
|
9971
|
-
/**
|
|
9972
|
-
* Add an event callback for the specified query.
|
|
9973
|
-
*
|
|
9974
|
-
* @returns Events to raise.
|
|
9975
|
-
*/
|
|
9976
|
-
function syncTreeAddEventRegistration(syncTree, query, eventRegistration) {
|
|
9977
|
-
const { syncPoint, serverCache, writesCache, serverCacheComplete, viewAlreadyExists, foundAncestorDefaultView } = syncTreeRegisterSyncPoint(query, syncTree);
|
|
9978
9944
|
let events = syncPointAddEventRegistration(syncPoint, query, eventRegistration, writesCache, serverCache, serverCacheComplete);
|
|
9979
|
-
if (!viewAlreadyExists && !foundAncestorDefaultView) {
|
|
9945
|
+
if (!viewAlreadyExists && !foundAncestorDefaultView && !skipSetupListener) {
|
|
9980
9946
|
const view = syncPointViewForQuery(syncPoint, query);
|
|
9981
9947
|
events = events.concat(syncTreeSetupListener_(syncTree, query, view));
|
|
9982
9948
|
}
|
|
@@ -10106,7 +10072,7 @@ function syncTreeApplyOperationDescendantsHelper_(operation, syncPointTree, serv
|
|
|
10106
10072
|
}
|
|
10107
10073
|
function syncTreeCreateListenerForView_(syncTree, view) {
|
|
10108
10074
|
const query = view.query;
|
|
10109
|
-
const tag =
|
|
10075
|
+
const tag = syncTreeTagForQuery(syncTree, query);
|
|
10110
10076
|
return {
|
|
10111
10077
|
hashFn: () => {
|
|
10112
10078
|
const cache = viewGetServerCache(view) || ChildrenNode.EMPTY_NODE;
|
|
@@ -10134,7 +10100,7 @@ function syncTreeCreateListenerForView_(syncTree, view) {
|
|
|
10134
10100
|
/**
|
|
10135
10101
|
* Return the tag associated with the given query.
|
|
10136
10102
|
*/
|
|
10137
|
-
function
|
|
10103
|
+
function syncTreeTagForQuery(syncTree, query) {
|
|
10138
10104
|
const queryKey = syncTreeMakeQueryKey_(query);
|
|
10139
10105
|
return syncTree.queryToTagMap.get(queryKey);
|
|
10140
10106
|
}
|
|
@@ -10234,7 +10200,7 @@ function syncTreeGetNextQueryTag_() {
|
|
|
10234
10200
|
*/
|
|
10235
10201
|
function syncTreeSetupListener_(syncTree, query, view) {
|
|
10236
10202
|
const path = query._path;
|
|
10237
|
-
const tag =
|
|
10203
|
+
const tag = syncTreeTagForQuery(syncTree, query);
|
|
10238
10204
|
const listener = syncTreeCreateListenerForView_(syncTree, view);
|
|
10239
10205
|
const events = syncTree.listenProvider_.startListening(syncTreeQueryForListening_(query), tag, listener.hashFn, listener.onComplete);
|
|
10240
10206
|
const subtree = syncTree.syncPointTree_.subtree(path);
|
|
@@ -10265,7 +10231,7 @@ function syncTreeSetupListener_(syncTree, query, view) {
|
|
|
10265
10231
|
});
|
|
10266
10232
|
for (let i = 0; i < queriesToStop.length; ++i) {
|
|
10267
10233
|
const queryToStop = queriesToStop[i];
|
|
10268
|
-
syncTree.listenProvider_.stopListening(syncTreeQueryForListening_(queryToStop),
|
|
10234
|
+
syncTree.listenProvider_.stopListening(syncTreeQueryForListening_(queryToStop), syncTreeTagForQuery(syncTree, queryToStop));
|
|
10269
10235
|
}
|
|
10270
10236
|
}
|
|
10271
10237
|
return events;
|
|
@@ -11190,14 +11156,14 @@ function repoGetNextWriteId(repo) {
|
|
|
11190
11156
|
* belonging to active listeners. If they are found, such values
|
|
11191
11157
|
* are considered to be the most up-to-date.
|
|
11192
11158
|
*
|
|
11193
|
-
* If the client is not connected, this method will
|
|
11194
|
-
*
|
|
11195
|
-
* the client is not able to retrieve the query result
|
|
11196
|
-
* an error.
|
|
11159
|
+
* If the client is not connected, this method will wait until the
|
|
11160
|
+
* repo has established a connection and then request the value for `query`.
|
|
11161
|
+
* If the client is not able to retrieve the query result for another reason,
|
|
11162
|
+
* it reports an error.
|
|
11197
11163
|
*
|
|
11198
11164
|
* @param query - The query to surface a value for.
|
|
11199
11165
|
*/
|
|
11200
|
-
function repoGetValue(repo, query) {
|
|
11166
|
+
function repoGetValue(repo, query, eventRegistration) {
|
|
11201
11167
|
// Only active queries are cached. There is no persisted cache.
|
|
11202
11168
|
const cached = syncTreeGetServerValue(repo.serverSyncTree_, query);
|
|
11203
11169
|
if (cached != null) {
|
|
@@ -11205,24 +11171,34 @@ function repoGetValue(repo, query) {
|
|
|
11205
11171
|
}
|
|
11206
11172
|
return repo.server_.get(query).then(payload => {
|
|
11207
11173
|
const node = nodeFromJSON(payload).withIndex(query._queryParams.getIndex());
|
|
11208
|
-
|
|
11174
|
+
/**
|
|
11175
|
+
* Below we simulate the actions of an `onlyOnce` `onValue()` event where:
|
|
11176
|
+
* Add an event registration,
|
|
11177
|
+
* Update data at the path,
|
|
11178
|
+
* Raise any events,
|
|
11179
|
+
* Cleanup the SyncTree
|
|
11180
|
+
*/
|
|
11181
|
+
syncTreeAddEventRegistration(repo.serverSyncTree_, query, eventRegistration, true);
|
|
11182
|
+
let events;
|
|
11209
11183
|
if (query._queryParams.loadsAllData()) {
|
|
11210
|
-
syncTreeApplyServerOverwrite(repo.serverSyncTree_, query._path, node);
|
|
11184
|
+
events = syncTreeApplyServerOverwrite(repo.serverSyncTree_, query._path, node);
|
|
11211
11185
|
}
|
|
11212
11186
|
else {
|
|
11213
|
-
|
|
11214
|
-
|
|
11215
|
-
// `repoGetValue` results have the same cache effects as initial listener(s)
|
|
11216
|
-
// updates.
|
|
11217
|
-
const tag = syncTreeRegisterQuery(repo.serverSyncTree_, query);
|
|
11218
|
-
syncTreeApplyTaggedQueryOverwrite(repo.serverSyncTree_, query._path, node, tag);
|
|
11219
|
-
// Call `syncTreeRemoveEventRegistration` with a null event registration, since there is none.
|
|
11220
|
-
// Note: The below code essentially unregisters the query and cleans up any views/syncpoints temporarily created above.
|
|
11221
|
-
}
|
|
11222
|
-
const cancels = syncTreeRemoveEventRegistration(repo.serverSyncTree_, query, null);
|
|
11223
|
-
if (cancels.length > 0) {
|
|
11224
|
-
repoLog(repo, 'unexpected cancel events in repoGetValue');
|
|
11187
|
+
const tag = syncTreeTagForQuery(repo.serverSyncTree_, query);
|
|
11188
|
+
events = syncTreeApplyTaggedQueryOverwrite(repo.serverSyncTree_, query._path, node, tag);
|
|
11225
11189
|
}
|
|
11190
|
+
/*
|
|
11191
|
+
* We need to raise events in the scenario where `get()` is called at a parent path, and
|
|
11192
|
+
* while the `get()` is pending, `onValue` is called at a child location. While get() is waiting
|
|
11193
|
+
* for the data, `onValue` will register a new event. Then, get() will come back, and update the syncTree
|
|
11194
|
+
* and its corresponding serverCache, including the child location where `onValue` is called. Then,
|
|
11195
|
+
* `onValue` will receive the event from the server, but look at the syncTree and see that the data received
|
|
11196
|
+
* from the server is already at the SyncPoint, and so the `onValue` callback will never get fired.
|
|
11197
|
+
* Calling `eventQueueRaiseEventsForChangedPath()` is the correct way to propagate the events and
|
|
11198
|
+
* ensure the corresponding child events will get fired.
|
|
11199
|
+
*/
|
|
11200
|
+
eventQueueRaiseEventsForChangedPath(repo.eventQueue_, query._path, events);
|
|
11201
|
+
syncTreeRemoveEventRegistration(repo.serverSyncTree_, query, eventRegistration, null, true);
|
|
11226
11202
|
return node;
|
|
11227
11203
|
}, err => {
|
|
11228
11204
|
repoLog(repo, 'get for query ' + stringify(query) + ' failed: ' + err);
|
|
@@ -12905,7 +12881,9 @@ function update(ref, values) {
|
|
|
12905
12881
|
*/
|
|
12906
12882
|
function get(query) {
|
|
12907
12883
|
query = getModularInstance(query);
|
|
12908
|
-
|
|
12884
|
+
const callbackContext = new CallbackContext(() => { });
|
|
12885
|
+
const container = new ValueEventRegistration(callbackContext);
|
|
12886
|
+
return repoGetValue(query._repo, query, container).then(node => {
|
|
12909
12887
|
return new DataSnapshot(node, new ReferenceImpl(query._repo, query._path), query._queryParams.getIndex());
|
|
12910
12888
|
});
|
|
12911
12889
|
}
|