@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.
@@ -9390,7 +9390,7 @@ function viewProcessorApplyServerMerge(viewProcessor, viewCache, path, changedCh
9390
9390
  });
9391
9391
  viewMergeTree.children.inorderTraversal(function (childKey, childMergeTree) {
9392
9392
  var isUnknownDeepMerge = !viewCache.serverCache.isCompleteForChild(childKey) &&
9393
- childMergeTree.value === undefined;
9393
+ childMergeTree.value === null;
9394
9394
  if (!serverNode.hasChild(childKey) && !isUnknownDeepMerge) {
9395
9395
  var serverChild = viewCache.serverCache
9396
9396
  .getNode()
@@ -10092,9 +10092,12 @@ function syncTreeApplyTaggedListenComplete(syncTree, path, tag) {
10092
10092
  *
10093
10093
  * @param eventRegistration - If null, all callbacks are removed.
10094
10094
  * @param cancelError - If a cancelError is provided, appropriate cancel events will be returned.
10095
+ * @param skipListenerDedup - When performing a `get()`, we don't add any new listeners, so no
10096
+ * deduping needs to take place. This flag allows toggling of that behavior
10095
10097
  * @returns Cancel events, if cancelError was provided.
10096
10098
  */
10097
- function syncTreeRemoveEventRegistration(syncTree, query, eventRegistration, cancelError) {
10099
+ function syncTreeRemoveEventRegistration(syncTree, query, eventRegistration, cancelError, skipListenerDedup) {
10100
+ if (skipListenerDedup === void 0) { skipListenerDedup = false; }
10098
10101
  // Find the syncPoint first. Then deal with whether or not it has matching listeners
10099
10102
  var path = query._path;
10100
10103
  var maybeSyncPoint = syncTree.syncPointTree_.get(path);
@@ -10111,50 +10114,54 @@ function syncTreeRemoveEventRegistration(syncTree, query, eventRegistration, can
10111
10114
  }
10112
10115
  var removed = removedAndEvents.removed;
10113
10116
  cancelEvents = removedAndEvents.events;
10114
- // We may have just removed one of many listeners and can short-circuit this whole process
10115
- // We may also not have removed a default listener, in which case all of the descendant listeners should already be
10116
- // properly set up.
10117
- //
10118
- // Since indexed queries can shadow if they don't have other query constraints, check for loadsAllData(), instead of
10119
- // queryId === 'default'
10120
- var removingDefault = -1 !==
10121
- removed.findIndex(function (query) {
10122
- return query._queryParams.loadsAllData();
10117
+ if (!skipListenerDedup) {
10118
+ /**
10119
+ * We may have just removed one of many listeners and can short-circuit this whole process
10120
+ * We may also not have removed a default listener, in which case all of the descendant listeners should already be
10121
+ * properly set up.
10122
+ */
10123
+ // Since indexed queries can shadow if they don't have other query constraints, check for loadsAllData(), instead of
10124
+ // queryId === 'default'
10125
+ var removingDefault = -1 !==
10126
+ removed.findIndex(function (query) {
10127
+ return query._queryParams.loadsAllData();
10128
+ });
10129
+ var covered = syncTree.syncPointTree_.findOnPath(path, function (relativePath, parentSyncPoint) {
10130
+ return syncPointHasCompleteView(parentSyncPoint);
10123
10131
  });
10124
- var covered = syncTree.syncPointTree_.findOnPath(path, function (relativePath, parentSyncPoint) {
10125
- return syncPointHasCompleteView(parentSyncPoint);
10126
- });
10127
- if (removingDefault && !covered) {
10128
- var subtree = syncTree.syncPointTree_.subtree(path);
10129
- // There are potentially child listeners. Determine what if any listens we need to send before executing the
10130
- // removal
10131
- if (!subtree.isEmpty()) {
10132
- // We need to fold over our subtree and collect the listeners to send
10133
- var newViews = syncTreeCollectDistinctViewsForSubTree_(subtree);
10134
- // Ok, we've collected all the listens we need. Set them up.
10135
- for (var i = 0; i < newViews.length; ++i) {
10136
- var view = newViews[i], newQuery = view.query;
10137
- var listener = syncTreeCreateListenerForView_(syncTree, view);
10138
- syncTree.listenProvider_.startListening(syncTreeQueryForListening_(newQuery), syncTreeTagForQuery_(syncTree, newQuery), listener.hashFn, listener.onComplete);
10132
+ if (removingDefault && !covered) {
10133
+ var subtree = syncTree.syncPointTree_.subtree(path);
10134
+ // There are potentially child listeners. Determine what if any listens we need to send before executing the
10135
+ // removal
10136
+ if (!subtree.isEmpty()) {
10137
+ // We need to fold over our subtree and collect the listeners to send
10138
+ var newViews = syncTreeCollectDistinctViewsForSubTree_(subtree);
10139
+ // Ok, we've collected all the listens we need. Set them up.
10140
+ for (var i = 0; i < newViews.length; ++i) {
10141
+ var view = newViews[i], newQuery = view.query;
10142
+ var listener = syncTreeCreateListenerForView_(syncTree, view);
10143
+ syncTree.listenProvider_.startListening(syncTreeQueryForListening_(newQuery), syncTreeTagForQuery(syncTree, newQuery), listener.hashFn, listener.onComplete);
10144
+ }
10145
+ }
10146
+ // Otherwise there's nothing below us, so nothing we need to start listening on
10147
+ }
10148
+ // If we removed anything and we're not covered by a higher up listen, we need to stop listening on this query
10149
+ // The above block has us covered in terms of making sure we're set up on listens lower in the tree.
10150
+ // Also, note that if we have a cancelError, it's already been removed at the provider level.
10151
+ if (!covered && removed.length > 0 && !cancelError) {
10152
+ // If we removed a default, then we weren't listening on any of the other queries here. Just cancel the one
10153
+ // default. Otherwise, we need to iterate through and cancel each individual query
10154
+ if (removingDefault) {
10155
+ // We don't tag default listeners
10156
+ var defaultTag = null;
10157
+ syncTree.listenProvider_.stopListening(syncTreeQueryForListening_(query), defaultTag);
10158
+ }
10159
+ else {
10160
+ removed.forEach(function (queryToRemove) {
10161
+ var tagToRemove = syncTree.queryToTagMap.get(syncTreeMakeQueryKey_(queryToRemove));
10162
+ syncTree.listenProvider_.stopListening(syncTreeQueryForListening_(queryToRemove), tagToRemove);
10163
+ });
10139
10164
  }
10140
- }
10141
- }
10142
- // If we removed anything and we're not covered by a higher up listen, we need to stop listening on this query
10143
- // The above block has us covered in terms of making sure we're set up on listens lower in the tree.
10144
- // Also, note that if we have a cancelError, it's already been removed at the provider level.
10145
- if (!covered && removed.length > 0 && !cancelError) {
10146
- // If we removed a default, then we weren't listening on any of the other queries here. Just cancel the one
10147
- // default. Otherwise, we need to iterate through and cancel each individual query
10148
- if (removingDefault) {
10149
- // We don't tag default listeners
10150
- var defaultTag = null;
10151
- syncTree.listenProvider_.stopListening(syncTreeQueryForListening_(query), defaultTag);
10152
- }
10153
- else {
10154
- removed.forEach(function (queryToRemove) {
10155
- var tagToRemove = syncTree.queryToTagMap.get(syncTreeMakeQueryKey_(queryToRemove));
10156
- syncTree.listenProvider_.stopListening(syncTreeQueryForListening_(queryToRemove), tagToRemove);
10157
- });
10158
10165
  }
10159
10166
  }
10160
10167
  // Now, clear all of the tags we're tracking for the removed listens
@@ -10162,30 +10169,6 @@ function syncTreeRemoveEventRegistration(syncTree, query, eventRegistration, can
10162
10169
  }
10163
10170
  return cancelEvents;
10164
10171
  }
10165
- /**
10166
- * This function was added to support non-listener queries,
10167
- * specifically for use in repoGetValue. It sets up all the same
10168
- * local cache data-structures (SyncPoint + View) that are
10169
- * needed for listeners without installing an event registration.
10170
- * If `query` is not `loadsAllData`, it will also provision a tag for
10171
- * the query so that query results can be merged into the sync
10172
- * tree using existing logic for tagged listener queries.
10173
- *
10174
- * @param syncTree - Synctree to add the query to.
10175
- * @param query - Query to register
10176
- * @returns tag as a string if query is not a default query, null if query is not.
10177
- */
10178
- function syncTreeRegisterQuery(syncTree, query) {
10179
- var _a = syncTreeRegisterSyncPoint(query, syncTree), syncPoint = _a.syncPoint, serverCache = _a.serverCache, writesCache = _a.writesCache, serverCacheComplete = _a.serverCacheComplete;
10180
- var view = syncPointGetView(syncPoint, query, writesCache, serverCache, serverCacheComplete);
10181
- if (!syncPoint.views.has(query._queryIdentifier)) {
10182
- syncPoint.views.set(query._queryIdentifier, view);
10183
- }
10184
- if (!query._queryParams.loadsAllData()) {
10185
- return syncTreeTagForQuery_(syncTree, query);
10186
- }
10187
- return null;
10188
- }
10189
10172
  /**
10190
10173
  * Apply new server data for the specified tagged query.
10191
10174
  *
@@ -10226,11 +10209,12 @@ function syncTreeApplyTaggedQueryMerge(syncTree, path, changedChildren, tag) {
10226
10209
  }
10227
10210
  }
10228
10211
  /**
10229
- * Creates a new syncpoint for a query and creates a tag if the view doesn't exist.
10230
- * Extracted from addEventRegistration to allow `repoGetValue` to properly set up the SyncTree
10231
- * without actually listening on a query.
10212
+ * Add an event callback for the specified query.
10213
+ *
10214
+ * @returns Events to raise.
10232
10215
  */
10233
- function syncTreeRegisterSyncPoint(query, syncTree) {
10216
+ function syncTreeAddEventRegistration(syncTree, query, eventRegistration, skipSetupListener) {
10217
+ if (skipSetupListener === void 0) { skipSetupListener = false; }
10234
10218
  var path = query._path;
10235
10219
  var serverCache = null;
10236
10220
  var foundAncestorDefaultView = false;
@@ -10279,24 +10263,8 @@ function syncTreeRegisterSyncPoint(query, syncTree) {
10279
10263
  syncTree.tagToQueryMap.set(tag, queryKey);
10280
10264
  }
10281
10265
  var writesCache = writeTreeChildWrites(syncTree.pendingWriteTree_, path);
10282
- return {
10283
- syncPoint: syncPoint,
10284
- writesCache: writesCache,
10285
- serverCache: serverCache,
10286
- serverCacheComplete: serverCacheComplete,
10287
- foundAncestorDefaultView: foundAncestorDefaultView,
10288
- viewAlreadyExists: viewAlreadyExists
10289
- };
10290
- }
10291
- /**
10292
- * Add an event callback for the specified query.
10293
- *
10294
- * @returns Events to raise.
10295
- */
10296
- function syncTreeAddEventRegistration(syncTree, query, eventRegistration) {
10297
- var _a = syncTreeRegisterSyncPoint(query, syncTree), syncPoint = _a.syncPoint, serverCache = _a.serverCache, writesCache = _a.writesCache, serverCacheComplete = _a.serverCacheComplete, viewAlreadyExists = _a.viewAlreadyExists, foundAncestorDefaultView = _a.foundAncestorDefaultView;
10298
10266
  var events = syncPointAddEventRegistration(syncPoint, query, eventRegistration, writesCache, serverCache, serverCacheComplete);
10299
- if (!viewAlreadyExists && !foundAncestorDefaultView) {
10267
+ if (!viewAlreadyExists && !foundAncestorDefaultView && !skipSetupListener) {
10300
10268
  var view = syncPointViewForQuery(syncPoint, query);
10301
10269
  events = events.concat(syncTreeSetupListener_(syncTree, query, view));
10302
10270
  }
@@ -10426,7 +10394,7 @@ function syncTreeApplyOperationDescendantsHelper_(operation, syncPointTree, serv
10426
10394
  }
10427
10395
  function syncTreeCreateListenerForView_(syncTree, view) {
10428
10396
  var query = view.query;
10429
- var tag = syncTreeTagForQuery_(syncTree, query);
10397
+ var tag = syncTreeTagForQuery(syncTree, query);
10430
10398
  return {
10431
10399
  hashFn: function () {
10432
10400
  var cache = viewGetServerCache(view) || ChildrenNode.EMPTY_NODE;
@@ -10454,7 +10422,7 @@ function syncTreeCreateListenerForView_(syncTree, view) {
10454
10422
  /**
10455
10423
  * Return the tag associated with the given query.
10456
10424
  */
10457
- function syncTreeTagForQuery_(syncTree, query) {
10425
+ function syncTreeTagForQuery(syncTree, query) {
10458
10426
  var queryKey = syncTreeMakeQueryKey_(query);
10459
10427
  return syncTree.queryToTagMap.get(queryKey);
10460
10428
  }
@@ -10554,7 +10522,7 @@ function syncTreeGetNextQueryTag_() {
10554
10522
  */
10555
10523
  function syncTreeSetupListener_(syncTree, query, view) {
10556
10524
  var path = query._path;
10557
- var tag = syncTreeTagForQuery_(syncTree, query);
10525
+ var tag = syncTreeTagForQuery(syncTree, query);
10558
10526
  var listener = syncTreeCreateListenerForView_(syncTree, view);
10559
10527
  var events = syncTree.listenProvider_.startListening(syncTreeQueryForListening_(query), tag, listener.hashFn, listener.onComplete);
10560
10528
  var subtree = syncTree.syncPointTree_.subtree(path);
@@ -10585,7 +10553,7 @@ function syncTreeSetupListener_(syncTree, query, view) {
10585
10553
  });
10586
10554
  for (var i = 0; i < queriesToStop.length; ++i) {
10587
10555
  var queryToStop = queriesToStop[i];
10588
- syncTree.listenProvider_.stopListening(syncTreeQueryForListening_(queryToStop), syncTreeTagForQuery_(syncTree, queryToStop));
10556
+ syncTree.listenProvider_.stopListening(syncTreeQueryForListening_(queryToStop), syncTreeTagForQuery(syncTree, queryToStop));
10589
10557
  }
10590
10558
  }
10591
10559
  return events;
@@ -11522,14 +11490,14 @@ function repoGetNextWriteId(repo) {
11522
11490
  * belonging to active listeners. If they are found, such values
11523
11491
  * are considered to be the most up-to-date.
11524
11492
  *
11525
- * If the client is not connected, this method will try to
11526
- * establish a connection and request the value for `query`. If
11527
- * the client is not able to retrieve the query result, it reports
11528
- * an error.
11493
+ * If the client is not connected, this method will wait until the
11494
+ * repo has established a connection and then request the value for `query`.
11495
+ * If the client is not able to retrieve the query result for another reason,
11496
+ * it reports an error.
11529
11497
  *
11530
11498
  * @param query - The query to surface a value for.
11531
11499
  */
11532
- function repoGetValue(repo, query) {
11500
+ function repoGetValue(repo, query, eventRegistration) {
11533
11501
  // Only active queries are cached. There is no persisted cache.
11534
11502
  var cached = syncTreeGetServerValue(repo.serverSyncTree_, query);
11535
11503
  if (cached != null) {
@@ -11537,24 +11505,34 @@ function repoGetValue(repo, query) {
11537
11505
  }
11538
11506
  return repo.server_.get(query).then(function (payload) {
11539
11507
  var node = nodeFromJSON(payload).withIndex(query._queryParams.getIndex());
11540
- // if this is a filtered query, then overwrite at path
11508
+ /**
11509
+ * Below we simulate the actions of an `onlyOnce` `onValue()` event where:
11510
+ * Add an event registration,
11511
+ * Update data at the path,
11512
+ * Raise any events,
11513
+ * Cleanup the SyncTree
11514
+ */
11515
+ syncTreeAddEventRegistration(repo.serverSyncTree_, query, eventRegistration, true);
11516
+ var events;
11541
11517
  if (query._queryParams.loadsAllData()) {
11542
- syncTreeApplyServerOverwrite(repo.serverSyncTree_, query._path, node);
11518
+ events = syncTreeApplyServerOverwrite(repo.serverSyncTree_, query._path, node);
11543
11519
  }
11544
11520
  else {
11545
- // Simulate `syncTreeAddEventRegistration` without events/listener setup.
11546
- // We do this (along with the syncTreeRemoveEventRegistration` below) so that
11547
- // `repoGetValue` results have the same cache effects as initial listener(s)
11548
- // updates.
11549
- var tag = syncTreeRegisterQuery(repo.serverSyncTree_, query);
11550
- syncTreeApplyTaggedQueryOverwrite(repo.serverSyncTree_, query._path, node, tag);
11551
- // Call `syncTreeRemoveEventRegistration` with a null event registration, since there is none.
11552
- // Note: The below code essentially unregisters the query and cleans up any views/syncpoints temporarily created above.
11553
- }
11554
- var cancels = syncTreeRemoveEventRegistration(repo.serverSyncTree_, query, null);
11555
- if (cancels.length > 0) {
11556
- repoLog(repo, 'unexpected cancel events in repoGetValue');
11521
+ var tag = syncTreeTagForQuery(repo.serverSyncTree_, query);
11522
+ events = syncTreeApplyTaggedQueryOverwrite(repo.serverSyncTree_, query._path, node, tag);
11557
11523
  }
11524
+ /*
11525
+ * We need to raise events in the scenario where `get()` is called at a parent path, and
11526
+ * while the `get()` is pending, `onValue` is called at a child location. While get() is waiting
11527
+ * for the data, `onValue` will register a new event. Then, get() will come back, and update the syncTree
11528
+ * and its corresponding serverCache, including the child location where `onValue` is called. Then,
11529
+ * `onValue` will receive the event from the server, but look at the syncTree and see that the data received
11530
+ * from the server is already at the SyncPoint, and so the `onValue` callback will never get fired.
11531
+ * Calling `eventQueueRaiseEventsForChangedPath()` is the correct way to propagate the events and
11532
+ * ensure the corresponding child events will get fired.
11533
+ */
11534
+ eventQueueRaiseEventsForChangedPath(repo.eventQueue_, query._path, events);
11535
+ syncTreeRemoveEventRegistration(repo.serverSyncTree_, query, eventRegistration, null, true);
11558
11536
  return node;
11559
11537
  }, function (err) {
11560
11538
  repoLog(repo, 'get for query ' + util.stringify(query) + ' failed: ' + err);
@@ -13314,7 +13292,9 @@ function update(ref, values) {
13314
13292
  */
13315
13293
  function get(query) {
13316
13294
  query = util.getModularInstance(query);
13317
- return repoGetValue(query._repo, query).then(function (node) {
13295
+ var callbackContext = new CallbackContext(function () { });
13296
+ var container = new ValueEventRegistration(callbackContext);
13297
+ return repoGetValue(query._repo, query, container).then(function (node) {
13318
13298
  return new DataSnapshot(node, new ReferenceImpl(query._repo, query._path), query._queryParams.getIndex());
13319
13299
  });
13320
13300
  }