@firebase/firestore 3.4.4-canary.2dd99ae2d → 3.4.4-canary.3e9f3e253
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/dist/firestore/src/api/credentials.d.ts +1 -0
- package/dist/firestore/src/api/snapshot.d.ts +1 -2
- package/dist/firestore/src/core/target.d.ts +8 -4
- package/dist/firestore/src/lite-api/query.d.ts +2 -2
- package/dist/firestore/src/local/document_overlay_cache.d.ts +72 -0
- package/dist/firestore/src/local/index_manager.d.ts +52 -0
- package/dist/firestore/src/local/indexeddb_document_overlay_cache.d.ts +45 -0
- package/dist/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
- package/dist/firestore/src/local/indexeddb_persistence.d.ts +6 -4
- package/dist/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
- package/dist/firestore/src/local/indexeddb_schema.d.ts +193 -7
- package/dist/firestore/src/local/local_documents_view.d.ts +0 -1
- package/dist/firestore/src/local/local_serializer.d.ts +18 -2
- package/dist/firestore/src/local/memory_document_overlay_cache.d.ts +37 -0
- package/dist/firestore/src/local/memory_index_manager.d.ts +11 -0
- package/dist/firestore/src/local/memory_persistence.d.ts +6 -2
- package/dist/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
- package/dist/firestore/src/local/persistence.d.ts +8 -2
- package/dist/firestore/src/local/remote_document_cache.d.ts +7 -9
- package/dist/firestore/src/local/simple_db.d.ts +1 -0
- package/dist/firestore/src/model/document_key.d.ts +4 -0
- package/dist/firestore/src/model/field_index.d.ts +2 -2
- package/dist/firestore/src/model/overlay.d.ts +32 -0
- package/dist/firestore/src/model/target_index_matcher.d.ts +70 -0
- package/dist/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
- package/dist/firestore/test/unit/local/document_overlay_cache.test.d.ts +1 -0
- package/dist/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
- package/dist/firestore/test/unit/local/test_document_overlay_cache.d.ts +38 -0
- package/dist/firestore/test/unit/local/test_index_manager.d.ts +11 -0
- package/dist/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
- package/dist/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
- package/dist/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
- package/dist/firestore/test/util/helpers.d.ts +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.esm2017.js +3864 -3349
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm5.js +3879 -3455
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +878 -221
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/index.node.mjs +878 -221
- package/dist/index.node.mjs.map +1 -1
- package/dist/index.rn.js +3973 -3458
- package/dist/index.rn.js.map +1 -1
- package/dist/internal.d.ts +252 -14
- package/dist/lite/firestore/src/api/credentials.d.ts +1 -0
- package/dist/lite/firestore/src/api/snapshot.d.ts +1 -2
- package/dist/lite/firestore/src/core/target.d.ts +8 -4
- package/dist/lite/firestore/src/lite-api/query.d.ts +2 -2
- package/dist/lite/firestore/src/local/document_overlay_cache.d.ts +72 -0
- package/dist/lite/firestore/src/local/index_manager.d.ts +52 -0
- package/dist/lite/firestore/src/local/indexeddb_document_overlay_cache.d.ts +45 -0
- package/dist/lite/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
- package/dist/lite/firestore/src/local/indexeddb_persistence.d.ts +6 -4
- package/dist/lite/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
- package/dist/lite/firestore/src/local/indexeddb_schema.d.ts +193 -7
- package/dist/lite/firestore/src/local/local_documents_view.d.ts +0 -1
- package/dist/lite/firestore/src/local/local_serializer.d.ts +18 -2
- package/dist/lite/firestore/src/local/memory_document_overlay_cache.d.ts +37 -0
- package/dist/lite/firestore/src/local/memory_index_manager.d.ts +11 -0
- package/dist/lite/firestore/src/local/memory_persistence.d.ts +6 -2
- package/dist/lite/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
- package/dist/lite/firestore/src/local/persistence.d.ts +8 -2
- package/dist/lite/firestore/src/local/remote_document_cache.d.ts +7 -9
- package/dist/lite/firestore/src/local/simple_db.d.ts +1 -0
- package/dist/lite/firestore/src/model/document_key.d.ts +4 -0
- package/dist/lite/firestore/src/model/field_index.d.ts +2 -2
- package/dist/lite/firestore/src/model/overlay.d.ts +32 -0
- package/dist/lite/firestore/src/model/target_index_matcher.d.ts +70 -0
- package/dist/lite/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
- package/dist/lite/firestore/test/unit/local/document_overlay_cache.test.d.ts +1 -0
- package/dist/lite/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
- package/dist/lite/firestore/test/unit/local/test_document_overlay_cache.d.ts +38 -0
- package/dist/lite/firestore/test/unit/local/test_index_manager.d.ts +11 -0
- package/dist/lite/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
- package/dist/lite/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
- package/dist/lite/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
- package/dist/lite/firestore/test/util/helpers.d.ts +1 -1
- package/dist/lite/index.browser.esm2017.js +1152 -1143
- package/dist/lite/index.browser.esm2017.js.map +1 -1
- package/dist/lite/index.browser.esm5.js +348 -341
- package/dist/lite/index.browser.esm5.js.map +1 -1
- package/dist/lite/index.node.cjs.js +44 -29
- package/dist/lite/index.node.cjs.js.map +1 -1
- package/dist/lite/index.node.mjs +44 -29
- package/dist/lite/index.node.mjs.map +1 -1
- package/dist/lite/index.rn.esm2017.js +1180 -1171
- package/dist/lite/index.rn.esm2017.js.map +1 -1
- package/dist/lite/internal.d.ts +6 -2
- package/dist/lite/packages/firestore/dist/lite/index.browser.esm2017.d.ts +121 -121
- package/dist/lite/packages/firestore/src/api/credentials.d.ts +1 -0
- package/dist/lite/packages/firestore/src/api/snapshot.d.ts +1 -2
- package/dist/lite/packages/firestore/src/core/target.d.ts +8 -4
- package/dist/lite/packages/firestore/src/lite-api/query.d.ts +2 -2
- package/dist/lite/packages/firestore/src/local/document_overlay_cache.d.ts +72 -0
- package/dist/lite/packages/firestore/src/local/index_manager.d.ts +52 -0
- package/dist/lite/packages/firestore/src/local/indexeddb_document_overlay_cache.d.ts +45 -0
- package/dist/lite/packages/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
- package/dist/lite/packages/firestore/src/local/indexeddb_persistence.d.ts +6 -4
- package/dist/lite/packages/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
- package/dist/lite/packages/firestore/src/local/indexeddb_schema.d.ts +193 -7
- package/dist/lite/packages/firestore/src/local/local_documents_view.d.ts +0 -1
- package/dist/lite/packages/firestore/src/local/local_serializer.d.ts +18 -2
- package/dist/lite/packages/firestore/src/local/memory_document_overlay_cache.d.ts +37 -0
- package/dist/lite/packages/firestore/src/local/memory_index_manager.d.ts +11 -0
- package/dist/lite/packages/firestore/src/local/memory_persistence.d.ts +6 -2
- package/dist/lite/packages/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
- package/dist/lite/packages/firestore/src/local/persistence.d.ts +8 -2
- package/dist/lite/packages/firestore/src/local/remote_document_cache.d.ts +7 -9
- package/dist/lite/packages/firestore/src/local/simple_db.d.ts +1 -0
- package/dist/lite/packages/firestore/src/model/document_key.d.ts +4 -0
- package/dist/lite/packages/firestore/src/model/field_index.d.ts +2 -2
- package/dist/lite/packages/firestore/src/model/overlay.d.ts +32 -0
- package/dist/lite/packages/firestore/src/model/target_index_matcher.d.ts +70 -0
- package/dist/lite/packages/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
- package/dist/lite/packages/firestore/test/unit/local/document_overlay_cache.test.d.ts +1 -0
- package/dist/lite/packages/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
- package/dist/lite/packages/firestore/test/unit/local/test_document_overlay_cache.d.ts +38 -0
- package/dist/lite/packages/firestore/test/unit/local/test_index_manager.d.ts +11 -0
- package/dist/lite/packages/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
- package/dist/lite/packages/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
- package/dist/lite/packages/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
- package/dist/lite/packages/firestore/test/util/helpers.d.ts +1 -1
- package/dist/lite/private.d.ts +2 -2
- package/dist/packages/firestore/dist/index.esm2017.d.ts +181 -179
- package/dist/packages/firestore/src/api/credentials.d.ts +1 -0
- package/dist/packages/firestore/src/api/snapshot.d.ts +1 -2
- package/dist/packages/firestore/src/core/target.d.ts +8 -4
- package/dist/packages/firestore/src/lite-api/query.d.ts +2 -2
- package/dist/packages/firestore/src/local/document_overlay_cache.d.ts +72 -0
- package/dist/packages/firestore/src/local/index_manager.d.ts +52 -0
- package/dist/packages/firestore/src/local/indexeddb_document_overlay_cache.d.ts +45 -0
- package/dist/packages/firestore/src/local/indexeddb_index_manager.d.ts +21 -2
- package/dist/packages/firestore/src/local/indexeddb_persistence.d.ts +6 -4
- package/dist/packages/firestore/src/local/indexeddb_remote_document_cache.d.ts +2 -8
- package/dist/packages/firestore/src/local/indexeddb_schema.d.ts +193 -7
- package/dist/packages/firestore/src/local/local_documents_view.d.ts +0 -1
- package/dist/packages/firestore/src/local/local_serializer.d.ts +18 -2
- package/dist/packages/firestore/src/local/memory_document_overlay_cache.d.ts +37 -0
- package/dist/packages/firestore/src/local/memory_index_manager.d.ts +11 -0
- package/dist/packages/firestore/src/local/memory_persistence.d.ts +6 -2
- package/dist/packages/firestore/src/local/memory_remote_document_cache.d.ts +1 -3
- package/dist/packages/firestore/src/local/persistence.d.ts +8 -2
- package/dist/packages/firestore/src/local/remote_document_cache.d.ts +7 -9
- package/dist/packages/firestore/src/local/simple_db.d.ts +1 -0
- package/dist/packages/firestore/src/model/document_key.d.ts +4 -0
- package/dist/packages/firestore/src/model/field_index.d.ts +2 -2
- package/dist/packages/firestore/src/model/overlay.d.ts +32 -0
- package/dist/packages/firestore/src/model/target_index_matcher.d.ts +70 -0
- package/dist/packages/firestore/test/unit/local/counting_query_engine.d.ts +3 -3
- package/dist/packages/firestore/test/unit/local/document_overlay_cache.test.d.ts +1 -0
- package/dist/packages/firestore/test/unit/local/persistence_test_helpers.d.ts +1 -0
- package/dist/packages/firestore/test/unit/local/test_document_overlay_cache.d.ts +38 -0
- package/dist/packages/firestore/test/unit/local/test_index_manager.d.ts +11 -0
- package/dist/packages/firestore/test/unit/local/test_remote_document_cache.d.ts +4 -2
- package/dist/packages/firestore/test/unit/local/test_remote_document_change_buffer.d.ts +1 -1
- package/dist/packages/firestore/test/unit/model/target_index_matcher.test.d.ts +17 -0
- package/dist/packages/firestore/test/util/helpers.d.ts +1 -1
- package/dist/private.d.ts +248 -14
- package/package.json +9 -9
package/dist/index.node.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import { credentials, loadPackageDefinition, Metadata } from '@grpc/grpc-js';
|
|
|
8
8
|
import { fromJSON } from '@grpc/proto-loader';
|
|
9
9
|
|
|
10
10
|
const name = "@firebase/firestore";
|
|
11
|
-
const version$1 = "3.4.4-canary.
|
|
11
|
+
const version$1 = "3.4.4-canary.3e9f3e253";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @license
|
|
@@ -61,7 +61,7 @@ User.GOOGLE_CREDENTIALS = new User('google-credentials-uid');
|
|
|
61
61
|
User.FIRST_PARTY = new User('first-party-uid');
|
|
62
62
|
User.MOCK_USER = new User('mock-user');
|
|
63
63
|
|
|
64
|
-
const version = "9.6.
|
|
64
|
+
const version = "9.6.6-canary.3e9f3e253";
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
67
|
* @license
|
|
@@ -666,13 +666,19 @@ class FirebaseAppCheckTokenProvider {
|
|
|
666
666
|
this.appCheckProvider = appCheckProvider;
|
|
667
667
|
this.forceRefresh = false;
|
|
668
668
|
this.appCheck = null;
|
|
669
|
+
this.latestAppCheckToken = null;
|
|
669
670
|
}
|
|
670
671
|
start(asyncQueue, changeListener) {
|
|
671
672
|
const onTokenChanged = tokenResult => {
|
|
672
673
|
if (tokenResult.error != null) {
|
|
673
674
|
logDebug('FirebaseAppCheckTokenProvider', `Error getting App Check token; using placeholder token instead. Error: ${tokenResult.error.message}`);
|
|
674
675
|
}
|
|
675
|
-
|
|
676
|
+
const tokenUpdated = tokenResult.token !== this.latestAppCheckToken;
|
|
677
|
+
this.latestAppCheckToken = tokenResult.token;
|
|
678
|
+
logDebug('FirebaseAppCheckTokenProvider', `Received ${tokenUpdated ? 'new' : 'existing'} token.`);
|
|
679
|
+
return tokenUpdated
|
|
680
|
+
? changeListener(tokenResult.token)
|
|
681
|
+
: Promise.resolve();
|
|
676
682
|
};
|
|
677
683
|
this.tokenListener = (tokenResult) => {
|
|
678
684
|
asyncQueue.enqueueRetryable(() => onTokenChanged(tokenResult));
|
|
@@ -707,6 +713,7 @@ class FirebaseAppCheckTokenProvider {
|
|
|
707
713
|
return this.appCheck.getToken(forceRefresh).then(tokenResult => {
|
|
708
714
|
if (tokenResult) {
|
|
709
715
|
hardAssert(typeof tokenResult.token === 'string');
|
|
716
|
+
this.latestAppCheckToken = tokenResult.token;
|
|
710
717
|
return new AppCheckToken(tokenResult.token);
|
|
711
718
|
}
|
|
712
719
|
else {
|
|
@@ -1192,23 +1199,6 @@ function decodeResourcePath(path) {
|
|
|
1192
1199
|
}
|
|
1193
1200
|
return new ResourcePath(segments);
|
|
1194
1201
|
}
|
|
1195
|
-
|
|
1196
|
-
/**
|
|
1197
|
-
* @license
|
|
1198
|
-
* Copyright 2017 Google LLC
|
|
1199
|
-
*
|
|
1200
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1201
|
-
* you may not use this file except in compliance with the License.
|
|
1202
|
-
* You may obtain a copy of the License at
|
|
1203
|
-
*
|
|
1204
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1205
|
-
*
|
|
1206
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
1207
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1208
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1209
|
-
* See the License for the specific language governing permissions and
|
|
1210
|
-
* limitations under the License.
|
|
1211
|
-
*/
|
|
1212
1202
|
/**
|
|
1213
1203
|
* Schema Version for the Web client:
|
|
1214
1204
|
* 1. Initial version including Mutation Queue, Query Cache, and Remote
|
|
@@ -1227,8 +1217,10 @@ function decodeResourcePath(path) {
|
|
|
1227
1217
|
* an auto-incrementing ID. This is required for Index-Free queries.
|
|
1228
1218
|
* 10. Rewrite the canonical IDs to the explicit Protobuf-based format.
|
|
1229
1219
|
* 11. Add bundles and named_queries for bundle support.
|
|
1220
|
+
* 12. Add document overlays.
|
|
1221
|
+
* 13. Add indexing support.
|
|
1230
1222
|
*/
|
|
1231
|
-
const SCHEMA_VERSION =
|
|
1223
|
+
const SCHEMA_VERSION = 12;
|
|
1232
1224
|
/**
|
|
1233
1225
|
* Wrapper class to store timestamps (seconds and nanos) in IndexedDb objects.
|
|
1234
1226
|
*/
|
|
@@ -1753,9 +1745,7 @@ class DbClientMetadata {
|
|
|
1753
1745
|
DbClientMetadata.store = 'clientMetadata';
|
|
1754
1746
|
/** Keys are automatically assigned via the clientId properties. */
|
|
1755
1747
|
DbClientMetadata.keyPath = 'clientId';
|
|
1756
|
-
/**
|
|
1757
|
-
* A object representing a bundle loaded by the SDK.
|
|
1758
|
-
*/
|
|
1748
|
+
/** An object representing a bundle loaded by the SDK. */
|
|
1759
1749
|
class DbBundle {
|
|
1760
1750
|
constructor(
|
|
1761
1751
|
/** The ID of the loaded bundle. */
|
|
@@ -1772,9 +1762,7 @@ class DbBundle {
|
|
|
1772
1762
|
/** Name of the IndexedDb object store. */
|
|
1773
1763
|
DbBundle.store = 'bundles';
|
|
1774
1764
|
DbBundle.keyPath = 'bundleId';
|
|
1775
|
-
/**
|
|
1776
|
-
* A object representing a named query loaded by the SDK via a bundle.
|
|
1777
|
-
*/
|
|
1765
|
+
/** An object representing a named query loaded by the SDK via a bundle. */
|
|
1778
1766
|
class DbNamedQuery {
|
|
1779
1767
|
constructor(
|
|
1780
1768
|
/** The name of the query. */
|
|
@@ -1791,6 +1779,156 @@ class DbNamedQuery {
|
|
|
1791
1779
|
/** Name of the IndexedDb object store. */
|
|
1792
1780
|
DbNamedQuery.store = 'namedQueries';
|
|
1793
1781
|
DbNamedQuery.keyPath = 'name';
|
|
1782
|
+
/** An object representing the global configuration for a field index. */
|
|
1783
|
+
class DbIndexConfiguration {
|
|
1784
|
+
constructor(
|
|
1785
|
+
/**
|
|
1786
|
+
* The index id for this entry. Undefined for indexes that are not yet
|
|
1787
|
+
* persisted.
|
|
1788
|
+
*/
|
|
1789
|
+
indexId,
|
|
1790
|
+
/** The collection group this index belongs to. */
|
|
1791
|
+
collectionGroup,
|
|
1792
|
+
/** The fields to index for this index. */
|
|
1793
|
+
fields) {
|
|
1794
|
+
this.indexId = indexId;
|
|
1795
|
+
this.collectionGroup = collectionGroup;
|
|
1796
|
+
this.fields = fields;
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
/** Name of the IndexedDb object store. */
|
|
1800
|
+
DbIndexConfiguration.store = 'indexConfiguration';
|
|
1801
|
+
DbIndexConfiguration.keyPath = 'indexId';
|
|
1802
|
+
/**
|
|
1803
|
+
* An index that provides access to the index configurations by collection
|
|
1804
|
+
* group.
|
|
1805
|
+
*
|
|
1806
|
+
* PORTING NOTE: iOS and Android maintain this index in-memory, but this is
|
|
1807
|
+
* not possible here as the Web client supports concurrent access to
|
|
1808
|
+
* persistence via multi-tab.
|
|
1809
|
+
*/
|
|
1810
|
+
DbIndexConfiguration.collectionGroupIndex = 'collectionGroupIndex';
|
|
1811
|
+
DbIndexConfiguration.collectionGroupIndexPath = 'collectionGroup';
|
|
1812
|
+
/**
|
|
1813
|
+
* An object describing how up-to-date the index backfill is for each user and
|
|
1814
|
+
* index.
|
|
1815
|
+
*/
|
|
1816
|
+
class DbIndexState {
|
|
1817
|
+
constructor(
|
|
1818
|
+
/** The index id for this entry. */
|
|
1819
|
+
indexId,
|
|
1820
|
+
/** The user id for this entry. */
|
|
1821
|
+
uid,
|
|
1822
|
+
/**
|
|
1823
|
+
* A number that indicates when the index was last updated (relative to
|
|
1824
|
+
* other indexes).
|
|
1825
|
+
*/
|
|
1826
|
+
sequenceNumber,
|
|
1827
|
+
/**
|
|
1828
|
+
* The latest read time that has been indexed by Firestore for this field
|
|
1829
|
+
* index. Set to `{seconds: 0, nanos: 0}` if no documents have been indexed.
|
|
1830
|
+
*/
|
|
1831
|
+
readTime,
|
|
1832
|
+
/**
|
|
1833
|
+
* The last document that has been indexed for this field index. Empty if
|
|
1834
|
+
* no documents have been indexed.
|
|
1835
|
+
*/
|
|
1836
|
+
documentKey,
|
|
1837
|
+
/**
|
|
1838
|
+
* The largest mutation batch id that has been processed for this index. -1
|
|
1839
|
+
* if no mutations have been indexed.
|
|
1840
|
+
*/
|
|
1841
|
+
largestBatchId) {
|
|
1842
|
+
this.indexId = indexId;
|
|
1843
|
+
this.uid = uid;
|
|
1844
|
+
this.sequenceNumber = sequenceNumber;
|
|
1845
|
+
this.readTime = readTime;
|
|
1846
|
+
this.documentKey = documentKey;
|
|
1847
|
+
this.largestBatchId = largestBatchId;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
/** Name of the IndexedDb object store. */
|
|
1851
|
+
DbIndexState.store = 'indexState';
|
|
1852
|
+
DbIndexState.keyPath = ['indexId', 'uid'];
|
|
1853
|
+
/**
|
|
1854
|
+
* An index that provides access to documents in a collection sorted by last
|
|
1855
|
+
* update time. Used by the backfiller.
|
|
1856
|
+
*
|
|
1857
|
+
* PORTING NOTE: iOS and Android maintain this index in-memory, but this is
|
|
1858
|
+
* not possible here as the Web client supports concurrent access to
|
|
1859
|
+
* persistence via multi-tab.
|
|
1860
|
+
*/
|
|
1861
|
+
DbIndexState.sequenceNumberIndex = 'sequenceNumberIndex';
|
|
1862
|
+
DbIndexState.sequenceNumberIndexPath = ['uid', 'sequenceNumber'];
|
|
1863
|
+
/** An object that stores the encoded entries for all documents and fields. */
|
|
1864
|
+
class DbIndexEntry {
|
|
1865
|
+
constructor(
|
|
1866
|
+
/** The index id for this entry. */
|
|
1867
|
+
indexId,
|
|
1868
|
+
/** The user id for this entry. */
|
|
1869
|
+
uid,
|
|
1870
|
+
/** The encoded array index value for this entry. */
|
|
1871
|
+
arrayValue,
|
|
1872
|
+
/** The encoded directional value for equality and inequality filters. */
|
|
1873
|
+
directionalValue,
|
|
1874
|
+
/** The document key this entry points to. */
|
|
1875
|
+
documentKey) {
|
|
1876
|
+
this.indexId = indexId;
|
|
1877
|
+
this.uid = uid;
|
|
1878
|
+
this.arrayValue = arrayValue;
|
|
1879
|
+
this.directionalValue = directionalValue;
|
|
1880
|
+
this.documentKey = documentKey;
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
/** Name of the IndexedDb object store. */
|
|
1884
|
+
DbIndexEntry.store = 'indexEntries';
|
|
1885
|
+
DbIndexEntry.keyPath = [
|
|
1886
|
+
'indexId',
|
|
1887
|
+
'uid',
|
|
1888
|
+
'arrayValue',
|
|
1889
|
+
'directionalValue',
|
|
1890
|
+
'documentKey'
|
|
1891
|
+
];
|
|
1892
|
+
/**
|
|
1893
|
+
* An object representing a document overlay.
|
|
1894
|
+
*/
|
|
1895
|
+
class DbDocumentOverlay {
|
|
1896
|
+
constructor(
|
|
1897
|
+
/** The user ID to whom this overlay belongs. */
|
|
1898
|
+
userId,
|
|
1899
|
+
/** The path to the collection that contains the document. */
|
|
1900
|
+
collectionPath,
|
|
1901
|
+
/** The ID (key) of the document within the collection. */
|
|
1902
|
+
documentId,
|
|
1903
|
+
/** The collection group to which the document belongs. */
|
|
1904
|
+
collectionGroup,
|
|
1905
|
+
/** The largest batch ID that's been applied for this overlay. */
|
|
1906
|
+
largestBatchId,
|
|
1907
|
+
/** The overlay mutation. */
|
|
1908
|
+
overlayMutation) {
|
|
1909
|
+
this.userId = userId;
|
|
1910
|
+
this.collectionPath = collectionPath;
|
|
1911
|
+
this.documentId = documentId;
|
|
1912
|
+
this.collectionGroup = collectionGroup;
|
|
1913
|
+
this.largestBatchId = largestBatchId;
|
|
1914
|
+
this.overlayMutation = overlayMutation;
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
/** Name of the IndexedDb object store. */
|
|
1918
|
+
DbDocumentOverlay.store = 'documentOverlays';
|
|
1919
|
+
DbDocumentOverlay.keyPath = ['userId', 'collectionPath', 'documentId'];
|
|
1920
|
+
DbDocumentOverlay.collectionPathOverlayIndex = 'collectionPathOverlayIndex';
|
|
1921
|
+
DbDocumentOverlay.collectionPathOverlayIndexPath = [
|
|
1922
|
+
'userId',
|
|
1923
|
+
'collectionPath',
|
|
1924
|
+
'largestBatchId'
|
|
1925
|
+
];
|
|
1926
|
+
DbDocumentOverlay.collectionGroupOverlayIndex = 'collectionGroupOverlayIndex';
|
|
1927
|
+
DbDocumentOverlay.collectionGroupOverlayIndexPath = [
|
|
1928
|
+
'userId',
|
|
1929
|
+
'collectionGroup',
|
|
1930
|
+
'largestBatchId'
|
|
1931
|
+
];
|
|
1794
1932
|
// Visible for testing
|
|
1795
1933
|
const V1_STORES = [
|
|
1796
1934
|
DbMutationQueue.store,
|
|
@@ -1805,7 +1943,6 @@ const V1_STORES = [
|
|
|
1805
1943
|
// V2 is no longer usable (see comment at top of file)
|
|
1806
1944
|
// Visible for testing
|
|
1807
1945
|
const V3_STORES = V1_STORES;
|
|
1808
|
-
// Visible for testing
|
|
1809
1946
|
// Note: DbRemoteDocumentChanges is no longer used and dropped with v9.
|
|
1810
1947
|
const V4_STORES = [...V3_STORES, DbClientMetadata.store];
|
|
1811
1948
|
// V5 does not change the set of stores.
|
|
@@ -1815,12 +1952,28 @@ const V8_STORES = [...V6_STORES, DbCollectionParent.store];
|
|
|
1815
1952
|
// V9 does not change the set of stores.
|
|
1816
1953
|
// V10 does not change the set of stores.
|
|
1817
1954
|
const V11_STORES = [...V8_STORES, DbBundle.store, DbNamedQuery.store];
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1955
|
+
const V12_STORES = [...V11_STORES, DbDocumentOverlay.store];
|
|
1956
|
+
const V13_STORES = [
|
|
1957
|
+
...V12_STORES,
|
|
1958
|
+
DbIndexConfiguration.store,
|
|
1959
|
+
DbIndexState.store,
|
|
1960
|
+
DbIndexEntry.store
|
|
1961
|
+
];
|
|
1962
|
+
/** Returns the object stores for the provided schema. */
|
|
1963
|
+
function getObjectStores(schemaVersion) {
|
|
1964
|
+
if (schemaVersion === 13) {
|
|
1965
|
+
return V13_STORES;
|
|
1966
|
+
}
|
|
1967
|
+
else if (schemaVersion === 12) {
|
|
1968
|
+
return V12_STORES;
|
|
1969
|
+
}
|
|
1970
|
+
else if (schemaVersion === 11) {
|
|
1971
|
+
return V11_STORES;
|
|
1972
|
+
}
|
|
1973
|
+
else {
|
|
1974
|
+
fail();
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1824
1977
|
|
|
1825
1978
|
/**
|
|
1826
1979
|
* @license
|
|
@@ -2117,6 +2270,15 @@ class SimpleDbTransaction {
|
|
|
2117
2270
|
this.transaction.abort();
|
|
2118
2271
|
}
|
|
2119
2272
|
}
|
|
2273
|
+
maybeCommit() {
|
|
2274
|
+
// If the browser supports V3 IndexedDB, we invoke commit() explicitly to
|
|
2275
|
+
// speed up index DB processing if the event loop remains blocks.
|
|
2276
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2277
|
+
const maybeV3IndexedDb = this.transaction;
|
|
2278
|
+
if (!this.aborted && typeof maybeV3IndexedDb.commit === 'function') {
|
|
2279
|
+
maybeV3IndexedDb.commit();
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2120
2282
|
/**
|
|
2121
2283
|
* Returns a SimpleDbStore<KeyType, ValueType> for the specified store. All
|
|
2122
2284
|
* operations performed on the SimpleDbStore happen within the context of this
|
|
@@ -2313,6 +2475,10 @@ class SimpleDb {
|
|
|
2313
2475
|
this.db = await this.ensureDb(action);
|
|
2314
2476
|
const transaction = SimpleDbTransaction.open(this.db, action, readonly ? 'readonly' : 'readwrite', objectStores);
|
|
2315
2477
|
const transactionFnResult = transactionFn(transaction)
|
|
2478
|
+
.next(result => {
|
|
2479
|
+
transaction.maybeCommit();
|
|
2480
|
+
return result;
|
|
2481
|
+
})
|
|
2316
2482
|
.catch(error => {
|
|
2317
2483
|
// Abort the transaction if there was an error.
|
|
2318
2484
|
transaction.abort(error);
|
|
@@ -2485,13 +2651,29 @@ class SimpleDbStore {
|
|
|
2485
2651
|
return wrapRequest(request);
|
|
2486
2652
|
}
|
|
2487
2653
|
loadAll(indexOrRange, range) {
|
|
2488
|
-
const
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
return
|
|
2494
|
-
|
|
2654
|
+
const iterateOptions = this.options(indexOrRange, range);
|
|
2655
|
+
// Use `getAll()` if the browser supports IndexedDB v3, as it is roughly
|
|
2656
|
+
// 20% faster. Unfortunately, getAll() does not support custom indices.
|
|
2657
|
+
if (!iterateOptions.index && typeof this.store.getAll === 'function') {
|
|
2658
|
+
const request = this.store.getAll(iterateOptions.range);
|
|
2659
|
+
return new PersistencePromise((resolve, reject) => {
|
|
2660
|
+
request.onerror = (event) => {
|
|
2661
|
+
reject(event.target.error);
|
|
2662
|
+
};
|
|
2663
|
+
request.onsuccess = (event) => {
|
|
2664
|
+
resolve(event.target.result);
|
|
2665
|
+
};
|
|
2666
|
+
});
|
|
2667
|
+
}
|
|
2668
|
+
else {
|
|
2669
|
+
const cursor = this.cursor(iterateOptions);
|
|
2670
|
+
const results = [];
|
|
2671
|
+
return this.iterateCursor(cursor, (key, value) => {
|
|
2672
|
+
results.push(value);
|
|
2673
|
+
}).next(() => {
|
|
2674
|
+
return results;
|
|
2675
|
+
});
|
|
2676
|
+
}
|
|
2495
2677
|
}
|
|
2496
2678
|
deleteAll(indexOrRange, range) {
|
|
2497
2679
|
logDebug(LOG_TAG$g, 'DELETE ALL', this.store.name);
|
|
@@ -3522,6 +3704,14 @@ class DocumentKey {
|
|
|
3522
3704
|
return (this.path.length >= 2 &&
|
|
3523
3705
|
this.path.get(this.path.length - 2) === collectionId);
|
|
3524
3706
|
}
|
|
3707
|
+
/** Returns the collection group (i.e. the name of the parent collection) for this key. */
|
|
3708
|
+
getCollectionGroup() {
|
|
3709
|
+
return this.path.get(this.path.length - 2);
|
|
3710
|
+
}
|
|
3711
|
+
/** Returns the fully qualified path to the parent collection. */
|
|
3712
|
+
getCollectionPath() {
|
|
3713
|
+
return this.path.popLast();
|
|
3714
|
+
}
|
|
3525
3715
|
isEqual(other) {
|
|
3526
3716
|
return (other !== null && ResourcePath.comparator(this.path, other.path) === 0);
|
|
3527
3717
|
}
|
|
@@ -4345,12 +4535,12 @@ class FieldIndex {
|
|
|
4345
4535
|
/** The collection ID this index applies to. */
|
|
4346
4536
|
collectionGroup,
|
|
4347
4537
|
/** The field segments for this index. */
|
|
4348
|
-
|
|
4538
|
+
fields,
|
|
4349
4539
|
/** Shows how up-to-date the index is for the current user. */
|
|
4350
4540
|
indexState) {
|
|
4351
4541
|
this.indexId = indexId;
|
|
4352
4542
|
this.collectionGroup = collectionGroup;
|
|
4353
|
-
this.
|
|
4543
|
+
this.fields = fields;
|
|
4354
4544
|
this.indexState = indexState;
|
|
4355
4545
|
}
|
|
4356
4546
|
}
|
|
@@ -4460,27 +4650,29 @@ function newTarget(path, collectionGroup = null, orderBy = [], filters = [], lim
|
|
|
4460
4650
|
function canonifyTarget(target) {
|
|
4461
4651
|
const targetImpl = debugCast(target);
|
|
4462
4652
|
if (targetImpl.memoizedCanonicalId === null) {
|
|
4463
|
-
let
|
|
4653
|
+
let str = targetImpl.path.canonicalString();
|
|
4464
4654
|
if (targetImpl.collectionGroup !== null) {
|
|
4465
|
-
|
|
4655
|
+
str += '|cg:' + targetImpl.collectionGroup;
|
|
4466
4656
|
}
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4657
|
+
str += '|f:';
|
|
4658
|
+
str += targetImpl.filters.map(f => canonifyFilter(f)).join(',');
|
|
4659
|
+
str += '|ob:';
|
|
4660
|
+
str += targetImpl.orderBy.map(o => canonifyOrderBy(o)).join(',');
|
|
4471
4661
|
if (!isNullOrUndefined(targetImpl.limit)) {
|
|
4472
|
-
|
|
4473
|
-
|
|
4662
|
+
str += '|l:';
|
|
4663
|
+
str += targetImpl.limit;
|
|
4474
4664
|
}
|
|
4475
4665
|
if (targetImpl.startAt) {
|
|
4476
|
-
|
|
4477
|
-
|
|
4666
|
+
str += '|lb:';
|
|
4667
|
+
str += targetImpl.startAt.inclusive ? 'b:' : 'a:';
|
|
4668
|
+
str += targetImpl.startAt.position.map(p => canonicalId(p)).join(',');
|
|
4478
4669
|
}
|
|
4479
4670
|
if (targetImpl.endAt) {
|
|
4480
|
-
|
|
4481
|
-
|
|
4671
|
+
str += '|ub:';
|
|
4672
|
+
str += targetImpl.endAt.inclusive ? 'a:' : 'b:';
|
|
4673
|
+
str += targetImpl.endAt.position.map(p => canonicalId(p)).join(',');
|
|
4482
4674
|
}
|
|
4483
|
-
targetImpl.memoizedCanonicalId =
|
|
4675
|
+
targetImpl.memoizedCanonicalId = str;
|
|
4484
4676
|
}
|
|
4485
4677
|
return targetImpl.memoizedCanonicalId;
|
|
4486
4678
|
}
|
|
@@ -4503,10 +4695,14 @@ function stringifyTarget(target) {
|
|
|
4503
4695
|
.join(', ')}]`;
|
|
4504
4696
|
}
|
|
4505
4697
|
if (target.startAt) {
|
|
4506
|
-
str += ', startAt: '
|
|
4698
|
+
str += ', startAt: ';
|
|
4699
|
+
str += target.startAt.inclusive ? 'b:' : 'a:';
|
|
4700
|
+
str += target.startAt.position.map(p => canonicalId(p)).join(',');
|
|
4507
4701
|
}
|
|
4508
4702
|
if (target.endAt) {
|
|
4509
|
-
str += ', endAt: '
|
|
4703
|
+
str += ', endAt: ';
|
|
4704
|
+
str += target.endAt.inclusive ? 'a:' : 'b:';
|
|
4705
|
+
str += target.endAt.position.map(p => canonicalId(p)).join(',');
|
|
4510
4706
|
}
|
|
4511
4707
|
return `Target(${str})`;
|
|
4512
4708
|
}
|
|
@@ -4729,7 +4925,6 @@ class ArrayContainsAnyFilter extends FieldFilter {
|
|
|
4729
4925
|
return other.arrayValue.values.some(val => arrayValueContains(this.value.arrayValue, val));
|
|
4730
4926
|
}
|
|
4731
4927
|
}
|
|
4732
|
-
// TODO(indexing): Change Bound.before to "inclusive"
|
|
4733
4928
|
/**
|
|
4734
4929
|
* Represents a bound of a query.
|
|
4735
4930
|
*
|
|
@@ -4745,17 +4940,11 @@ class ArrayContainsAnyFilter extends FieldFilter {
|
|
|
4745
4940
|
* just after the provided values.
|
|
4746
4941
|
*/
|
|
4747
4942
|
class Bound {
|
|
4748
|
-
constructor(position,
|
|
4943
|
+
constructor(position, inclusive) {
|
|
4749
4944
|
this.position = position;
|
|
4750
|
-
this.
|
|
4945
|
+
this.inclusive = inclusive;
|
|
4751
4946
|
}
|
|
4752
4947
|
}
|
|
4753
|
-
function canonifyBound(bound) {
|
|
4754
|
-
// TODO(b/29183165): Make this collision robust.
|
|
4755
|
-
return `${bound.before ? 'b' : 'a'}:${bound.position
|
|
4756
|
-
.map(p => canonicalId(p))
|
|
4757
|
-
.join(',')}`;
|
|
4758
|
-
}
|
|
4759
4948
|
/**
|
|
4760
4949
|
* An ordering on a field, in some Direction. Direction defaults to ASCENDING.
|
|
4761
4950
|
*/
|
|
@@ -4775,11 +4964,7 @@ function stringifyOrderBy(orderBy) {
|
|
|
4775
4964
|
function orderByEquals(left, right) {
|
|
4776
4965
|
return left.dir === right.dir && left.field.isEqual(right.field);
|
|
4777
4966
|
}
|
|
4778
|
-
|
|
4779
|
-
* Returns true if a document sorts before a bound using the provided sort
|
|
4780
|
-
* order.
|
|
4781
|
-
*/
|
|
4782
|
-
function sortsBeforeDocument(bound, orderBy, doc) {
|
|
4967
|
+
function boundCompareToDocument(bound, orderBy, doc) {
|
|
4783
4968
|
let comparison = 0;
|
|
4784
4969
|
for (let i = 0; i < bound.position.length; i++) {
|
|
4785
4970
|
const orderByComponent = orderBy[i];
|
|
@@ -4798,7 +4983,23 @@ function sortsBeforeDocument(bound, orderBy, doc) {
|
|
|
4798
4983
|
break;
|
|
4799
4984
|
}
|
|
4800
4985
|
}
|
|
4801
|
-
return
|
|
4986
|
+
return comparison;
|
|
4987
|
+
}
|
|
4988
|
+
/**
|
|
4989
|
+
* Returns true if a document sorts after a bound using the provided sort
|
|
4990
|
+
* order.
|
|
4991
|
+
*/
|
|
4992
|
+
function boundSortsAfterDocument(bound, orderBy, doc) {
|
|
4993
|
+
const comparison = boundCompareToDocument(bound, orderBy, doc);
|
|
4994
|
+
return bound.inclusive ? comparison >= 0 : comparison > 0;
|
|
4995
|
+
}
|
|
4996
|
+
/**
|
|
4997
|
+
* Returns true if a document sorts before a bound using the provided sort
|
|
4998
|
+
* order.
|
|
4999
|
+
*/
|
|
5000
|
+
function boundSortsBeforeDocument(bound, orderBy, doc) {
|
|
5001
|
+
const comparison = boundCompareToDocument(bound, orderBy, doc);
|
|
5002
|
+
return bound.inclusive ? comparison <= 0 : comparison < 0;
|
|
4802
5003
|
}
|
|
4803
5004
|
function boundEquals(left, right) {
|
|
4804
5005
|
if (left === null) {
|
|
@@ -4807,7 +5008,7 @@ function boundEquals(left, right) {
|
|
|
4807
5008
|
else if (right === null) {
|
|
4808
5009
|
return false;
|
|
4809
5010
|
}
|
|
4810
|
-
if (left.
|
|
5011
|
+
if (left.inclusive !== right.inclusive ||
|
|
4811
5012
|
left.position.length !== right.position.length) {
|
|
4812
5013
|
return false;
|
|
4813
5014
|
}
|
|
@@ -5011,10 +5212,10 @@ function queryToTarget(query) {
|
|
|
5011
5212
|
}
|
|
5012
5213
|
// We need to swap the cursors to match the now-flipped query ordering.
|
|
5013
5214
|
const startAt = queryImpl.endAt
|
|
5014
|
-
? new Bound(queryImpl.endAt.position, !queryImpl.endAt.
|
|
5215
|
+
? new Bound(queryImpl.endAt.position, !queryImpl.endAt.inclusive)
|
|
5015
5216
|
: null;
|
|
5016
5217
|
const endAt = queryImpl.startAt
|
|
5017
|
-
? new Bound(queryImpl.startAt.position, !queryImpl.startAt.
|
|
5218
|
+
? new Bound(queryImpl.startAt.position, !queryImpl.startAt.inclusive)
|
|
5018
5219
|
: null;
|
|
5019
5220
|
// Now return as a LimitType.First query.
|
|
5020
5221
|
queryImpl.memoizedTarget = newTarget(queryImpl.path, queryImpl.collectionGroup, orderBys, queryImpl.filters, queryImpl.limit, startAt, endAt);
|
|
@@ -5102,11 +5303,11 @@ function queryMatchesFilters(query, doc) {
|
|
|
5102
5303
|
/** Makes sure a document is within the bounds, if provided. */
|
|
5103
5304
|
function queryMatchesBounds(query, doc) {
|
|
5104
5305
|
if (query.startAt &&
|
|
5105
|
-
!
|
|
5306
|
+
!boundSortsBeforeDocument(query.startAt, queryOrderBy(query), doc)) {
|
|
5106
5307
|
return false;
|
|
5107
5308
|
}
|
|
5108
5309
|
if (query.endAt &&
|
|
5109
|
-
|
|
5310
|
+
!boundSortsAfterDocument(query.endAt, queryOrderBy(query), doc)) {
|
|
5110
5311
|
return false;
|
|
5111
5312
|
}
|
|
5112
5313
|
return true;
|
|
@@ -6599,6 +6800,47 @@ class MutationBatchResult {
|
|
|
6599
6800
|
}
|
|
6600
6801
|
}
|
|
6601
6802
|
|
|
6803
|
+
/**
|
|
6804
|
+
* @license
|
|
6805
|
+
* Copyright 2022 Google LLC
|
|
6806
|
+
*
|
|
6807
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6808
|
+
* you may not use this file except in compliance with the License.
|
|
6809
|
+
* You may obtain a copy of the License at
|
|
6810
|
+
*
|
|
6811
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
6812
|
+
*
|
|
6813
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
6814
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
6815
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
6816
|
+
* See the License for the specific language governing permissions and
|
|
6817
|
+
* limitations under the License.
|
|
6818
|
+
*/
|
|
6819
|
+
/**
|
|
6820
|
+
* Representation of an overlay computed by Firestore.
|
|
6821
|
+
*
|
|
6822
|
+
* Holds information about a mutation and the largest batch id in Firestore when
|
|
6823
|
+
* the mutation was created.
|
|
6824
|
+
*/
|
|
6825
|
+
class Overlay {
|
|
6826
|
+
constructor(largestBatchId, mutation) {
|
|
6827
|
+
this.largestBatchId = largestBatchId;
|
|
6828
|
+
this.mutation = mutation;
|
|
6829
|
+
}
|
|
6830
|
+
getKey() {
|
|
6831
|
+
return this.mutation.key;
|
|
6832
|
+
}
|
|
6833
|
+
isEqual(other) {
|
|
6834
|
+
return other !== null && this.mutation === other.mutation;
|
|
6835
|
+
}
|
|
6836
|
+
toString() {
|
|
6837
|
+
return `Overlay{
|
|
6838
|
+
largestBatchId: ${this.largestBatchId},
|
|
6839
|
+
mutation: ${this.mutation.toString()}
|
|
6840
|
+
}`;
|
|
6841
|
+
}
|
|
6842
|
+
}
|
|
6843
|
+
|
|
6602
6844
|
/**
|
|
6603
6845
|
* @license
|
|
6604
6846
|
* Copyright 2017 Google LLC
|
|
@@ -7985,10 +8227,10 @@ function toQueryTarget(serializer, target) {
|
|
|
7985
8227
|
result.structuredQuery.limit = limit;
|
|
7986
8228
|
}
|
|
7987
8229
|
if (target.startAt) {
|
|
7988
|
-
result.structuredQuery.startAt =
|
|
8230
|
+
result.structuredQuery.startAt = toStartAtCursor(target.startAt);
|
|
7989
8231
|
}
|
|
7990
8232
|
if (target.endAt) {
|
|
7991
|
-
result.structuredQuery.endAt =
|
|
8233
|
+
result.structuredQuery.endAt = toEndAtCursor(target.endAt);
|
|
7992
8234
|
}
|
|
7993
8235
|
return result;
|
|
7994
8236
|
}
|
|
@@ -8021,11 +8263,11 @@ function convertQueryTargetToQuery(target) {
|
|
|
8021
8263
|
}
|
|
8022
8264
|
let startAt = null;
|
|
8023
8265
|
if (query.startAt) {
|
|
8024
|
-
startAt =
|
|
8266
|
+
startAt = fromStartAtCursor(query.startAt);
|
|
8025
8267
|
}
|
|
8026
8268
|
let endAt = null;
|
|
8027
8269
|
if (query.endAt) {
|
|
8028
|
-
endAt =
|
|
8270
|
+
endAt = fromEndAtCursor(query.endAt);
|
|
8029
8271
|
}
|
|
8030
8272
|
return newQuery(path, collectionGroup, orderBy, filterBy, limit, "F" /* First */, startAt, endAt);
|
|
8031
8273
|
}
|
|
@@ -8116,16 +8358,27 @@ function toOrder(orderBys) {
|
|
|
8116
8358
|
function fromOrder(orderBys) {
|
|
8117
8359
|
return orderBys.map(order => fromPropertyOrder(order));
|
|
8118
8360
|
}
|
|
8119
|
-
function
|
|
8361
|
+
function toStartAtCursor(cursor) {
|
|
8362
|
+
return {
|
|
8363
|
+
before: cursor.inclusive,
|
|
8364
|
+
values: cursor.position
|
|
8365
|
+
};
|
|
8366
|
+
}
|
|
8367
|
+
function toEndAtCursor(cursor) {
|
|
8120
8368
|
return {
|
|
8121
|
-
before: cursor.
|
|
8369
|
+
before: !cursor.inclusive,
|
|
8122
8370
|
values: cursor.position
|
|
8123
8371
|
};
|
|
8124
8372
|
}
|
|
8125
|
-
function
|
|
8126
|
-
const
|
|
8373
|
+
function fromStartAtCursor(cursor) {
|
|
8374
|
+
const inclusive = !!cursor.before;
|
|
8127
8375
|
const position = cursor.values || [];
|
|
8128
|
-
return new Bound(position,
|
|
8376
|
+
return new Bound(position, inclusive);
|
|
8377
|
+
}
|
|
8378
|
+
function fromEndAtCursor(cursor) {
|
|
8379
|
+
const inclusive = !cursor.before;
|
|
8380
|
+
const position = cursor.values || [];
|
|
8381
|
+
return new Bound(position, inclusive);
|
|
8129
8382
|
}
|
|
8130
8383
|
// visible for testing
|
|
8131
8384
|
function toDirection(dir) {
|
|
@@ -8589,6 +8842,37 @@ function fromBundleMetadata(metadata) {
|
|
|
8589
8842
|
version: metadata.version,
|
|
8590
8843
|
createTime: fromVersion(metadata.createTime)
|
|
8591
8844
|
};
|
|
8845
|
+
}
|
|
8846
|
+
/** Encodes a DbDocumentOverlay object to an Overlay model object. */
|
|
8847
|
+
function fromDbDocumentOverlay(localSerializer, dbDocumentOverlay) {
|
|
8848
|
+
return new Overlay(dbDocumentOverlay.largestBatchId, fromMutation(localSerializer.remoteSerializer, dbDocumentOverlay.overlayMutation));
|
|
8849
|
+
}
|
|
8850
|
+
/** Decodes an Overlay model object into a DbDocumentOverlay object. */
|
|
8851
|
+
function toDbDocumentOverlay(localSerializer, userId, overlay) {
|
|
8852
|
+
const [_, collectionPath, documentId] = toDbDocumentOverlayKey(userId, overlay.mutation.key);
|
|
8853
|
+
return new DbDocumentOverlay(userId, collectionPath, documentId, overlay.mutation.key.getCollectionGroup(), overlay.largestBatchId, toMutation(localSerializer.remoteSerializer, overlay.mutation));
|
|
8854
|
+
}
|
|
8855
|
+
/**
|
|
8856
|
+
* Returns the DbDocumentOverlayKey corresponding to the given user and
|
|
8857
|
+
* document key.
|
|
8858
|
+
*/
|
|
8859
|
+
function toDbDocumentOverlayKey(userId, docKey) {
|
|
8860
|
+
const docId = docKey.path.lastSegment();
|
|
8861
|
+
const collectionPath = encodeResourcePath(docKey.path.popLast());
|
|
8862
|
+
return [userId, collectionPath, docId];
|
|
8863
|
+
}
|
|
8864
|
+
function toDbIndexConfiguration(index) {
|
|
8865
|
+
return new DbIndexConfiguration(index.indexId, index.collectionGroup, index.fields.map(s => [s.fieldPath.canonicalString(), s.kind]));
|
|
8866
|
+
}
|
|
8867
|
+
function fromDbIndexConfiguration(index, state) {
|
|
8868
|
+
const decodedState = state
|
|
8869
|
+
? new IndexState(state.sequenceNumber, new IndexOffset(fromDbTimestamp(state.readTime), new DocumentKey(decodeResourcePath(state.documentKey)), state.largestBatchId))
|
|
8870
|
+
: IndexState.empty();
|
|
8871
|
+
const decodedSegments = index.fields.map(([fieldPath, kind]) => new IndexSegment(FieldPath$1.fromServerFormat(fieldPath), kind));
|
|
8872
|
+
return new FieldIndex(index.indexId, index.collectionGroup, decodedSegments, decodedState);
|
|
8873
|
+
}
|
|
8874
|
+
function toDbIndexState(indexId, user, sequenceNumber, offset) {
|
|
8875
|
+
return new DbIndexState(indexId, user.uid || '', sequenceNumber, toDbTimestamp(offset.readTime), encodeResourcePath(offset.documentKey.path), offset.largestBatchId);
|
|
8592
8876
|
}
|
|
8593
8877
|
|
|
8594
8878
|
/**
|
|
@@ -8648,6 +8932,125 @@ function namedQueriesStore(txn) {
|
|
|
8648
8932
|
return getStore(txn, DbNamedQuery.store);
|
|
8649
8933
|
}
|
|
8650
8934
|
|
|
8935
|
+
/**
|
|
8936
|
+
* @license
|
|
8937
|
+
* Copyright 2022 Google LLC
|
|
8938
|
+
*
|
|
8939
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8940
|
+
* you may not use this file except in compliance with the License.
|
|
8941
|
+
* You may obtain a copy of the License at
|
|
8942
|
+
*
|
|
8943
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8944
|
+
*
|
|
8945
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
8946
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
8947
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
8948
|
+
* See the License for the specific language governing permissions and
|
|
8949
|
+
* limitations under the License.
|
|
8950
|
+
*/
|
|
8951
|
+
/**
|
|
8952
|
+
* Implementation of DocumentOverlayCache using IndexedDb.
|
|
8953
|
+
*/
|
|
8954
|
+
class IndexedDbDocumentOverlayCache {
|
|
8955
|
+
/**
|
|
8956
|
+
* @param serializer - The document serializer.
|
|
8957
|
+
* @param userId - The userId for which we are accessing overlays.
|
|
8958
|
+
*/
|
|
8959
|
+
constructor(serializer, userId) {
|
|
8960
|
+
this.serializer = serializer;
|
|
8961
|
+
this.userId = userId;
|
|
8962
|
+
}
|
|
8963
|
+
static forUser(serializer, user) {
|
|
8964
|
+
const userId = user.uid || '';
|
|
8965
|
+
return new IndexedDbDocumentOverlayCache(serializer, userId);
|
|
8966
|
+
}
|
|
8967
|
+
getOverlay(transaction, key) {
|
|
8968
|
+
return documentOverlayStore(transaction)
|
|
8969
|
+
.get(toDbDocumentOverlayKey(this.userId, key))
|
|
8970
|
+
.next(dbOverlay => {
|
|
8971
|
+
if (dbOverlay) {
|
|
8972
|
+
return fromDbDocumentOverlay(this.serializer, dbOverlay);
|
|
8973
|
+
}
|
|
8974
|
+
return null;
|
|
8975
|
+
});
|
|
8976
|
+
}
|
|
8977
|
+
saveOverlays(transaction, largestBatchId, overlays) {
|
|
8978
|
+
const promises = [];
|
|
8979
|
+
overlays.forEach(mutation => {
|
|
8980
|
+
const overlay = new Overlay(largestBatchId, mutation);
|
|
8981
|
+
promises.push(this.saveOverlay(transaction, overlay));
|
|
8982
|
+
});
|
|
8983
|
+
return PersistencePromise.waitFor(promises);
|
|
8984
|
+
}
|
|
8985
|
+
removeOverlaysForBatchId(transaction, documentKeys, batchId) {
|
|
8986
|
+
const collectionPaths = new Set();
|
|
8987
|
+
// Get the set of unique collection paths.
|
|
8988
|
+
documentKeys.forEach(key => collectionPaths.add(encodeResourcePath(key.getCollectionPath())));
|
|
8989
|
+
const promises = [];
|
|
8990
|
+
collectionPaths.forEach(collectionPath => {
|
|
8991
|
+
const range = IDBKeyRange.bound([this.userId, collectionPath, batchId], [this.userId, collectionPath, batchId + 1],
|
|
8992
|
+
/*lowerOpen=*/ false,
|
|
8993
|
+
/*upperOpen=*/ true);
|
|
8994
|
+
promises.push(documentOverlayStore(transaction).deleteAll(DbDocumentOverlay.collectionPathOverlayIndex, range));
|
|
8995
|
+
});
|
|
8996
|
+
return PersistencePromise.waitFor(promises);
|
|
8997
|
+
}
|
|
8998
|
+
getOverlaysForCollection(transaction, collection, sinceBatchId) {
|
|
8999
|
+
const result = new Map();
|
|
9000
|
+
const collectionPath = encodeResourcePath(collection);
|
|
9001
|
+
// We want batch IDs larger than `sinceBatchId`, and so the lower bound
|
|
9002
|
+
// is not inclusive.
|
|
9003
|
+
const range = IDBKeyRange.bound([this.userId, collectionPath, sinceBatchId], [this.userId, collectionPath, Number.POSITIVE_INFINITY],
|
|
9004
|
+
/*lowerOpen=*/ true);
|
|
9005
|
+
return documentOverlayStore(transaction)
|
|
9006
|
+
.loadAll(DbDocumentOverlay.collectionPathOverlayIndex, range)
|
|
9007
|
+
.next(dbOverlays => {
|
|
9008
|
+
for (const dbOverlay of dbOverlays) {
|
|
9009
|
+
const overlay = fromDbDocumentOverlay(this.serializer, dbOverlay);
|
|
9010
|
+
result.set(overlay.getKey(), overlay);
|
|
9011
|
+
}
|
|
9012
|
+
return result;
|
|
9013
|
+
});
|
|
9014
|
+
}
|
|
9015
|
+
getOverlaysForCollectionGroup(transaction, collectionGroup, sinceBatchId, count) {
|
|
9016
|
+
const result = new Map();
|
|
9017
|
+
let currentBatchId = undefined;
|
|
9018
|
+
// We want batch IDs larger than `sinceBatchId`, and so the lower bound
|
|
9019
|
+
// is not inclusive.
|
|
9020
|
+
const range = IDBKeyRange.bound([this.userId, collectionGroup, sinceBatchId], [this.userId, collectionGroup, Number.POSITIVE_INFINITY],
|
|
9021
|
+
/*lowerOpen=*/ true);
|
|
9022
|
+
return documentOverlayStore(transaction)
|
|
9023
|
+
.iterate({
|
|
9024
|
+
index: DbDocumentOverlay.collectionGroupOverlayIndex,
|
|
9025
|
+
range
|
|
9026
|
+
}, (_, dbOverlay, control) => {
|
|
9027
|
+
// We do not want to return partial batch overlays, even if the size
|
|
9028
|
+
// of the result set exceeds the given `count` argument. Therefore, we
|
|
9029
|
+
// continue to aggregate results even after the result size exceeds
|
|
9030
|
+
// `count` if there are more overlays from the `currentBatchId`.
|
|
9031
|
+
const overlay = fromDbDocumentOverlay(this.serializer, dbOverlay);
|
|
9032
|
+
if (result.size < count ||
|
|
9033
|
+
overlay.largestBatchId === currentBatchId) {
|
|
9034
|
+
result.set(overlay.getKey(), overlay);
|
|
9035
|
+
currentBatchId = overlay.largestBatchId;
|
|
9036
|
+
}
|
|
9037
|
+
else {
|
|
9038
|
+
control.done();
|
|
9039
|
+
}
|
|
9040
|
+
})
|
|
9041
|
+
.next(() => result);
|
|
9042
|
+
}
|
|
9043
|
+
saveOverlay(transaction, overlay) {
|
|
9044
|
+
return documentOverlayStore(transaction).put(toDbDocumentOverlay(this.serializer, this.userId, overlay));
|
|
9045
|
+
}
|
|
9046
|
+
}
|
|
9047
|
+
/**
|
|
9048
|
+
* Helper to get a typed SimpleDbStore for the document overlay object store.
|
|
9049
|
+
*/
|
|
9050
|
+
function documentOverlayStore(txn) {
|
|
9051
|
+
return getStore(txn, DbDocumentOverlay.store);
|
|
9052
|
+
}
|
|
9053
|
+
|
|
8651
9054
|
/**
|
|
8652
9055
|
* @license
|
|
8653
9056
|
* Copyright 2019 Google LLC
|
|
@@ -8678,6 +9081,38 @@ class MemoryIndexManager {
|
|
|
8678
9081
|
getCollectionParents(transaction, collectionId) {
|
|
8679
9082
|
return PersistencePromise.resolve(this.collectionParentIndex.getEntries(collectionId));
|
|
8680
9083
|
}
|
|
9084
|
+
addFieldIndex(transaction, index) {
|
|
9085
|
+
// Field indices are not supported with memory persistence.
|
|
9086
|
+
return PersistencePromise.resolve();
|
|
9087
|
+
}
|
|
9088
|
+
deleteFieldIndex(transaction, index) {
|
|
9089
|
+
// Field indices are not supported with memory persistence.
|
|
9090
|
+
return PersistencePromise.resolve();
|
|
9091
|
+
}
|
|
9092
|
+
getDocumentsMatchingTarget(transaction, fieldIndex, target) {
|
|
9093
|
+
// Field indices are not supported with memory persistence.
|
|
9094
|
+
return PersistencePromise.resolve(documentKeySet());
|
|
9095
|
+
}
|
|
9096
|
+
getFieldIndex(transaction, target) {
|
|
9097
|
+
// Field indices are not supported with memory persistence.
|
|
9098
|
+
return PersistencePromise.resolve(null);
|
|
9099
|
+
}
|
|
9100
|
+
getFieldIndexes(transaction, collectionGroup) {
|
|
9101
|
+
// Field indices are not supported with memory persistence.
|
|
9102
|
+
return PersistencePromise.resolve([]);
|
|
9103
|
+
}
|
|
9104
|
+
getNextCollectionGroupToUpdate(transaction) {
|
|
9105
|
+
// Field indices are not supported with memory persistence.
|
|
9106
|
+
return PersistencePromise.resolve(null);
|
|
9107
|
+
}
|
|
9108
|
+
updateCollectionGroup(transaction, collectionGroup, offset) {
|
|
9109
|
+
// Field indices are not supported with memory persistence.
|
|
9110
|
+
return PersistencePromise.resolve();
|
|
9111
|
+
}
|
|
9112
|
+
updateIndexEntries(transaction, documents) {
|
|
9113
|
+
// Field indices are not supported with memory persistence.
|
|
9114
|
+
return PersistencePromise.resolve();
|
|
9115
|
+
}
|
|
8681
9116
|
}
|
|
8682
9117
|
/**
|
|
8683
9118
|
* Internal implementation of the collection-parent index exposed by MemoryIndexManager.
|
|
@@ -8729,17 +9164,22 @@ class MemoryCollectionParentIndex {
|
|
|
8729
9164
|
*/
|
|
8730
9165
|
/**
|
|
8731
9166
|
* A persisted implementation of IndexManager.
|
|
9167
|
+
*
|
|
9168
|
+
* PORTING NOTE: Unlike iOS and Android, the Web SDK does not memoize index
|
|
9169
|
+
* data as it supports multi-tab access.
|
|
8732
9170
|
*/
|
|
8733
9171
|
class IndexedDbIndexManager {
|
|
8734
|
-
constructor() {
|
|
9172
|
+
constructor(user) {
|
|
9173
|
+
this.user = user;
|
|
8735
9174
|
/**
|
|
8736
9175
|
* An in-memory copy of the index entries we've already written since the SDK
|
|
8737
9176
|
* launched. Used to avoid re-writing the same entry repeatedly.
|
|
8738
9177
|
*
|
|
8739
|
-
* This is *NOT* a complete cache of what's in persistence and so can never be
|
|
8740
|
-
* satisfy reads.
|
|
9178
|
+
* This is *NOT* a complete cache of what's in persistence and so can never be
|
|
9179
|
+
* used to satisfy reads.
|
|
8741
9180
|
*/
|
|
8742
9181
|
this.collectionParentsCache = new MemoryCollectionParentIndex();
|
|
9182
|
+
this.uid = user.uid || '';
|
|
8743
9183
|
}
|
|
8744
9184
|
/**
|
|
8745
9185
|
* Adds a new entry to the collection parent index.
|
|
@@ -8786,6 +9226,85 @@ class IndexedDbIndexManager {
|
|
|
8786
9226
|
return parentPaths;
|
|
8787
9227
|
});
|
|
8788
9228
|
}
|
|
9229
|
+
addFieldIndex(transaction, index) {
|
|
9230
|
+
// TODO(indexing): Verify that the auto-incrementing index ID works in
|
|
9231
|
+
// Safari & Firefox.
|
|
9232
|
+
const indexes = indexConfigurationStore(transaction);
|
|
9233
|
+
const dbIndex = toDbIndexConfiguration(index);
|
|
9234
|
+
delete dbIndex.indexId; // `indexId` is auto-populated by IndexedDb
|
|
9235
|
+
return indexes.add(dbIndex).next();
|
|
9236
|
+
}
|
|
9237
|
+
deleteFieldIndex(transaction, index) {
|
|
9238
|
+
const indexes = indexConfigurationStore(transaction);
|
|
9239
|
+
const states = indexStateStore(transaction);
|
|
9240
|
+
const entries = indexEntriesStore(transaction);
|
|
9241
|
+
return indexes
|
|
9242
|
+
.delete(index.indexId)
|
|
9243
|
+
.next(() => states.delete(IDBKeyRange.bound([index.indexId], [index.indexId + 1],
|
|
9244
|
+
/*lowerOpen=*/ false,
|
|
9245
|
+
/*upperOpen=*/ true)))
|
|
9246
|
+
.next(() => entries.delete(IDBKeyRange.bound([index.indexId], [index.indexId + 1],
|
|
9247
|
+
/*lowerOpen=*/ false,
|
|
9248
|
+
/*upperOpen=*/ true)));
|
|
9249
|
+
}
|
|
9250
|
+
getDocumentsMatchingTarget(transaction, fieldIndex, target) {
|
|
9251
|
+
// TODO(indexing): Implement
|
|
9252
|
+
return PersistencePromise.resolve(documentKeySet());
|
|
9253
|
+
}
|
|
9254
|
+
getFieldIndex(transaction, target) {
|
|
9255
|
+
// TODO(indexing): Implement
|
|
9256
|
+
return PersistencePromise.resolve(null);
|
|
9257
|
+
}
|
|
9258
|
+
getFieldIndexes(transaction, collectionGroup) {
|
|
9259
|
+
const indexes = indexConfigurationStore(transaction);
|
|
9260
|
+
const states = indexStateStore(transaction);
|
|
9261
|
+
return (collectionGroup
|
|
9262
|
+
? indexes.loadAll(DbIndexConfiguration.collectionGroupIndex, IDBKeyRange.bound(collectionGroup, collectionGroup))
|
|
9263
|
+
: indexes.loadAll()).next(indexConfigs => {
|
|
9264
|
+
const result = [];
|
|
9265
|
+
return PersistencePromise.forEach(indexConfigs, (indexConfig) => {
|
|
9266
|
+
return states
|
|
9267
|
+
.get([indexConfig.indexId, this.uid])
|
|
9268
|
+
.next(indexState => {
|
|
9269
|
+
result.push(fromDbIndexConfiguration(indexConfig, indexState));
|
|
9270
|
+
});
|
|
9271
|
+
}).next(() => result);
|
|
9272
|
+
});
|
|
9273
|
+
}
|
|
9274
|
+
getNextCollectionGroupToUpdate(transaction) {
|
|
9275
|
+
return this.getFieldIndexes(transaction).next(indexes => {
|
|
9276
|
+
if (indexes.length === 0) {
|
|
9277
|
+
return null;
|
|
9278
|
+
}
|
|
9279
|
+
indexes.sort((l, r) => l.indexState.sequenceNumber - r.indexState.sequenceNumber);
|
|
9280
|
+
return indexes[0].collectionGroup;
|
|
9281
|
+
});
|
|
9282
|
+
}
|
|
9283
|
+
updateCollectionGroup(transaction, collectionGroup, offset) {
|
|
9284
|
+
const indexes = indexConfigurationStore(transaction);
|
|
9285
|
+
const states = indexStateStore(transaction);
|
|
9286
|
+
return this.getNextSequenceNumber(transaction).next(nextSequenceNumber => indexes
|
|
9287
|
+
.loadAll(DbIndexConfiguration.collectionGroupIndex, IDBKeyRange.bound(collectionGroup, collectionGroup))
|
|
9288
|
+
.next(configs => PersistencePromise.forEach(configs, (config) => states.put(toDbIndexState(config.indexId, this.user, nextSequenceNumber, offset)))));
|
|
9289
|
+
}
|
|
9290
|
+
updateIndexEntries(transaction, documents) {
|
|
9291
|
+
// TODO(indexing): Implement
|
|
9292
|
+
return PersistencePromise.resolve();
|
|
9293
|
+
}
|
|
9294
|
+
getNextSequenceNumber(transaction) {
|
|
9295
|
+
let nextSequenceNumber = 1;
|
|
9296
|
+
const states = indexStateStore(transaction);
|
|
9297
|
+
return states
|
|
9298
|
+
.iterate({
|
|
9299
|
+
index: DbIndexState.sequenceNumberIndex,
|
|
9300
|
+
reverse: true,
|
|
9301
|
+
range: IDBKeyRange.upperBound([this.uid, Number.MAX_SAFE_INTEGER])
|
|
9302
|
+
}, (_, state, controller) => {
|
|
9303
|
+
controller.done();
|
|
9304
|
+
nextSequenceNumber = state.sequenceNumber + 1;
|
|
9305
|
+
})
|
|
9306
|
+
.next(() => nextSequenceNumber);
|
|
9307
|
+
}
|
|
8789
9308
|
}
|
|
8790
9309
|
/**
|
|
8791
9310
|
* Helper to get a typed SimpleDbStore for the collectionParents
|
|
@@ -8793,6 +9312,24 @@ class IndexedDbIndexManager {
|
|
|
8793
9312
|
*/
|
|
8794
9313
|
function collectionParentsStore(txn) {
|
|
8795
9314
|
return getStore(txn, DbCollectionParent.store);
|
|
9315
|
+
}
|
|
9316
|
+
/**
|
|
9317
|
+
* Helper to get a typed SimpleDbStore for the index entry object store.
|
|
9318
|
+
*/
|
|
9319
|
+
function indexEntriesStore(txn) {
|
|
9320
|
+
return getStore(txn, DbIndexEntry.store);
|
|
9321
|
+
}
|
|
9322
|
+
/**
|
|
9323
|
+
* Helper to get a typed SimpleDbStore for the index configuration object store.
|
|
9324
|
+
*/
|
|
9325
|
+
function indexConfigurationStore(txn) {
|
|
9326
|
+
return getStore(txn, DbIndexConfiguration.store);
|
|
9327
|
+
}
|
|
9328
|
+
/**
|
|
9329
|
+
* Helper to get a typed SimpleDbStore for the index state object store.
|
|
9330
|
+
*/
|
|
9331
|
+
function indexStateStore(txn) {
|
|
9332
|
+
return getStore(txn, DbIndexState.store);
|
|
8796
9333
|
}
|
|
8797
9334
|
|
|
8798
9335
|
/**
|
|
@@ -10262,12 +10799,10 @@ class RemoteDocumentChangeBuffer {
|
|
|
10262
10799
|
* `newIndexedDbRemoteDocumentCache()`.
|
|
10263
10800
|
*/
|
|
10264
10801
|
class IndexedDbRemoteDocumentCacheImpl {
|
|
10265
|
-
|
|
10266
|
-
* @param serializer - The document serializer.
|
|
10267
|
-
* @param indexManager - The query indexes that need to be maintained.
|
|
10268
|
-
*/
|
|
10269
|
-
constructor(serializer, indexManager) {
|
|
10802
|
+
constructor(serializer) {
|
|
10270
10803
|
this.serializer = serializer;
|
|
10804
|
+
}
|
|
10805
|
+
setIndexManager(indexManager) {
|
|
10271
10806
|
this.indexManager = indexManager;
|
|
10272
10807
|
}
|
|
10273
10808
|
/**
|
|
@@ -10389,21 +10924,21 @@ class IndexedDbRemoteDocumentCacheImpl {
|
|
|
10389
10924
|
}
|
|
10390
10925
|
});
|
|
10391
10926
|
}
|
|
10392
|
-
|
|
10927
|
+
getAll(transaction, collection, sinceReadTime) {
|
|
10393
10928
|
let results = mutableDocumentMap();
|
|
10394
|
-
const immediateChildrenPathLength =
|
|
10929
|
+
const immediateChildrenPathLength = collection.length + 1;
|
|
10395
10930
|
const iterationOptions = {};
|
|
10396
10931
|
if (sinceReadTime.isEqual(SnapshotVersion.min())) {
|
|
10397
10932
|
// Documents are ordered by key, so we can use a prefix scan to narrow
|
|
10398
10933
|
// down the documents we need to match the query against.
|
|
10399
|
-
const startKey =
|
|
10934
|
+
const startKey = collection.toArray();
|
|
10400
10935
|
iterationOptions.range = IDBKeyRange.lowerBound(startKey);
|
|
10401
10936
|
}
|
|
10402
10937
|
else {
|
|
10403
10938
|
// Execute an index-free query and filter by read time. This is safe
|
|
10404
10939
|
// since all document changes to queries that have a
|
|
10405
10940
|
// lastLimboFreeSnapshotVersion (`sinceReadTime`) have a read time set.
|
|
10406
|
-
const collectionKey =
|
|
10941
|
+
const collectionKey = collection.toArray();
|
|
10407
10942
|
const readTimeKey = toDbTimestampKey(sinceReadTime);
|
|
10408
10943
|
iterationOptions.range = IDBKeyRange.lowerBound([collectionKey, readTimeKey],
|
|
10409
10944
|
/* open= */ true);
|
|
@@ -10420,12 +10955,12 @@ class IndexedDbRemoteDocumentCacheImpl {
|
|
|
10420
10955
|
return;
|
|
10421
10956
|
}
|
|
10422
10957
|
const document = this.maybeDecodeDocument(DocumentKey.fromSegments(key), dbRemoteDoc);
|
|
10423
|
-
if (
|
|
10424
|
-
control.done();
|
|
10425
|
-
}
|
|
10426
|
-
else if (queryMatches(query, document)) {
|
|
10958
|
+
if (collection.isPrefixOf(document.key.path)) {
|
|
10427
10959
|
results = results.insert(document.key, document);
|
|
10428
10960
|
}
|
|
10961
|
+
else {
|
|
10962
|
+
control.done();
|
|
10963
|
+
}
|
|
10429
10964
|
})
|
|
10430
10965
|
.next(() => results);
|
|
10431
10966
|
}
|
|
@@ -10463,14 +10998,9 @@ class IndexedDbRemoteDocumentCacheImpl {
|
|
|
10463
10998
|
return MutableDocument.newInvalidDocument(documentKey);
|
|
10464
10999
|
}
|
|
10465
11000
|
}
|
|
10466
|
-
/**
|
|
10467
|
-
|
|
10468
|
-
|
|
10469
|
-
* @param serializer - The document serializer.
|
|
10470
|
-
* @param indexManager - The query indexes that need to be maintained.
|
|
10471
|
-
*/
|
|
10472
|
-
function newIndexedDbRemoteDocumentCache(serializer, indexManager) {
|
|
10473
|
-
return new IndexedDbRemoteDocumentCacheImpl(serializer, indexManager);
|
|
11001
|
+
/** Creates a new IndexedDbRemoteDocumentCache. */
|
|
11002
|
+
function newIndexedDbRemoteDocumentCache(serializer) {
|
|
11003
|
+
return new IndexedDbRemoteDocumentCacheImpl(serializer);
|
|
10474
11004
|
}
|
|
10475
11005
|
/**
|
|
10476
11006
|
* Returns the set of documents that have changed since the specified read
|
|
@@ -10637,9 +11167,6 @@ class SchemaConverter {
|
|
|
10637
11167
|
* and local feature development.
|
|
10638
11168
|
*/
|
|
10639
11169
|
createOrUpgrade(db, txn, fromVersion, toVersion) {
|
|
10640
|
-
hardAssert(fromVersion < toVersion &&
|
|
10641
|
-
fromVersion >= 0 &&
|
|
10642
|
-
toVersion <= SCHEMA_VERSION);
|
|
10643
11170
|
const simpleDbTransaction = new SimpleDbTransaction('createOrUpgrade', txn);
|
|
10644
11171
|
if (fromVersion < 1 && toVersion >= 1) {
|
|
10645
11172
|
createPrimaryClientStore(db);
|
|
@@ -10706,6 +11233,16 @@ class SchemaConverter {
|
|
|
10706
11233
|
createNamedQueriesStore(db);
|
|
10707
11234
|
});
|
|
10708
11235
|
}
|
|
11236
|
+
if (fromVersion < 12 && toVersion >= 12) {
|
|
11237
|
+
p = p.next(() => {
|
|
11238
|
+
createDocumentOverlayStore(db);
|
|
11239
|
+
});
|
|
11240
|
+
}
|
|
11241
|
+
if (fromVersion < 13 && toVersion >= 13) {
|
|
11242
|
+
p = p.next(() => {
|
|
11243
|
+
createFieldIndex(db);
|
|
11244
|
+
});
|
|
11245
|
+
}
|
|
10709
11246
|
return p;
|
|
10710
11247
|
}
|
|
10711
11248
|
addDocumentGlobal(txn) {
|
|
@@ -10912,6 +11449,27 @@ function createNamedQueriesStore(db) {
|
|
|
10912
11449
|
db.createObjectStore(DbNamedQuery.store, {
|
|
10913
11450
|
keyPath: DbNamedQuery.keyPath
|
|
10914
11451
|
});
|
|
11452
|
+
}
|
|
11453
|
+
function createFieldIndex(db) {
|
|
11454
|
+
const indexConfiguratioStore = db.createObjectStore(DbIndexConfiguration.store, {
|
|
11455
|
+
keyPath: DbIndexConfiguration.keyPath,
|
|
11456
|
+
autoIncrement: true
|
|
11457
|
+
});
|
|
11458
|
+
indexConfiguratioStore.createIndex(DbIndexConfiguration.collectionGroupIndex, DbIndexConfiguration.collectionGroupIndexPath, { unique: false });
|
|
11459
|
+
const indexStateStore = db.createObjectStore(DbIndexState.store, {
|
|
11460
|
+
keyPath: DbIndexState.keyPath
|
|
11461
|
+
});
|
|
11462
|
+
indexStateStore.createIndex(DbIndexState.sequenceNumberIndex, DbIndexState.sequenceNumberIndexPath, { unique: false });
|
|
11463
|
+
db.createObjectStore(DbIndexEntry.store, {
|
|
11464
|
+
keyPath: DbIndexEntry.keyPath
|
|
11465
|
+
});
|
|
11466
|
+
}
|
|
11467
|
+
function createDocumentOverlayStore(db) {
|
|
11468
|
+
const documentOverlayStore = db.createObjectStore(DbDocumentOverlay.store, {
|
|
11469
|
+
keyPath: DbDocumentOverlay.keyPath
|
|
11470
|
+
});
|
|
11471
|
+
documentOverlayStore.createIndex(DbDocumentOverlay.collectionPathOverlayIndex, DbDocumentOverlay.collectionPathOverlayIndexPath, { unique: false });
|
|
11472
|
+
documentOverlayStore.createIndex(DbDocumentOverlay.collectionGroupOverlayIndex, DbDocumentOverlay.collectionGroupOverlayIndexPath, { unique: false });
|
|
10915
11473
|
}
|
|
10916
11474
|
|
|
10917
11475
|
/**
|
|
@@ -11023,7 +11581,7 @@ class IndexedDbPersistence {
|
|
|
11023
11581
|
* If set to true, forcefully obtains database access. Existing tabs will
|
|
11024
11582
|
* no longer be able to access IndexedDB.
|
|
11025
11583
|
*/
|
|
11026
|
-
forceOwningTab) {
|
|
11584
|
+
forceOwningTab, schemaVersion = SCHEMA_VERSION) {
|
|
11027
11585
|
this.allowTabSynchronization = allowTabSynchronization;
|
|
11028
11586
|
this.persistenceKey = persistenceKey;
|
|
11029
11587
|
this.clientId = clientId;
|
|
@@ -11032,6 +11590,7 @@ class IndexedDbPersistence {
|
|
|
11032
11590
|
this.document = document;
|
|
11033
11591
|
this.sequenceNumberSyncer = sequenceNumberSyncer;
|
|
11034
11592
|
this.forceOwningTab = forceOwningTab;
|
|
11593
|
+
this.schemaVersion = schemaVersion;
|
|
11035
11594
|
this.listenSequence = null;
|
|
11036
11595
|
this._started = false;
|
|
11037
11596
|
this.isPrimary = false;
|
|
@@ -11053,10 +11612,9 @@ class IndexedDbPersistence {
|
|
|
11053
11612
|
this.referenceDelegate = new IndexedDbLruDelegateImpl(this, lruParams);
|
|
11054
11613
|
this.dbName = persistenceKey + MAIN_DATABASE;
|
|
11055
11614
|
this.serializer = new LocalSerializer(serializer);
|
|
11056
|
-
this.simpleDb = new SimpleDb(this.dbName,
|
|
11615
|
+
this.simpleDb = new SimpleDb(this.dbName, this.schemaVersion, new SchemaConverter(this.serializer));
|
|
11057
11616
|
this.targetCache = new IndexedDbTargetCache(this.referenceDelegate, this.serializer);
|
|
11058
|
-
this.
|
|
11059
|
-
this.remoteDocumentCache = newIndexedDbRemoteDocumentCache(this.serializer, this.indexManager);
|
|
11617
|
+
this.remoteDocumentCache = newIndexedDbRemoteDocumentCache(this.serializer);
|
|
11060
11618
|
this.bundleCache = new IndexedDbBundleCache();
|
|
11061
11619
|
if (this.window && this.window.localStorage) {
|
|
11062
11620
|
this.webStorage = this.window.localStorage;
|
|
@@ -11392,8 +11950,8 @@ class IndexedDbPersistence {
|
|
|
11392
11950
|
get started() {
|
|
11393
11951
|
return this._started;
|
|
11394
11952
|
}
|
|
11395
|
-
getMutationQueue(user) {
|
|
11396
|
-
return IndexedDbMutationQueue.forUser(user, this.serializer,
|
|
11953
|
+
getMutationQueue(user, indexManager) {
|
|
11954
|
+
return IndexedDbMutationQueue.forUser(user, this.serializer, indexManager, this.referenceDelegate);
|
|
11397
11955
|
}
|
|
11398
11956
|
getTargetCache() {
|
|
11399
11957
|
return this.targetCache;
|
|
@@ -11401,8 +11959,11 @@ class IndexedDbPersistence {
|
|
|
11401
11959
|
getRemoteDocumentCache() {
|
|
11402
11960
|
return this.remoteDocumentCache;
|
|
11403
11961
|
}
|
|
11404
|
-
getIndexManager() {
|
|
11405
|
-
return
|
|
11962
|
+
getIndexManager(user) {
|
|
11963
|
+
return new IndexedDbIndexManager(user);
|
|
11964
|
+
}
|
|
11965
|
+
getDocumentOverlayCache(user) {
|
|
11966
|
+
return IndexedDbDocumentOverlayCache.forUser(this.serializer, user);
|
|
11406
11967
|
}
|
|
11407
11968
|
getBundleCache() {
|
|
11408
11969
|
return this.bundleCache;
|
|
@@ -11410,11 +11971,12 @@ class IndexedDbPersistence {
|
|
|
11410
11971
|
runTransaction(action, mode, transactionOperation) {
|
|
11411
11972
|
logDebug(LOG_TAG$d, 'Starting transaction:', action);
|
|
11412
11973
|
const simpleDbMode = mode === 'readonly' ? 'readonly' : 'readwrite';
|
|
11974
|
+
const objectStores = getObjectStores(this.schemaVersion);
|
|
11413
11975
|
let persistenceTransaction;
|
|
11414
11976
|
// Do all transactions as readwrite against all object stores, since we
|
|
11415
11977
|
// are the only reader/writer.
|
|
11416
11978
|
return this.simpleDb
|
|
11417
|
-
.runTransaction(action, simpleDbMode,
|
|
11979
|
+
.runTransaction(action, simpleDbMode, objectStores, simpleDbTxn => {
|
|
11418
11980
|
persistenceTransaction = new IndexedDbTransaction(simpleDbTxn, this.listenSequence
|
|
11419
11981
|
? this.listenSequence.next()
|
|
11420
11982
|
: ListenSequence.INVALID);
|
|
@@ -11786,39 +12348,28 @@ class LocalDocumentsView {
|
|
|
11786
12348
|
getDocumentsMatchingCollectionQuery(transaction, query, sinceReadTime) {
|
|
11787
12349
|
// Query the remote documents and overlay mutations.
|
|
11788
12350
|
let results;
|
|
11789
|
-
let mutationBatches;
|
|
11790
12351
|
return this.remoteDocumentCache
|
|
11791
|
-
.
|
|
12352
|
+
.getAll(transaction, query.path, sinceReadTime)
|
|
11792
12353
|
.next(queryResults => {
|
|
11793
12354
|
results = queryResults;
|
|
11794
12355
|
return this.mutationQueue.getAllMutationBatchesAffectingQuery(transaction, query);
|
|
11795
12356
|
})
|
|
11796
|
-
.next(
|
|
11797
|
-
mutationBatches
|
|
11798
|
-
|
|
11799
|
-
|
|
11800
|
-
|
|
11801
|
-
|
|
11802
|
-
|
|
11803
|
-
|
|
11804
|
-
|
|
11805
|
-
|
|
11806
|
-
|
|
11807
|
-
|
|
11808
|
-
|
|
11809
|
-
let document = results.get(key);
|
|
11810
|
-
if (document == null) {
|
|
11811
|
-
// Create invalid document to apply mutations on top of
|
|
11812
|
-
document = MutableDocument.newInvalidDocument(key);
|
|
11813
|
-
results = results.insert(key, document);
|
|
11814
|
-
}
|
|
11815
|
-
mutationApplyToLocalView(mutation, document, batch.localWriteTime);
|
|
11816
|
-
if (!document.isFoundDocument()) {
|
|
11817
|
-
results = results.remove(key);
|
|
11818
|
-
}
|
|
12357
|
+
.next(mutationBatches => {
|
|
12358
|
+
for (const batch of mutationBatches) {
|
|
12359
|
+
for (const mutation of batch.mutations) {
|
|
12360
|
+
const key = mutation.key;
|
|
12361
|
+
let document = results.get(key);
|
|
12362
|
+
if (document == null) {
|
|
12363
|
+
// Create invalid document to apply mutations on top of
|
|
12364
|
+
document = MutableDocument.newInvalidDocument(key);
|
|
12365
|
+
results = results.insert(key, document);
|
|
12366
|
+
}
|
|
12367
|
+
mutationApplyToLocalView(mutation, document, batch.localWriteTime);
|
|
12368
|
+
if (!document.isFoundDocument()) {
|
|
12369
|
+
results = results.remove(key);
|
|
11819
12370
|
}
|
|
11820
12371
|
}
|
|
11821
|
-
}
|
|
12372
|
+
}
|
|
11822
12373
|
})
|
|
11823
12374
|
.next(() => {
|
|
11824
12375
|
// Finally, filter out any documents that don't actually match
|
|
@@ -11831,29 +12382,6 @@ class LocalDocumentsView {
|
|
|
11831
12382
|
return results;
|
|
11832
12383
|
});
|
|
11833
12384
|
}
|
|
11834
|
-
addMissingBaseDocuments(transaction, matchingMutationBatches, existingDocuments) {
|
|
11835
|
-
let missingBaseDocEntriesForPatching = documentKeySet();
|
|
11836
|
-
for (const batch of matchingMutationBatches) {
|
|
11837
|
-
for (const mutation of batch.mutations) {
|
|
11838
|
-
if (mutation instanceof PatchMutation &&
|
|
11839
|
-
existingDocuments.get(mutation.key) === null) {
|
|
11840
|
-
missingBaseDocEntriesForPatching =
|
|
11841
|
-
missingBaseDocEntriesForPatching.add(mutation.key);
|
|
11842
|
-
}
|
|
11843
|
-
}
|
|
11844
|
-
}
|
|
11845
|
-
let mergedDocuments = existingDocuments;
|
|
11846
|
-
return this.remoteDocumentCache
|
|
11847
|
-
.getEntries(transaction, missingBaseDocEntriesForPatching)
|
|
11848
|
-
.next(missingBaseDocs => {
|
|
11849
|
-
missingBaseDocs.forEach((key, doc) => {
|
|
11850
|
-
if (doc.isFoundDocument()) {
|
|
11851
|
-
mergedDocuments = mergedDocuments.insert(key, doc);
|
|
11852
|
-
}
|
|
11853
|
-
});
|
|
11854
|
-
return mergedDocuments;
|
|
11855
|
-
});
|
|
11856
|
-
}
|
|
11857
12385
|
}
|
|
11858
12386
|
|
|
11859
12387
|
/**
|
|
@@ -11912,11 +12440,18 @@ class LocalStoreImpl {
|
|
|
11912
12440
|
* PORTING NOTE: This is only used for multi-tab synchronization.
|
|
11913
12441
|
*/
|
|
11914
12442
|
this.lastDocumentChangeReadTime = SnapshotVersion.min();
|
|
11915
|
-
this.mutationQueue = persistence.getMutationQueue(initialUser);
|
|
11916
12443
|
this.remoteDocuments = persistence.getRemoteDocumentCache();
|
|
11917
12444
|
this.targetCache = persistence.getTargetCache();
|
|
11918
|
-
this.localDocuments = new LocalDocumentsView(this.remoteDocuments, this.mutationQueue, this.persistence.getIndexManager());
|
|
11919
12445
|
this.bundleCache = persistence.getBundleCache();
|
|
12446
|
+
this.initializeUserComponents(initialUser);
|
|
12447
|
+
}
|
|
12448
|
+
initializeUserComponents(user) {
|
|
12449
|
+
// TODO(indexing): Add spec tests that test these components change after a
|
|
12450
|
+
// user change
|
|
12451
|
+
this.indexManager = this.persistence.getIndexManager(user);
|
|
12452
|
+
this.mutationQueue = this.persistence.getMutationQueue(user, this.indexManager);
|
|
12453
|
+
this.localDocuments = new LocalDocumentsView(this.remoteDocuments, this.mutationQueue, this.indexManager);
|
|
12454
|
+
this.remoteDocuments.setIndexManager(this.indexManager);
|
|
11920
12455
|
this.queryEngine.setLocalDocumentsView(this.localDocuments);
|
|
11921
12456
|
}
|
|
11922
12457
|
collectGarbage(garbageCollector) {
|
|
@@ -11938,8 +12473,6 @@ persistence, queryEngine, initialUser, serializer) {
|
|
|
11938
12473
|
// change.
|
|
11939
12474
|
async function localStoreHandleUserChange(localStore, user) {
|
|
11940
12475
|
const localStoreImpl = debugCast(localStore);
|
|
11941
|
-
let newMutationQueue = localStoreImpl.mutationQueue;
|
|
11942
|
-
let newLocalDocuments = localStoreImpl.localDocuments;
|
|
11943
12476
|
const result = await localStoreImpl.persistence.runTransaction('Handle user change', 'readonly', txn => {
|
|
11944
12477
|
// Swap out the mutation queue, grabbing the pending mutation batches
|
|
11945
12478
|
// before and after.
|
|
@@ -11948,11 +12481,8 @@ async function localStoreHandleUserChange(localStore, user) {
|
|
|
11948
12481
|
.getAllMutationBatches(txn)
|
|
11949
12482
|
.next(promisedOldBatches => {
|
|
11950
12483
|
oldBatches = promisedOldBatches;
|
|
11951
|
-
|
|
11952
|
-
|
|
11953
|
-
// MutationQueue.
|
|
11954
|
-
newLocalDocuments = new LocalDocumentsView(localStoreImpl.remoteDocuments, newMutationQueue, localStoreImpl.persistence.getIndexManager());
|
|
11955
|
-
return newMutationQueue.getAllMutationBatches(txn);
|
|
12484
|
+
localStoreImpl.initializeUserComponents(user);
|
|
12485
|
+
return localStoreImpl.mutationQueue.getAllMutationBatches(txn);
|
|
11956
12486
|
})
|
|
11957
12487
|
.next(newBatches => {
|
|
11958
12488
|
const removedBatchIds = [];
|
|
@@ -11973,7 +12503,7 @@ async function localStoreHandleUserChange(localStore, user) {
|
|
|
11973
12503
|
}
|
|
11974
12504
|
// Return the set of all (potentially) changed documents and the list
|
|
11975
12505
|
// of mutation batch IDs that were affected by change.
|
|
11976
|
-
return
|
|
12506
|
+
return localStoreImpl.localDocuments
|
|
11977
12507
|
.getDocuments(txn, changedKeys)
|
|
11978
12508
|
.next(affectedDocuments => {
|
|
11979
12509
|
return {
|
|
@@ -11984,9 +12514,6 @@ async function localStoreHandleUserChange(localStore, user) {
|
|
|
11984
12514
|
});
|
|
11985
12515
|
});
|
|
11986
12516
|
});
|
|
11987
|
-
localStoreImpl.mutationQueue = newMutationQueue;
|
|
11988
|
-
localStoreImpl.localDocuments = newLocalDocuments;
|
|
11989
|
-
localStoreImpl.queryEngine.setLocalDocumentsView(localStoreImpl.localDocuments);
|
|
11990
12517
|
return result;
|
|
11991
12518
|
}
|
|
11992
12519
|
/* Accepts locally generated Mutations and commit them to storage. */
|
|
@@ -12699,6 +13226,122 @@ class MemoryBundleCache {
|
|
|
12699
13226
|
}
|
|
12700
13227
|
}
|
|
12701
13228
|
|
|
13229
|
+
/**
|
|
13230
|
+
* @license
|
|
13231
|
+
* Copyright 2022 Google LLC
|
|
13232
|
+
*
|
|
13233
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
13234
|
+
* you may not use this file except in compliance with the License.
|
|
13235
|
+
* You may obtain a copy of the License at
|
|
13236
|
+
*
|
|
13237
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
13238
|
+
*
|
|
13239
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13240
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13241
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13242
|
+
* See the License for the specific language governing permissions and
|
|
13243
|
+
* limitations under the License.
|
|
13244
|
+
*/
|
|
13245
|
+
/**
|
|
13246
|
+
* An in-memory implementation of DocumentOverlayCache.
|
|
13247
|
+
*/
|
|
13248
|
+
class MemoryDocumentOverlayCache {
|
|
13249
|
+
constructor() {
|
|
13250
|
+
// A map sorted by DocumentKey, whose value is a pair of the largest batch id
|
|
13251
|
+
// for the overlay and the overlay itself.
|
|
13252
|
+
this.overlays = new SortedMap(DocumentKey.comparator);
|
|
13253
|
+
this.overlayByBatchId = new Map();
|
|
13254
|
+
}
|
|
13255
|
+
getOverlay(transaction, key) {
|
|
13256
|
+
return PersistencePromise.resolve(this.overlays.get(key));
|
|
13257
|
+
}
|
|
13258
|
+
saveOverlays(transaction, largestBatchId, overlays) {
|
|
13259
|
+
overlays.forEach(mutation => {
|
|
13260
|
+
this.saveOverlay(transaction, largestBatchId, mutation);
|
|
13261
|
+
});
|
|
13262
|
+
return PersistencePromise.resolve();
|
|
13263
|
+
}
|
|
13264
|
+
removeOverlaysForBatchId(transaction, documentKeys, batchId) {
|
|
13265
|
+
const keys = this.overlayByBatchId.get(batchId);
|
|
13266
|
+
if (keys !== undefined) {
|
|
13267
|
+
keys.forEach(key => (this.overlays = this.overlays.remove(key)));
|
|
13268
|
+
this.overlayByBatchId.delete(batchId);
|
|
13269
|
+
}
|
|
13270
|
+
return PersistencePromise.resolve();
|
|
13271
|
+
}
|
|
13272
|
+
getOverlaysForCollection(transaction, collection, sinceBatchId) {
|
|
13273
|
+
const result = new Map();
|
|
13274
|
+
const immediateChildrenPathLength = collection.length + 1;
|
|
13275
|
+
const prefix = new DocumentKey(collection.child(''));
|
|
13276
|
+
const iter = this.overlays.getIteratorFrom(prefix);
|
|
13277
|
+
while (iter.hasNext()) {
|
|
13278
|
+
const entry = iter.getNext();
|
|
13279
|
+
const overlay = entry.value;
|
|
13280
|
+
const key = overlay.getKey();
|
|
13281
|
+
if (!collection.isPrefixOf(key.path)) {
|
|
13282
|
+
break;
|
|
13283
|
+
}
|
|
13284
|
+
// Documents from sub-collections
|
|
13285
|
+
if (key.path.length !== immediateChildrenPathLength) {
|
|
13286
|
+
continue;
|
|
13287
|
+
}
|
|
13288
|
+
if (overlay.largestBatchId > sinceBatchId) {
|
|
13289
|
+
result.set(overlay.getKey(), overlay);
|
|
13290
|
+
}
|
|
13291
|
+
}
|
|
13292
|
+
return PersistencePromise.resolve(result);
|
|
13293
|
+
}
|
|
13294
|
+
getOverlaysForCollectionGroup(transaction, collectionGroup, sinceBatchId, count) {
|
|
13295
|
+
let batchIdToOverlays = new SortedMap((key1, key2) => key1 - key2);
|
|
13296
|
+
const iter = this.overlays.getIterator();
|
|
13297
|
+
while (iter.hasNext()) {
|
|
13298
|
+
const entry = iter.getNext();
|
|
13299
|
+
const overlay = entry.value;
|
|
13300
|
+
const key = overlay.getKey();
|
|
13301
|
+
if (key.getCollectionGroup() !== collectionGroup) {
|
|
13302
|
+
continue;
|
|
13303
|
+
}
|
|
13304
|
+
if (overlay.largestBatchId > sinceBatchId) {
|
|
13305
|
+
let overlaysForBatchId = batchIdToOverlays.get(overlay.largestBatchId);
|
|
13306
|
+
if (overlaysForBatchId === null) {
|
|
13307
|
+
overlaysForBatchId = new Map();
|
|
13308
|
+
batchIdToOverlays = batchIdToOverlays.insert(overlay.largestBatchId, overlaysForBatchId);
|
|
13309
|
+
}
|
|
13310
|
+
overlaysForBatchId.set(overlay.getKey(), overlay);
|
|
13311
|
+
}
|
|
13312
|
+
}
|
|
13313
|
+
const result = new Map();
|
|
13314
|
+
const batchIter = batchIdToOverlays.getIterator();
|
|
13315
|
+
while (batchIter.hasNext()) {
|
|
13316
|
+
const entry = batchIter.getNext();
|
|
13317
|
+
const overlays = entry.value;
|
|
13318
|
+
overlays.forEach((overlay, key) => result.set(key, overlay));
|
|
13319
|
+
if (result.size >= count) {
|
|
13320
|
+
break;
|
|
13321
|
+
}
|
|
13322
|
+
}
|
|
13323
|
+
return PersistencePromise.resolve(result);
|
|
13324
|
+
}
|
|
13325
|
+
saveOverlay(transaction, largestBatchId, mutation) {
|
|
13326
|
+
if (mutation === null) {
|
|
13327
|
+
return;
|
|
13328
|
+
}
|
|
13329
|
+
// Remove the association of the overlay to its batch id.
|
|
13330
|
+
const existing = this.overlays.get(mutation.key);
|
|
13331
|
+
if (existing !== null) {
|
|
13332
|
+
this.overlayByBatchId.get(existing.largestBatchId).delete(mutation.key);
|
|
13333
|
+
}
|
|
13334
|
+
this.overlays = this.overlays.insert(mutation.key, new Overlay(largestBatchId, mutation));
|
|
13335
|
+
// Create the association of this overlay to the given largestBatchId.
|
|
13336
|
+
let batch = this.overlayByBatchId.get(largestBatchId);
|
|
13337
|
+
if (batch === undefined) {
|
|
13338
|
+
batch = new Set();
|
|
13339
|
+
this.overlayByBatchId.set(largestBatchId, batch);
|
|
13340
|
+
}
|
|
13341
|
+
batch.add(mutation.key);
|
|
13342
|
+
}
|
|
13343
|
+
}
|
|
13344
|
+
|
|
12702
13345
|
/**
|
|
12703
13346
|
* @license
|
|
12704
13347
|
* Copyright 2017 Google LLC
|
|
@@ -13052,14 +13695,16 @@ class MemoryRemoteDocumentCacheImpl {
|
|
|
13052
13695
|
* expected to just return 0 to avoid unnecessarily doing the work of
|
|
13053
13696
|
* calculating the size.
|
|
13054
13697
|
*/
|
|
13055
|
-
constructor(
|
|
13056
|
-
this.indexManager = indexManager;
|
|
13698
|
+
constructor(sizer) {
|
|
13057
13699
|
this.sizer = sizer;
|
|
13058
13700
|
/** Underlying cache of documents and their read times. */
|
|
13059
13701
|
this.docs = documentEntryMap();
|
|
13060
13702
|
/** Size of all cached documents. */
|
|
13061
13703
|
this.size = 0;
|
|
13062
13704
|
}
|
|
13705
|
+
setIndexManager(indexManager) {
|
|
13706
|
+
this.indexManager = indexManager;
|
|
13707
|
+
}
|
|
13063
13708
|
/**
|
|
13064
13709
|
* Adds the supplied entry to the cache and updates the cache size as appropriate.
|
|
13065
13710
|
*
|
|
@@ -13107,21 +13752,22 @@ class MemoryRemoteDocumentCacheImpl {
|
|
|
13107
13752
|
});
|
|
13108
13753
|
return PersistencePromise.resolve(results);
|
|
13109
13754
|
}
|
|
13110
|
-
|
|
13755
|
+
getAll(transaction, collectionPath, sinceReadTime) {
|
|
13111
13756
|
let results = mutableDocumentMap();
|
|
13112
13757
|
// Documents are ordered by key, so we can use a prefix scan to narrow down
|
|
13113
13758
|
// the documents we need to match the query against.
|
|
13114
|
-
const prefix = new DocumentKey(
|
|
13759
|
+
const prefix = new DocumentKey(collectionPath.child(''));
|
|
13115
13760
|
const iterator = this.docs.getIteratorFrom(prefix);
|
|
13116
13761
|
while (iterator.hasNext()) {
|
|
13117
13762
|
const { key, value: { document } } = iterator.getNext();
|
|
13118
|
-
if (!
|
|
13763
|
+
if (!collectionPath.isPrefixOf(key.path)) {
|
|
13119
13764
|
break;
|
|
13120
13765
|
}
|
|
13121
|
-
if (
|
|
13766
|
+
if (key.path.length > collectionPath.length + 1) {
|
|
13767
|
+
// Exclude entries from subcollections.
|
|
13122
13768
|
continue;
|
|
13123
13769
|
}
|
|
13124
|
-
if (
|
|
13770
|
+
if (document.readTime.compareTo(sinceReadTime) <= 0) {
|
|
13125
13771
|
continue;
|
|
13126
13772
|
}
|
|
13127
13773
|
results = results.insert(document.key, document.mutableCopy());
|
|
@@ -13143,13 +13789,12 @@ class MemoryRemoteDocumentCacheImpl {
|
|
|
13143
13789
|
/**
|
|
13144
13790
|
* Creates a new memory-only RemoteDocumentCache.
|
|
13145
13791
|
*
|
|
13146
|
-
* @param indexManager - A class that manages collection group indices.
|
|
13147
13792
|
* @param sizer - Used to assess the size of a document. For eager GC, this is
|
|
13148
13793
|
* expected to just return 0 to avoid unnecessarily doing the work of
|
|
13149
13794
|
* calculating the size.
|
|
13150
13795
|
*/
|
|
13151
|
-
function newMemoryRemoteDocumentCache(
|
|
13152
|
-
return new MemoryRemoteDocumentCacheImpl(
|
|
13796
|
+
function newMemoryRemoteDocumentCache(sizer) {
|
|
13797
|
+
return new MemoryRemoteDocumentCacheImpl(sizer);
|
|
13153
13798
|
}
|
|
13154
13799
|
/**
|
|
13155
13800
|
* Handles the details of adding and updating documents in the MemoryRemoteDocumentCache.
|
|
@@ -13343,6 +13988,7 @@ class MemoryPersistence {
|
|
|
13343
13988
|
*/
|
|
13344
13989
|
constructor(referenceDelegateFactory, serializer) {
|
|
13345
13990
|
this.mutationQueues = {};
|
|
13991
|
+
this.overlays = {};
|
|
13346
13992
|
this.listenSequence = new ListenSequence(0);
|
|
13347
13993
|
this._started = false;
|
|
13348
13994
|
this._started = true;
|
|
@@ -13350,7 +13996,7 @@ class MemoryPersistence {
|
|
|
13350
13996
|
this.targetCache = new MemoryTargetCache(this);
|
|
13351
13997
|
const sizer = (doc) => this.referenceDelegate.documentSize(doc);
|
|
13352
13998
|
this.indexManager = new MemoryIndexManager();
|
|
13353
|
-
this.remoteDocumentCache = newMemoryRemoteDocumentCache(
|
|
13999
|
+
this.remoteDocumentCache = newMemoryRemoteDocumentCache(sizer);
|
|
13354
14000
|
this.serializer = new LocalSerializer(serializer);
|
|
13355
14001
|
this.bundleCache = new MemoryBundleCache(this.serializer);
|
|
13356
14002
|
}
|
|
@@ -13371,13 +14017,23 @@ class MemoryPersistence {
|
|
|
13371
14017
|
setNetworkEnabled() {
|
|
13372
14018
|
// No op.
|
|
13373
14019
|
}
|
|
13374
|
-
getIndexManager() {
|
|
14020
|
+
getIndexManager(user) {
|
|
14021
|
+
// We do not currently support indices for memory persistence, so we can
|
|
14022
|
+
// return the same shared instance of the memory index manager.
|
|
13375
14023
|
return this.indexManager;
|
|
13376
14024
|
}
|
|
13377
|
-
|
|
14025
|
+
getDocumentOverlayCache(user) {
|
|
14026
|
+
let overlay = this.overlays[user.toKey()];
|
|
14027
|
+
if (!overlay) {
|
|
14028
|
+
overlay = new MemoryDocumentOverlayCache();
|
|
14029
|
+
this.overlays[user.toKey()] = overlay;
|
|
14030
|
+
}
|
|
14031
|
+
return overlay;
|
|
14032
|
+
}
|
|
14033
|
+
getMutationQueue(user, indexManager) {
|
|
13378
14034
|
let queue = this.mutationQueues[user.toKey()];
|
|
13379
14035
|
if (!queue) {
|
|
13380
|
-
queue = new MemoryMutationQueue(
|
|
14036
|
+
queue = new MemoryMutationQueue(indexManager, this.referenceDelegate);
|
|
13381
14037
|
this.mutationQueues[user.toKey()] = queue;
|
|
13382
14038
|
}
|
|
13383
14039
|
return queue;
|
|
@@ -20340,12 +20996,12 @@ async function syncEngineListen(syncEngine, query) {
|
|
|
20340
20996
|
}
|
|
20341
20997
|
else {
|
|
20342
20998
|
const targetData = await localStoreAllocateTarget(syncEngineImpl.localStore, queryToTarget(query));
|
|
20343
|
-
const status = syncEngineImpl.sharedClientState.addLocalQueryTarget(targetData.targetId);
|
|
20344
|
-
targetId = targetData.targetId;
|
|
20345
|
-
viewSnapshot = await initializeViewAndComputeSnapshot(syncEngineImpl, query, targetId, status === 'current');
|
|
20346
20999
|
if (syncEngineImpl.isPrimaryClient) {
|
|
20347
21000
|
remoteStoreListen(syncEngineImpl.remoteStore, targetData);
|
|
20348
21001
|
}
|
|
21002
|
+
const status = syncEngineImpl.sharedClientState.addLocalQueryTarget(targetData.targetId);
|
|
21003
|
+
targetId = targetData.targetId;
|
|
21004
|
+
viewSnapshot = await initializeViewAndComputeSnapshot(syncEngineImpl, query, targetId, status === 'current');
|
|
20349
21005
|
}
|
|
20350
21006
|
return viewSnapshot;
|
|
20351
21007
|
}
|
|
@@ -24853,8 +25509,7 @@ class DocumentSnapshot extends DocumentSnapshot$1 {
|
|
|
24853
25509
|
this.metadata = metadata;
|
|
24854
25510
|
}
|
|
24855
25511
|
/**
|
|
24856
|
-
*
|
|
24857
|
-
* exists. True if the document exists.
|
|
25512
|
+
* Returns whether or not the data exists. True if the document exists.
|
|
24858
25513
|
*/
|
|
24859
25514
|
exists() {
|
|
24860
25515
|
return super.exists();
|
|
@@ -25228,51 +25883,53 @@ function limitToLast(limit) {
|
|
|
25228
25883
|
return new QueryLimitConstraint('limitToLast', limit, "L" /* Last */);
|
|
25229
25884
|
}
|
|
25230
25885
|
class QueryStartAtConstraint extends QueryConstraint {
|
|
25231
|
-
constructor(type, _docOrFields,
|
|
25886
|
+
constructor(type, _docOrFields, _inclusive) {
|
|
25232
25887
|
super();
|
|
25233
25888
|
this.type = type;
|
|
25234
25889
|
this._docOrFields = _docOrFields;
|
|
25235
|
-
this.
|
|
25890
|
+
this._inclusive = _inclusive;
|
|
25236
25891
|
}
|
|
25237
25892
|
_apply(query) {
|
|
25238
|
-
const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this.
|
|
25893
|
+
const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
|
|
25239
25894
|
return new Query(query.firestore, query.converter, queryWithStartAt(query._query, bound));
|
|
25240
25895
|
}
|
|
25241
25896
|
}
|
|
25242
25897
|
function startAt(...docOrFields) {
|
|
25243
|
-
return new QueryStartAtConstraint('startAt', docOrFields,
|
|
25898
|
+
return new QueryStartAtConstraint('startAt', docOrFields,
|
|
25899
|
+
/*inclusive=*/ true);
|
|
25244
25900
|
}
|
|
25245
25901
|
function startAfter(...docOrFields) {
|
|
25246
25902
|
return new QueryStartAtConstraint('startAfter', docOrFields,
|
|
25247
|
-
/*
|
|
25903
|
+
/*inclusive=*/ false);
|
|
25248
25904
|
}
|
|
25249
25905
|
class QueryEndAtConstraint extends QueryConstraint {
|
|
25250
|
-
constructor(type, _docOrFields,
|
|
25906
|
+
constructor(type, _docOrFields, _inclusive) {
|
|
25251
25907
|
super();
|
|
25252
25908
|
this.type = type;
|
|
25253
25909
|
this._docOrFields = _docOrFields;
|
|
25254
|
-
this.
|
|
25910
|
+
this._inclusive = _inclusive;
|
|
25255
25911
|
}
|
|
25256
25912
|
_apply(query) {
|
|
25257
|
-
const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this.
|
|
25913
|
+
const bound = newQueryBoundFromDocOrFields(query, this.type, this._docOrFields, this._inclusive);
|
|
25258
25914
|
return new Query(query.firestore, query.converter, queryWithEndAt(query._query, bound));
|
|
25259
25915
|
}
|
|
25260
25916
|
}
|
|
25261
25917
|
function endBefore(...docOrFields) {
|
|
25262
|
-
return new QueryEndAtConstraint('endBefore', docOrFields,
|
|
25918
|
+
return new QueryEndAtConstraint('endBefore', docOrFields,
|
|
25919
|
+
/*inclusive=*/ false);
|
|
25263
25920
|
}
|
|
25264
25921
|
function endAt(...docOrFields) {
|
|
25265
|
-
return new QueryEndAtConstraint('endAt', docOrFields, /*
|
|
25922
|
+
return new QueryEndAtConstraint('endAt', docOrFields, /*inclusive=*/ true);
|
|
25266
25923
|
}
|
|
25267
25924
|
/** Helper function to create a bound from a document or fields */
|
|
25268
|
-
function newQueryBoundFromDocOrFields(query, methodName, docOrFields,
|
|
25925
|
+
function newQueryBoundFromDocOrFields(query, methodName, docOrFields, inclusive) {
|
|
25269
25926
|
docOrFields[0] = getModularInstance(docOrFields[0]);
|
|
25270
25927
|
if (docOrFields[0] instanceof DocumentSnapshot$1) {
|
|
25271
|
-
return newQueryBoundFromDocument(query._query, query.firestore._databaseId, methodName, docOrFields[0]._document,
|
|
25928
|
+
return newQueryBoundFromDocument(query._query, query.firestore._databaseId, methodName, docOrFields[0]._document, inclusive);
|
|
25272
25929
|
}
|
|
25273
25930
|
else {
|
|
25274
25931
|
const reader = newUserDataReader(query.firestore);
|
|
25275
|
-
return newQueryBoundFromFields(query._query, query.firestore._databaseId, reader, methodName, docOrFields,
|
|
25932
|
+
return newQueryBoundFromFields(query._query, query.firestore._databaseId, reader, methodName, docOrFields, inclusive);
|
|
25276
25933
|
}
|
|
25277
25934
|
}
|
|
25278
25935
|
function newQueryFilter(query, methodName, dataReader, databaseId, fieldPath, op, value) {
|
|
@@ -25330,7 +25987,7 @@ function newQueryOrderBy(query, fieldPath, direction) {
|
|
|
25330
25987
|
* of the query or if any of the fields in the order by are an uncommitted
|
|
25331
25988
|
* server timestamp.
|
|
25332
25989
|
*/
|
|
25333
|
-
function newQueryBoundFromDocument(query, databaseId, methodName, doc,
|
|
25990
|
+
function newQueryBoundFromDocument(query, databaseId, methodName, doc, inclusive) {
|
|
25334
25991
|
if (!doc) {
|
|
25335
25992
|
throw new FirestoreError(Code.NOT_FOUND, `Can't use a DocumentSnapshot that doesn't exist for ` +
|
|
25336
25993
|
`${methodName}().`);
|
|
@@ -25367,12 +26024,12 @@ function newQueryBoundFromDocument(query, databaseId, methodName, doc, before) {
|
|
|
25367
26024
|
}
|
|
25368
26025
|
}
|
|
25369
26026
|
}
|
|
25370
|
-
return new Bound(components,
|
|
26027
|
+
return new Bound(components, inclusive);
|
|
25371
26028
|
}
|
|
25372
26029
|
/**
|
|
25373
26030
|
* Converts a list of field values to a `Bound` for the given query.
|
|
25374
26031
|
*/
|
|
25375
|
-
function newQueryBoundFromFields(query, databaseId, dataReader, methodName, values,
|
|
26032
|
+
function newQueryBoundFromFields(query, databaseId, dataReader, methodName, values, inclusive) {
|
|
25376
26033
|
// Use explicit order by's because it has to match the query the user made
|
|
25377
26034
|
const orderBy = query.explicitOrderBy;
|
|
25378
26035
|
if (values.length > orderBy.length) {
|
|
@@ -25409,7 +26066,7 @@ function newQueryBoundFromFields(query, databaseId, dataReader, methodName, valu
|
|
|
25409
26066
|
components.push(wrapped);
|
|
25410
26067
|
}
|
|
25411
26068
|
}
|
|
25412
|
-
return new Bound(components,
|
|
26069
|
+
return new Bound(components, inclusive);
|
|
25413
26070
|
}
|
|
25414
26071
|
/**
|
|
25415
26072
|
* Parses the given `documentIdValue` into a `ReferenceValue`, throwing
|