@firebase/firestore 3.5.0 → 3.6.0

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.
Files changed (106) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/firestore/lite/index.d.ts +2 -0
  3. package/dist/firestore/src/api/aggregate.d.ts +43 -0
  4. package/dist/firestore/src/api/database.d.ts +15 -15
  5. package/dist/firestore/src/api.d.ts +2 -0
  6. package/dist/firestore/src/core/count_query_runner.d.ts +32 -0
  7. package/dist/firestore/src/core/firestore_client.d.ts +5 -0
  8. package/dist/firestore/src/lite-api/aggregate.d.ts +48 -0
  9. package/dist/firestore/src/lite-api/aggregate_types.d.ts +69 -0
  10. package/dist/firestore/src/lite-api/database.d.ts +7 -7
  11. package/dist/firestore/src/platform/node/grpc_connection.d.ts +1 -0
  12. package/dist/firestore/src/protos/firestore_proto_api.d.ts +28 -0
  13. package/dist/firestore/src/remote/connection.d.ts +7 -0
  14. package/dist/firestore/src/remote/datastore.d.ts +2 -0
  15. package/dist/firestore/src/remote/rest_connection.d.ts +1 -0
  16. package/dist/firestore/src/remote/serializer.d.ts +2 -1
  17. package/dist/firestore/test/integration/api/aggregation.test.d.ts +17 -0
  18. package/dist/firestore/test/integration/api_internal/aggregation.test.d.ts +17 -0
  19. package/dist/firestore/test/integration/util/helpers.d.ts +1 -0
  20. package/dist/firestore/test/unit/specs/spec_test_components.d.ts +1 -0
  21. package/dist/index.d.ts +196 -14
  22. package/dist/index.esm2017.js +4616 -4413
  23. package/dist/index.esm2017.js.map +1 -1
  24. package/dist/index.esm5.js +4608 -4402
  25. package/dist/index.esm5.js.map +1 -1
  26. package/dist/index.node.cjs.js +994 -613
  27. package/dist/index.node.cjs.js.map +1 -1
  28. package/dist/index.node.mjs +992 -615
  29. package/dist/index.node.mjs.map +1 -1
  30. package/dist/index.rn.js +4622 -4419
  31. package/dist/index.rn.js.map +1 -1
  32. package/dist/internal.d.ts +139 -17
  33. package/dist/lite/firestore/lite/index.d.ts +2 -0
  34. package/dist/lite/firestore/src/api/aggregate.d.ts +43 -0
  35. package/dist/lite/firestore/src/api/database.d.ts +15 -15
  36. package/dist/lite/firestore/src/api.d.ts +2 -0
  37. package/dist/lite/firestore/src/core/count_query_runner.d.ts +32 -0
  38. package/dist/lite/firestore/src/core/firestore_client.d.ts +5 -0
  39. package/dist/lite/firestore/src/lite-api/aggregate.d.ts +48 -0
  40. package/dist/lite/firestore/src/lite-api/aggregate_types.d.ts +69 -0
  41. package/dist/lite/firestore/src/lite-api/database.d.ts +7 -7
  42. package/dist/lite/firestore/src/platform/node/grpc_connection.d.ts +1 -0
  43. package/dist/lite/firestore/src/protos/firestore_proto_api.d.ts +28 -0
  44. package/dist/lite/firestore/src/remote/connection.d.ts +7 -0
  45. package/dist/lite/firestore/src/remote/datastore.d.ts +2 -0
  46. package/dist/lite/firestore/src/remote/rest_connection.d.ts +1 -0
  47. package/dist/lite/firestore/src/remote/serializer.d.ts +2 -1
  48. package/dist/lite/firestore/test/integration/api/aggregation.test.d.ts +17 -0
  49. package/dist/lite/firestore/test/integration/api_internal/aggregation.test.d.ts +17 -0
  50. package/dist/lite/firestore/test/integration/util/helpers.d.ts +1 -0
  51. package/dist/lite/firestore/test/unit/specs/spec_test_components.d.ts +1 -0
  52. package/dist/lite/index.browser.esm2017.js +1250 -1086
  53. package/dist/lite/index.browser.esm2017.js.map +1 -1
  54. package/dist/lite/index.browser.esm5.js +1394 -1232
  55. package/dist/lite/index.browser.esm5.js.map +1 -1
  56. package/dist/lite/index.d.ts +84 -4
  57. package/dist/lite/index.node.cjs.js +255 -63
  58. package/dist/lite/index.node.cjs.js.map +1 -1
  59. package/dist/lite/index.node.mjs +253 -65
  60. package/dist/lite/index.node.mjs.map +1 -1
  61. package/dist/lite/index.rn.esm2017.js +1257 -1093
  62. package/dist/lite/index.rn.esm2017.js.map +1 -1
  63. package/dist/lite/internal.d.ts +121 -6
  64. package/dist/lite/packages/firestore/dist/lite/index.browser.esm2017.d.ts +227 -142
  65. package/dist/lite/packages/firestore/lite/index.d.ts +2 -0
  66. package/dist/lite/packages/firestore/src/api/aggregate.d.ts +43 -0
  67. package/dist/lite/packages/firestore/src/api/database.d.ts +15 -15
  68. package/dist/lite/packages/firestore/src/api.d.ts +2 -0
  69. package/dist/lite/packages/firestore/src/core/count_query_runner.d.ts +32 -0
  70. package/dist/lite/packages/firestore/src/core/firestore_client.d.ts +5 -0
  71. package/dist/lite/packages/firestore/src/lite-api/aggregate.d.ts +48 -0
  72. package/dist/lite/packages/firestore/src/lite-api/aggregate_types.d.ts +69 -0
  73. package/dist/lite/packages/firestore/src/lite-api/database.d.ts +7 -7
  74. package/dist/lite/packages/firestore/src/platform/node/grpc_connection.d.ts +1 -0
  75. package/dist/lite/packages/firestore/src/protos/firestore_proto_api.d.ts +28 -0
  76. package/dist/lite/packages/firestore/src/remote/connection.d.ts +7 -0
  77. package/dist/lite/packages/firestore/src/remote/datastore.d.ts +2 -0
  78. package/dist/lite/packages/firestore/src/remote/rest_connection.d.ts +1 -0
  79. package/dist/lite/packages/firestore/src/remote/serializer.d.ts +2 -1
  80. package/dist/lite/packages/firestore/test/integration/api/aggregation.test.d.ts +17 -0
  81. package/dist/lite/packages/firestore/test/integration/api_internal/aggregation.test.d.ts +17 -0
  82. package/dist/lite/packages/firestore/test/integration/util/helpers.d.ts +1 -0
  83. package/dist/lite/packages/firestore/test/unit/specs/spec_test_components.d.ts +1 -0
  84. package/dist/lite/private.d.ts +119 -4
  85. package/dist/packages/firestore/dist/index.esm2017.d.ts +336 -254
  86. package/dist/packages/firestore/lite/index.d.ts +2 -0
  87. package/dist/packages/firestore/src/api/aggregate.d.ts +43 -0
  88. package/dist/packages/firestore/src/api/database.d.ts +15 -15
  89. package/dist/packages/firestore/src/api.d.ts +2 -0
  90. package/dist/packages/firestore/src/core/count_query_runner.d.ts +32 -0
  91. package/dist/packages/firestore/src/core/firestore_client.d.ts +5 -0
  92. package/dist/packages/firestore/src/lite-api/aggregate.d.ts +48 -0
  93. package/dist/packages/firestore/src/lite-api/aggregate_types.d.ts +69 -0
  94. package/dist/packages/firestore/src/lite-api/database.d.ts +7 -7
  95. package/dist/packages/firestore/src/platform/node/grpc_connection.d.ts +1 -0
  96. package/dist/packages/firestore/src/protos/firestore_proto_api.d.ts +28 -0
  97. package/dist/packages/firestore/src/remote/connection.d.ts +7 -0
  98. package/dist/packages/firestore/src/remote/datastore.d.ts +2 -0
  99. package/dist/packages/firestore/src/remote/rest_connection.d.ts +1 -0
  100. package/dist/packages/firestore/src/remote/serializer.d.ts +2 -1
  101. package/dist/packages/firestore/test/integration/api/aggregation.test.d.ts +17 -0
  102. package/dist/packages/firestore/test/integration/api_internal/aggregation.test.d.ts +17 -0
  103. package/dist/packages/firestore/test/integration/util/helpers.d.ts +1 -0
  104. package/dist/packages/firestore/test/unit/specs/spec_test_components.d.ts +1 -0
  105. package/dist/private.d.ts +234 -19
  106. package/package.json +6 -6
@@ -2,13 +2,13 @@ import { _getProvider, getApp, _removeServiceInstance, _registerComponent, regis
2
2
  import { Component } from '@firebase/component';
3
3
  import { Logger, LogLevel } from '@firebase/logger';
4
4
  import { inspect, TextEncoder, TextDecoder } from 'util';
5
- import { FirebaseError, createMockUserToken, getModularInstance, deepEqual, getUA, isIndexedDBAvailable, isSafari } from '@firebase/util';
5
+ import { FirebaseError, createMockUserToken, getModularInstance, deepEqual, getDefaultEmulatorHost, getUA, isIndexedDBAvailable, isSafari } from '@firebase/util';
6
6
  import { randomBytes as randomBytes$1 } from 'crypto';
7
7
  import * as grpc from '@grpc/grpc-js';
8
8
  import * as protoLoader from '@grpc/proto-loader';
9
9
 
10
10
  const name = "@firebase/firestore";
11
- const version$1 = "3.5.0";
11
+ const version$1 = "3.6.0";
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.10.0";
64
+ const version = "9.11.0";
65
65
 
66
66
  /**
67
67
  * @license
@@ -8726,6 +8726,21 @@ function toQueryTarget(serializer, target) {
8726
8726
  }
8727
8727
  return result;
8728
8728
  }
8729
+ function toRunAggregationQueryRequest(serializer, target) {
8730
+ const queryTarget = toQueryTarget(serializer, target);
8731
+ return {
8732
+ structuredAggregationQuery: {
8733
+ aggregations: [
8734
+ {
8735
+ count: {},
8736
+ alias: 'count_alias'
8737
+ }
8738
+ ],
8739
+ structuredQuery: queryTarget.structuredQuery
8740
+ },
8741
+ parent: queryTarget.parent
8742
+ };
8743
+ }
8729
8744
  function convertQueryTargetToQuery(target) {
8730
8745
  let path = fromQueryPath(target.parent);
8731
8746
  const query = target.structuredQuery;
@@ -16112,7 +16127,8 @@ function localStoreGetNewDocumentChanges(localStore, collectionGroup) {
16112
16127
  /** Sets the collection group's maximum read time from the given documents. */
16113
16128
  // PORTING NOTE: Multi-Tab only.
16114
16129
  function setMaxReadTime(localStoreImpl, collectionGroup, changedDocs) {
16115
- let readTime = SnapshotVersion.min();
16130
+ let readTime = localStoreImpl.collectionGroupReadTime.get(collectionGroup) ||
16131
+ SnapshotVersion.min();
16116
16132
  changedDocs.forEach((_, doc) => {
16117
16133
  if (doc.readTime.compareTo(readTime) > 0) {
16118
16134
  readTime = doc.readTime;
@@ -17404,6 +17420,11 @@ class GrpcConnection {
17404
17420
  this.firestore = protos['google']['firestore']['v1'];
17405
17421
  this.databasePath = `projects/${databaseInfo.databaseId.projectId}/databases/${databaseInfo.databaseId.database}`;
17406
17422
  }
17423
+ get shouldResourcePathBeIncludedInRequest() {
17424
+ // Both `invokeRPC()` and `invokeStreamingRPC()` ignore their `path` arguments, and expect
17425
+ // the "path" to be part of the given `request`.
17426
+ return true;
17427
+ }
17407
17428
  ensureActiveStub() {
17408
17429
  if (!this.cachedStub) {
17409
17430
  logDebug(LOG_TAG$9, 'Creating Firestore stub.');
@@ -18450,6 +18471,15 @@ const nested = {
18450
18471
  ruby_package: "Google::Cloud::Firestore::V1"
18451
18472
  },
18452
18473
  nested: {
18474
+ AggregationResult: {
18475
+ fields: {
18476
+ aggregateFields: {
18477
+ keyType: "string",
18478
+ type: "Value",
18479
+ id: 2
18480
+ }
18481
+ }
18482
+ },
18453
18483
  DocumentMask: {
18454
18484
  fields: {
18455
18485
  fieldPaths: {
@@ -18800,6 +18830,29 @@ const nested = {
18800
18830
  }
18801
18831
  ]
18802
18832
  },
18833
+ RunAggregationQuery: {
18834
+ requestType: "RunAggregationQueryRequest",
18835
+ responseType: "RunAggregationQueryResponse",
18836
+ responseStream: true,
18837
+ options: {
18838
+ "(google.api.http).post": "/v1/{parent=projects/*/databases/*/documents}:runAggregationQuery",
18839
+ "(google.api.http).body": "*",
18840
+ "(google.api.http).additional_bindings.post": "/v1/{parent=projects/*/databases/*/documents/*/**}:runAggregationQuery",
18841
+ "(google.api.http).additional_bindings.body": "*"
18842
+ },
18843
+ parsedOptions: [
18844
+ {
18845
+ "(google.api.http)": {
18846
+ post: "/v1/{parent=projects/*/databases/*/documents}:runAggregationQuery",
18847
+ body: "*",
18848
+ additional_bindings: {
18849
+ post: "/v1/{parent=projects/*/databases/*/documents/*/**}:runAggregationQuery",
18850
+ body: "*"
18851
+ }
18852
+ }
18853
+ }
18854
+ ]
18855
+ },
18803
18856
  PartitionQuery: {
18804
18857
  requestType: "PartitionQueryRequest",
18805
18858
  responseType: "PartitionQueryResponse",
@@ -19291,6 +19344,63 @@ const nested = {
19291
19344
  }
19292
19345
  }
19293
19346
  },
19347
+ RunAggregationQueryRequest: {
19348
+ oneofs: {
19349
+ queryType: {
19350
+ oneof: [
19351
+ "structuredAggregationQuery"
19352
+ ]
19353
+ },
19354
+ consistencySelector: {
19355
+ oneof: [
19356
+ "transaction",
19357
+ "newTransaction",
19358
+ "readTime"
19359
+ ]
19360
+ }
19361
+ },
19362
+ fields: {
19363
+ parent: {
19364
+ type: "string",
19365
+ id: 1,
19366
+ options: {
19367
+ "(google.api.field_behavior)": "REQUIRED"
19368
+ }
19369
+ },
19370
+ structuredAggregationQuery: {
19371
+ type: "StructuredAggregationQuery",
19372
+ id: 2
19373
+ },
19374
+ transaction: {
19375
+ type: "bytes",
19376
+ id: 4
19377
+ },
19378
+ newTransaction: {
19379
+ type: "TransactionOptions",
19380
+ id: 5
19381
+ },
19382
+ readTime: {
19383
+ type: "google.protobuf.Timestamp",
19384
+ id: 6
19385
+ }
19386
+ }
19387
+ },
19388
+ RunAggregationQueryResponse: {
19389
+ fields: {
19390
+ result: {
19391
+ type: "AggregationResult",
19392
+ id: 1
19393
+ },
19394
+ transaction: {
19395
+ type: "bytes",
19396
+ id: 2
19397
+ },
19398
+ readTime: {
19399
+ type: "google.protobuf.Timestamp",
19400
+ id: 3
19401
+ }
19402
+ }
19403
+ },
19294
19404
  PartitionQueryRequest: {
19295
19405
  oneofs: {
19296
19406
  queryType: {
@@ -19827,6 +19937,57 @@ const nested = {
19827
19937
  }
19828
19938
  }
19829
19939
  },
19940
+ StructuredAggregationQuery: {
19941
+ oneofs: {
19942
+ queryType: {
19943
+ oneof: [
19944
+ "structuredQuery"
19945
+ ]
19946
+ }
19947
+ },
19948
+ fields: {
19949
+ structuredQuery: {
19950
+ type: "StructuredQuery",
19951
+ id: 1
19952
+ },
19953
+ aggregations: {
19954
+ rule: "repeated",
19955
+ type: "Aggregation",
19956
+ id: 3
19957
+ }
19958
+ },
19959
+ nested: {
19960
+ Aggregation: {
19961
+ oneofs: {
19962
+ operator: {
19963
+ oneof: [
19964
+ "count"
19965
+ ]
19966
+ }
19967
+ },
19968
+ fields: {
19969
+ count: {
19970
+ type: "Count",
19971
+ id: 1
19972
+ },
19973
+ alias: {
19974
+ type: "string",
19975
+ id: 7
19976
+ }
19977
+ },
19978
+ nested: {
19979
+ Count: {
19980
+ fields: {
19981
+ upTo: {
19982
+ type: "google.protobuf.Int64Value",
19983
+ id: 1
19984
+ }
19985
+ }
19986
+ }
19987
+ }
19988
+ }
19989
+ }
19990
+ },
19830
19991
  Cursor: {
19831
19992
  fields: {
19832
19993
  values: {
@@ -21067,6 +21228,19 @@ async function invokeBatchGetDocumentsRpc(datastore, keys) {
21067
21228
  });
21068
21229
  return result;
21069
21230
  }
21231
+ async function invokeRunAggregationQueryRpc(datastore, query) {
21232
+ const datastoreImpl = debugCast(datastore);
21233
+ const request = toRunAggregationQueryRequest(datastoreImpl.serializer, queryToTarget(query));
21234
+ const parent = request.parent;
21235
+ if (!datastoreImpl.connection.shouldResourcePathBeIncludedInRequest) {
21236
+ delete request.parent;
21237
+ }
21238
+ const response = await datastoreImpl.invokeStreamingRPC('RunAggregationQuery', parent, request, /*expectedResponseCount=*/ 1);
21239
+ return (response
21240
+ // Omit RunAggregationQueryResponse that only contain readTimes.
21241
+ .filter(proto => !!proto.result)
21242
+ .map(proto => proto.result.aggregateFields));
21243
+ }
21070
21244
  function newPersistentWriteStream(datastore, queue, listener) {
21071
21245
  const datastoreImpl = debugCast(datastore);
21072
21246
  datastoreImpl.verifyInitialized();
@@ -23624,10 +23798,15 @@ async function syncEngineEmitNewSnapsAndNotifyLocalStore(syncEngine, changes, re
23624
23798
  queriesProcessed.push(syncEngineImpl
23625
23799
  .applyDocChanges(queryView, changes, remoteEvent)
23626
23800
  .then(viewSnapshot => {
23627
- if (viewSnapshot) {
23801
+ // If there are changes, or we are handling a global snapshot, notify
23802
+ // secondary clients to update query state.
23803
+ if (viewSnapshot || remoteEvent) {
23628
23804
  if (syncEngineImpl.isPrimaryClient) {
23629
- syncEngineImpl.sharedClientState.updateQueryState(queryView.targetId, viewSnapshot.fromCache ? 'not-current' : 'current');
23805
+ syncEngineImpl.sharedClientState.updateQueryState(queryView.targetId, (viewSnapshot === null || viewSnapshot === void 0 ? void 0 : viewSnapshot.fromCache) ? 'not-current' : 'current');
23630
23806
  }
23807
+ }
23808
+ // Update views if there are actual changes.
23809
+ if (!!viewSnapshot) {
23631
23810
  newSnaps.push(viewSnapshot);
23632
23811
  const docChanges = LocalViewChanges.fromSnapshot(queryView.targetId, viewSnapshot);
23633
23812
  docChangesInAllViews.push(docChanges);
@@ -24673,6 +24852,100 @@ function newBundleReader(reader, serializer) {
24673
24852
  return new BundleReaderImpl(reader, serializer);
24674
24853
  }
24675
24854
 
24855
+ /**
24856
+ * @license
24857
+ * Copyright 2022 Google LLC
24858
+ *
24859
+ * Licensed under the Apache License, Version 2.0 (the "License");
24860
+ * you may not use this file except in compliance with the License.
24861
+ * You may obtain a copy of the License at
24862
+ *
24863
+ * http://www.apache.org/licenses/LICENSE-2.0
24864
+ *
24865
+ * Unless required by applicable law or agreed to in writing, software
24866
+ * distributed under the License is distributed on an "AS IS" BASIS,
24867
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24868
+ * See the License for the specific language governing permissions and
24869
+ * limitations under the License.
24870
+ */
24871
+ /**
24872
+ * Represents an aggregation that can be performed by Firestore.
24873
+ */
24874
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
24875
+ class AggregateField {
24876
+ constructor() {
24877
+ /** A type string to uniquely identify instances of this class. */
24878
+ this.type = 'AggregateField';
24879
+ }
24880
+ }
24881
+ /**
24882
+ * The results of executing an aggregation query.
24883
+ */
24884
+ class AggregateQuerySnapshot {
24885
+ /** @hideconstructor */
24886
+ constructor(query, _data) {
24887
+ this._data = _data;
24888
+ /** A type string to uniquely identify instances of this class. */
24889
+ this.type = 'AggregateQuerySnapshot';
24890
+ this.query = query;
24891
+ }
24892
+ /**
24893
+ * Returns the results of the aggregations performed over the underlying
24894
+ * query.
24895
+ *
24896
+ * The keys of the returned object will be the same as those of the
24897
+ * `AggregateSpec` object specified to the aggregation method, and the values
24898
+ * will be the corresponding aggregation result.
24899
+ *
24900
+ * @returns The results of the aggregations performed over the underlying
24901
+ * query.
24902
+ */
24903
+ data() {
24904
+ return this._data;
24905
+ }
24906
+ }
24907
+
24908
+ /**
24909
+ * @license
24910
+ * Copyright 2022 Google LLC
24911
+ *
24912
+ * Licensed under the Apache License, Version 2.0 (the "License");
24913
+ * you may not use this file except in compliance with the License.
24914
+ * You may obtain a copy of the License at
24915
+ *
24916
+ * http://www.apache.org/licenses/LICENSE-2.0
24917
+ *
24918
+ * Unless required by applicable law or agreed to in writing, software
24919
+ * distributed under the License is distributed on an "AS IS" BASIS,
24920
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24921
+ * See the License for the specific language governing permissions and
24922
+ * limitations under the License.
24923
+ */
24924
+ /**
24925
+ * CountQueryRunner encapsulates the logic needed to run the count aggregation
24926
+ * queries.
24927
+ */
24928
+ class CountQueryRunner {
24929
+ constructor(query, datastore, userDataWriter) {
24930
+ this.query = query;
24931
+ this.datastore = datastore;
24932
+ this.userDataWriter = userDataWriter;
24933
+ }
24934
+ run() {
24935
+ return invokeRunAggregationQueryRpc(this.datastore, this.query._query).then(result => {
24936
+ hardAssert(result[0] !== undefined);
24937
+ const counts = Object.entries(result[0])
24938
+ .filter(([key, value]) => key === 'count_alias')
24939
+ .map(([key, value]) => this.userDataWriter.convertValue(value));
24940
+ const countValue = counts[0];
24941
+ hardAssert(typeof countValue === 'number');
24942
+ return Promise.resolve(new AggregateQuerySnapshot(this.query, {
24943
+ count: countValue
24944
+ }));
24945
+ });
24946
+ }
24947
+ }
24948
+
24676
24949
  /**
24677
24950
  * @license
24678
24951
  * Copyright 2017 Google LLC
@@ -25229,6 +25502,26 @@ function firestoreClientTransaction(client, updateFunction, options) {
25229
25502
  });
25230
25503
  return deferred.promise;
25231
25504
  }
25505
+ function firestoreClientRunCountQuery(client, query, userDataWriter) {
25506
+ const deferred = new Deferred();
25507
+ client.asyncQueue.enqueueAndForget(async () => {
25508
+ try {
25509
+ const remoteStore = await getRemoteStore(client);
25510
+ if (!canUseNetwork(remoteStore)) {
25511
+ deferred.reject(new FirestoreError(Code.UNAVAILABLE, 'Failed to get count result because the client is offline.'));
25512
+ }
25513
+ else {
25514
+ const datastore = await getDatastore(client);
25515
+ const result = new CountQueryRunner(query, datastore, userDataWriter).run();
25516
+ deferred.resolve(result);
25517
+ }
25518
+ }
25519
+ catch (e) {
25520
+ deferred.reject(e);
25521
+ }
25522
+ });
25523
+ return deferred.promise;
25524
+ }
25232
25525
  async function readDocumentFromCache(localStore, docKey, result) {
25233
25526
  try {
25234
25527
  const document = await localStoreReadDocument(localStore, docKey);
@@ -25484,7 +25777,7 @@ class FirestoreSettingsImpl {
25484
25777
  /**
25485
25778
  * The Cloud Firestore service interface.
25486
25779
  *
25487
- * Do not call this constructor directly. Instead, use {@link getFirestore}.
25780
+ * Do not call this constructor directly. Instead, use {@link (getFirestore:1)}.
25488
25781
  */
25489
25782
  class Firestore$1 {
25490
25783
  /** @hideconstructor */
@@ -26226,7 +26519,7 @@ const CACHE_SIZE_UNLIMITED = LRU_COLLECTION_DISABLED;
26226
26519
  /**
26227
26520
  * The Cloud Firestore service interface.
26228
26521
  *
26229
- * Do not call this constructor directly. Instead, use {@link getFirestore}.
26522
+ * Do not call this constructor directly. Instead, use {@link (getFirestore:1)}.
26230
26523
  */
26231
26524
  class Firestore extends Firestore$1 {
26232
26525
  /** @hideconstructor */
@@ -26251,8 +26544,8 @@ class Firestore extends Firestore$1 {
26251
26544
  /**
26252
26545
  * Initializes a new instance of {@link Firestore} with the provided settings.
26253
26546
  * Can only be called before any other function, including
26254
- * {@link getFirestore}. If the custom settings are empty, this function is
26255
- * equivalent to calling {@link getFirestore}.
26547
+ * {@link (getFirestore:1)}. If the custom settings are empty, this function is
26548
+ * equivalent to calling {@link (getFirestore:1)}.
26256
26549
  *
26257
26550
  * @param app - The {@link @firebase/app#FirebaseApp} with which the {@link Firestore} instance will
26258
26551
  * be associated.
@@ -26295,9 +26588,17 @@ function getFirestore(appOrDatabaseId, optionalDatabaseId) {
26295
26588
  const databaseId = typeof appOrDatabaseId === 'string'
26296
26589
  ? appOrDatabaseId
26297
26590
  : optionalDatabaseId || DEFAULT_DATABASE_NAME;
26298
- return _getProvider(app, 'firestore').getImmediate({
26591
+ const db = _getProvider(app, 'firestore').getImmediate({
26299
26592
  identifier: databaseId
26300
26593
  });
26594
+ if (!db._initialized) {
26595
+ const firestoreEmulatorHost = getDefaultEmulatorHost('firestore');
26596
+ if (firestoreEmulatorHost) {
26597
+ const [host, port] = firestoreEmulatorHost.split(':');
26598
+ connectFirestoreEmulator(db, host, parseInt(port, 10));
26599
+ }
26600
+ }
26601
+ return db;
26301
26602
  }
26302
26603
  /**
26303
26604
  * @internal
@@ -26319,7 +26620,7 @@ function configureFirestore(firestore) {
26319
26620
  * Attempts to enable persistent storage, if possible.
26320
26621
  *
26321
26622
  * Must be called before any other functions (other than
26322
- * {@link initializeFirestore}, {@link getFirestore} or
26623
+ * {@link initializeFirestore}, {@link (getFirestore:1)} or
26323
26624
  * {@link clearIndexedDbPersistence}.
26324
26625
  *
26325
26626
  * If this fails, `enableIndexedDbPersistence()` will reject the promise it
@@ -26443,7 +26744,7 @@ function canFallbackFromIndexedDbError(error) {
26443
26744
  * Must be called while the {@link Firestore} instance is not started (after the app is
26444
26745
  * terminated or when the app is first initialized). On startup, this function
26445
26746
  * must be called before other functions (other than {@link
26446
- * initializeFirestore} or {@link getFirestore})). If the {@link Firestore}
26747
+ * initializeFirestore} or {@link (getFirestore:1)})). If the {@link Firestore}
26447
26748
  * instance is still running, the promise will be rejected with the error code
26448
26749
  * of `failed-precondition`.
26449
26750
  *
@@ -26527,7 +26828,7 @@ function disableNetwork(firestore) {
26527
26828
  * may be used. Any other function will throw a `FirestoreError`.
26528
26829
  *
26529
26830
  * To restart after termination, create a new instance of FirebaseFirestore with
26530
- * {@link getFirestore}.
26831
+ * {@link (getFirestore:1)}.
26531
26832
  *
26532
26833
  * Termination does not cancel any pending writes, and any promises that are
26533
26834
  * awaiting a response from the server will not be resolved. If you have
@@ -26626,7 +26927,7 @@ function registerFirestore(variant, useFetchStreams = true) {
26626
26927
 
26627
26928
  /**
26628
26929
  * @license
26629
- * Copyright 2020 Google LLC
26930
+ * Copyright 2017 Google LLC
26630
26931
  *
26631
26932
  * Licensed under the Apache License, Version 2.0 (the "License");
26632
26933
  * you may not use this file except in compliance with the License.
@@ -26640,46 +26941,24 @@ function registerFirestore(variant, useFetchStreams = true) {
26640
26941
  * See the License for the specific language governing permissions and
26641
26942
  * limitations under the License.
26642
26943
  */
26944
+ function isPartialObserver(obj) {
26945
+ return implementsAnyMethods(obj, ['next', 'error', 'complete']);
26946
+ }
26643
26947
  /**
26644
- * A `FieldPath` refers to a field in a document. The path may consist of a
26645
- * single field name (referring to a top-level field in the document), or a
26646
- * list of field names (referring to a nested field in the document).
26647
- *
26648
- * Create a `FieldPath` by providing field names. If more than one field
26649
- * name is provided, the path will point to a nested field in a document.
26948
+ * Returns true if obj is an object and contains at least one of the specified
26949
+ * methods.
26650
26950
  */
26651
- class FieldPath {
26652
- /**
26653
- * Creates a `FieldPath` from the provided field names. If more than one field
26654
- * name is provided, the path will point to a nested field in a document.
26655
- *
26656
- * @param fieldNames - A list of field names.
26657
- */
26658
- constructor(...fieldNames) {
26659
- for (let i = 0; i < fieldNames.length; ++i) {
26660
- if (fieldNames[i].length === 0) {
26661
- throw new FirestoreError(Code.INVALID_ARGUMENT, `Invalid field name at argument $(i + 1). ` +
26662
- 'Field names must not be empty.');
26663
- }
26664
- }
26665
- this._internalPath = new FieldPath$1(fieldNames);
26951
+ function implementsAnyMethods(obj, methods) {
26952
+ if (typeof obj !== 'object' || obj === null) {
26953
+ return false;
26666
26954
  }
26667
- /**
26668
- * Returns true if this `FieldPath` is equal to the provided one.
26669
- *
26670
- * @param other - The `FieldPath` to compare against.
26671
- * @returns true if this `FieldPath` is equal to the provided one.
26672
- */
26673
- isEqual(other) {
26674
- return this._internalPath.isEqual(other._internalPath);
26955
+ const object = obj;
26956
+ for (const method of methods) {
26957
+ if (method in object && typeof object[method] === 'function') {
26958
+ return true;
26959
+ }
26675
26960
  }
26676
- }
26677
- /**
26678
- * Returns a special sentinel `FieldPath` to refer to the ID of a document.
26679
- * It can be used in queries to sort or filter by the document ID.
26680
- */
26681
- function documentId() {
26682
- return new FieldPath(DOCUMENT_KEY_NAME);
26961
+ return false;
26683
26962
  }
26684
26963
 
26685
26964
  /**
@@ -26780,11 +27059,69 @@ class Bytes {
26780
27059
  * limitations under the License.
26781
27060
  */
26782
27061
  /**
26783
- * Sentinel values that can be used when writing document fields with `set()`
26784
- * or `update()`.
26785
- */
26786
- class FieldValue {
26787
- /**
27062
+ * A `FieldPath` refers to a field in a document. The path may consist of a
27063
+ * single field name (referring to a top-level field in the document), or a
27064
+ * list of field names (referring to a nested field in the document).
27065
+ *
27066
+ * Create a `FieldPath` by providing field names. If more than one field
27067
+ * name is provided, the path will point to a nested field in a document.
27068
+ */
27069
+ class FieldPath {
27070
+ /**
27071
+ * Creates a `FieldPath` from the provided field names. If more than one field
27072
+ * name is provided, the path will point to a nested field in a document.
27073
+ *
27074
+ * @param fieldNames - A list of field names.
27075
+ */
27076
+ constructor(...fieldNames) {
27077
+ for (let i = 0; i < fieldNames.length; ++i) {
27078
+ if (fieldNames[i].length === 0) {
27079
+ throw new FirestoreError(Code.INVALID_ARGUMENT, `Invalid field name at argument $(i + 1). ` +
27080
+ 'Field names must not be empty.');
27081
+ }
27082
+ }
27083
+ this._internalPath = new FieldPath$1(fieldNames);
27084
+ }
27085
+ /**
27086
+ * Returns true if this `FieldPath` is equal to the provided one.
27087
+ *
27088
+ * @param other - The `FieldPath` to compare against.
27089
+ * @returns true if this `FieldPath` is equal to the provided one.
27090
+ */
27091
+ isEqual(other) {
27092
+ return this._internalPath.isEqual(other._internalPath);
27093
+ }
27094
+ }
27095
+ /**
27096
+ * Returns a special sentinel `FieldPath` to refer to the ID of a document.
27097
+ * It can be used in queries to sort or filter by the document ID.
27098
+ */
27099
+ function documentId() {
27100
+ return new FieldPath(DOCUMENT_KEY_NAME);
27101
+ }
27102
+
27103
+ /**
27104
+ * @license
27105
+ * Copyright 2020 Google LLC
27106
+ *
27107
+ * Licensed under the Apache License, Version 2.0 (the "License");
27108
+ * you may not use this file except in compliance with the License.
27109
+ * You may obtain a copy of the License at
27110
+ *
27111
+ * http://www.apache.org/licenses/LICENSE-2.0
27112
+ *
27113
+ * Unless required by applicable law or agreed to in writing, software
27114
+ * distributed under the License is distributed on an "AS IS" BASIS,
27115
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27116
+ * See the License for the specific language governing permissions and
27117
+ * limitations under the License.
27118
+ */
27119
+ /**
27120
+ * Sentinel values that can be used when writing document fields with `set()`
27121
+ * or `update()`.
27122
+ */
27123
+ class FieldValue {
27124
+ /**
26788
27125
  * @param _methodName - The public API endpoint that returns this class.
26789
27126
  * @hideconstructor
26790
27127
  */
@@ -27685,378 +28022,87 @@ function fieldPathFromArgument(methodName, arg) {
27685
28022
  * See the License for the specific language governing permissions and
27686
28023
  * limitations under the License.
27687
28024
  */
28025
+ function validateHasExplicitOrderByForLimitToLast(query) {
28026
+ if (query.limitType === "L" /* Last */ &&
28027
+ query.explicitOrderBy.length === 0) {
28028
+ throw new FirestoreError(Code.UNIMPLEMENTED, 'limitToLast() queries require specifying at least one orderBy() clause');
28029
+ }
28030
+ }
27688
28031
  /**
27689
- * Metadata about a snapshot, describing the state of the snapshot.
28032
+ * A `QueryConstraint` is used to narrow the set of documents returned by a
28033
+ * Firestore query. `QueryConstraint`s are created by invoking {@link where},
28034
+ * {@link orderBy}, {@link (startAt:1)}, {@link (startAfter:1)}, {@link
28035
+ * endBefore:1}, {@link (endAt:1)}, {@link limit} or {@link limitToLast} and
28036
+ * can then be passed to {@link query} to create a new query instance that
28037
+ * also contains this `QueryConstraint`.
27690
28038
  */
27691
- class SnapshotMetadata {
27692
- /** @hideconstructor */
27693
- constructor(hasPendingWrites, fromCache) {
27694
- this.hasPendingWrites = hasPendingWrites;
27695
- this.fromCache = fromCache;
27696
- }
27697
- /**
27698
- * Returns true if this `SnapshotMetadata` is equal to the provided one.
27699
- *
27700
- * @param other - The `SnapshotMetadata` to compare against.
27701
- * @returns true if this `SnapshotMetadata` is equal to the provided one.
27702
- */
27703
- isEqual(other) {
27704
- return (this.hasPendingWrites === other.hasPendingWrites &&
27705
- this.fromCache === other.fromCache);
27706
- }
28039
+ class QueryConstraint {
27707
28040
  }
27708
28041
  /**
27709
- * A `DocumentSnapshot` contains data read from a document in your Firestore
27710
- * database. The data can be extracted with `.data()` or `.get(<field>)` to
27711
- * get a specific field.
28042
+ * Creates a new immutable instance of {@link Query} that is extended to also include
28043
+ * additional query constraints.
27712
28044
  *
27713
- * For a `DocumentSnapshot` that points to a non-existing document, any data
27714
- * access will return 'undefined'. You can use the `exists()` method to
27715
- * explicitly verify a document's existence.
28045
+ * @param query - The {@link Query} instance to use as a base for the new constraints.
28046
+ * @param queryConstraints - The list of {@link QueryConstraint}s to apply.
28047
+ * @throws if any of the provided query constraints cannot be combined with the
28048
+ * existing or new constraints.
27716
28049
  */
27717
- class DocumentSnapshot extends DocumentSnapshot$1 {
27718
- /** @hideconstructor protected */
27719
- constructor(_firestore, userDataWriter, key, document, metadata, converter) {
27720
- super(_firestore, userDataWriter, key, document, converter);
27721
- this._firestore = _firestore;
27722
- this._firestoreImpl = _firestore;
27723
- this.metadata = metadata;
27724
- }
27725
- /**
27726
- * Returns whether or not the data exists. True if the document exists.
27727
- */
27728
- exists() {
27729
- return super.exists();
28050
+ function query(query, ...queryConstraints) {
28051
+ for (const constraint of queryConstraints) {
28052
+ query = constraint._apply(query);
27730
28053
  }
27731
- /**
27732
- * Retrieves all fields in the document as an `Object`. Returns `undefined` if
27733
- * the document doesn't exist.
27734
- *
27735
- * By default, `serverTimestamp()` values that have not yet been
27736
- * set to their final value will be returned as `null`. You can override
27737
- * this by passing an options object.
27738
- *
27739
- * @param options - An options object to configure how data is retrieved from
27740
- * the snapshot (for example the desired behavior for server timestamps that
27741
- * have not yet been set to their final value).
27742
- * @returns An `Object` containing all fields in the document or `undefined` if
27743
- * the document doesn't exist.
27744
- */
27745
- data(options = {}) {
27746
- if (!this._document) {
27747
- return undefined;
27748
- }
27749
- else if (this._converter) {
27750
- // We only want to use the converter and create a new DocumentSnapshot
27751
- // if a converter has been provided.
27752
- const snapshot = new QueryDocumentSnapshot(this._firestore, this._userDataWriter, this._key, this._document, this.metadata,
27753
- /* converter= */ null);
27754
- return this._converter.fromFirestore(snapshot, options);
27755
- }
27756
- else {
27757
- return this._userDataWriter.convertValue(this._document.data.value, options.serverTimestamps);
27758
- }
28054
+ return query;
28055
+ }
28056
+ class QueryFilterConstraint extends QueryConstraint {
28057
+ constructor(_field, _op, _value) {
28058
+ super();
28059
+ this._field = _field;
28060
+ this._op = _op;
28061
+ this._value = _value;
28062
+ this.type = 'where';
27759
28063
  }
27760
- /**
27761
- * Retrieves the field specified by `fieldPath`. Returns `undefined` if the
27762
- * document or field doesn't exist.
27763
- *
27764
- * By default, a `serverTimestamp()` that has not yet been set to
27765
- * its final value will be returned as `null`. You can override this by
27766
- * passing an options object.
27767
- *
27768
- * @param fieldPath - The path (for example 'foo' or 'foo.bar') to a specific
27769
- * field.
27770
- * @param options - An options object to configure how the field is retrieved
27771
- * from the snapshot (for example the desired behavior for server timestamps
27772
- * that have not yet been set to their final value).
27773
- * @returns The data at the specified field location or undefined if no such
27774
- * field exists in the document.
27775
- */
27776
- // We are using `any` here to avoid an explicit cast by our users.
27777
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
27778
- get(fieldPath, options = {}) {
27779
- if (this._document) {
27780
- const value = this._document.data.field(fieldPathFromArgument('DocumentSnapshot.get', fieldPath));
27781
- if (value !== null) {
27782
- return this._userDataWriter.convertValue(value, options.serverTimestamps);
27783
- }
27784
- }
27785
- return undefined;
28064
+ _apply(query) {
28065
+ const reader = newUserDataReader(query.firestore);
28066
+ const filter = newQueryFilter(query._query, 'where', reader, query.firestore._databaseId, this._field, this._op, this._value);
28067
+ return new Query(query.firestore, query.converter, queryWithAddedFilter(query._query, filter));
27786
28068
  }
27787
28069
  }
27788
28070
  /**
27789
- * A `QueryDocumentSnapshot` contains data read from a document in your
27790
- * Firestore database as part of a query. The document is guaranteed to exist
27791
- * and its data can be extracted with `.data()` or `.get(<field>)` to get a
27792
- * specific field.
28071
+ * Creates a {@link QueryConstraint} that enforces that documents must contain the
28072
+ * specified field and that the value should satisfy the relation constraint
28073
+ * provided.
27793
28074
  *
27794
- * A `QueryDocumentSnapshot` offers the same API surface as a
27795
- * `DocumentSnapshot`. Since query results contain only existing documents, the
27796
- * `exists` property will always be true and `data()` will never return
27797
- * 'undefined'.
28075
+ * @param fieldPath - The path to compare
28076
+ * @param opStr - The operation string (e.g "&lt;", "&lt;=", "==", "&lt;",
28077
+ * "&lt;=", "!=").
28078
+ * @param value - The value for comparison
28079
+ * @returns The created {@link Query}.
27798
28080
  */
27799
- class QueryDocumentSnapshot extends DocumentSnapshot {
27800
- /**
27801
- * Retrieves all fields in the document as an `Object`.
27802
- *
27803
- * By default, `serverTimestamp()` values that have not yet been
27804
- * set to their final value will be returned as `null`. You can override
27805
- * this by passing an options object.
27806
- *
27807
- * @override
27808
- * @param options - An options object to configure how data is retrieved from
27809
- * the snapshot (for example the desired behavior for server timestamps that
27810
- * have not yet been set to their final value).
27811
- * @returns An `Object` containing all fields in the document.
27812
- */
27813
- data(options = {}) {
27814
- return super.data(options);
28081
+ function where(fieldPath, opStr, value) {
28082
+ const op = opStr;
28083
+ const field = fieldPathFromArgument('where', fieldPath);
28084
+ return new QueryFilterConstraint(field, op, value);
28085
+ }
28086
+ class QueryOrderByConstraint extends QueryConstraint {
28087
+ constructor(_field, _direction) {
28088
+ super();
28089
+ this._field = _field;
28090
+ this._direction = _direction;
28091
+ this.type = 'orderBy';
28092
+ }
28093
+ _apply(query) {
28094
+ const orderBy = newQueryOrderBy(query._query, this._field, this._direction);
28095
+ return new Query(query.firestore, query.converter, queryWithAddedOrderBy(query._query, orderBy));
27815
28096
  }
27816
28097
  }
27817
28098
  /**
27818
- * A `QuerySnapshot` contains zero or more `DocumentSnapshot` objects
27819
- * representing the results of a query. The documents can be accessed as an
27820
- * array via the `docs` property or enumerated using the `forEach` method. The
27821
- * number of documents can be determined via the `empty` and `size`
27822
- * properties.
27823
- */
27824
- class QuerySnapshot {
27825
- /** @hideconstructor */
27826
- constructor(_firestore, _userDataWriter, query, _snapshot) {
27827
- this._firestore = _firestore;
27828
- this._userDataWriter = _userDataWriter;
27829
- this._snapshot = _snapshot;
27830
- this.metadata = new SnapshotMetadata(_snapshot.hasPendingWrites, _snapshot.fromCache);
27831
- this.query = query;
27832
- }
27833
- /** An array of all the documents in the `QuerySnapshot`. */
27834
- get docs() {
27835
- const result = [];
27836
- this.forEach(doc => result.push(doc));
27837
- return result;
27838
- }
27839
- /** The number of documents in the `QuerySnapshot`. */
27840
- get size() {
27841
- return this._snapshot.docs.size;
27842
- }
27843
- /** True if there are no documents in the `QuerySnapshot`. */
27844
- get empty() {
27845
- return this.size === 0;
27846
- }
27847
- /**
27848
- * Enumerates all of the documents in the `QuerySnapshot`.
27849
- *
27850
- * @param callback - A callback to be called with a `QueryDocumentSnapshot` for
27851
- * each document in the snapshot.
27852
- * @param thisArg - The `this` binding for the callback.
27853
- */
27854
- forEach(callback, thisArg) {
27855
- this._snapshot.docs.forEach(doc => {
27856
- callback.call(thisArg, new QueryDocumentSnapshot(this._firestore, this._userDataWriter, doc.key, doc, new SnapshotMetadata(this._snapshot.mutatedKeys.has(doc.key), this._snapshot.fromCache), this.query.converter));
27857
- });
27858
- }
27859
- /**
27860
- * Returns an array of the documents changes since the last snapshot. If this
27861
- * is the first snapshot, all documents will be in the list as 'added'
27862
- * changes.
27863
- *
27864
- * @param options - `SnapshotListenOptions` that control whether metadata-only
27865
- * changes (i.e. only `DocumentSnapshot.metadata` changed) should trigger
27866
- * snapshot events.
27867
- */
27868
- docChanges(options = {}) {
27869
- const includeMetadataChanges = !!options.includeMetadataChanges;
27870
- if (includeMetadataChanges && this._snapshot.excludesMetadataChanges) {
27871
- throw new FirestoreError(Code.INVALID_ARGUMENT, 'To include metadata changes with your document changes, you must ' +
27872
- 'also pass { includeMetadataChanges:true } to onSnapshot().');
27873
- }
27874
- if (!this._cachedChanges ||
27875
- this._cachedChangesIncludeMetadataChanges !== includeMetadataChanges) {
27876
- this._cachedChanges = changesFromSnapshot(this, includeMetadataChanges);
27877
- this._cachedChangesIncludeMetadataChanges = includeMetadataChanges;
27878
- }
27879
- return this._cachedChanges;
27880
- }
27881
- }
27882
- /** Calculates the array of `DocumentChange`s for a given `ViewSnapshot`. */
27883
- function changesFromSnapshot(querySnapshot, includeMetadataChanges) {
27884
- if (querySnapshot._snapshot.oldDocs.isEmpty()) {
27885
- let index = 0;
27886
- return querySnapshot._snapshot.docChanges.map(change => {
27887
- const doc = new QueryDocumentSnapshot(querySnapshot._firestore, querySnapshot._userDataWriter, change.doc.key, change.doc, new SnapshotMetadata(querySnapshot._snapshot.mutatedKeys.has(change.doc.key), querySnapshot._snapshot.fromCache), querySnapshot.query.converter);
27888
- return {
27889
- type: 'added',
27890
- doc,
27891
- oldIndex: -1,
27892
- newIndex: index++
27893
- };
27894
- });
27895
- }
27896
- else {
27897
- // A `DocumentSet` that is updated incrementally as changes are applied to use
27898
- // to lookup the index of a document.
27899
- let indexTracker = querySnapshot._snapshot.oldDocs;
27900
- return querySnapshot._snapshot.docChanges
27901
- .filter(change => includeMetadataChanges || change.type !== 3 /* Metadata */)
27902
- .map(change => {
27903
- const doc = new QueryDocumentSnapshot(querySnapshot._firestore, querySnapshot._userDataWriter, change.doc.key, change.doc, new SnapshotMetadata(querySnapshot._snapshot.mutatedKeys.has(change.doc.key), querySnapshot._snapshot.fromCache), querySnapshot.query.converter);
27904
- let oldIndex = -1;
27905
- let newIndex = -1;
27906
- if (change.type !== 0 /* Added */) {
27907
- oldIndex = indexTracker.indexOf(change.doc.key);
27908
- indexTracker = indexTracker.delete(change.doc.key);
27909
- }
27910
- if (change.type !== 1 /* Removed */) {
27911
- indexTracker = indexTracker.add(change.doc);
27912
- newIndex = indexTracker.indexOf(change.doc.key);
27913
- }
27914
- return {
27915
- type: resultChangeType(change.type),
27916
- doc,
27917
- oldIndex,
27918
- newIndex
27919
- };
27920
- });
27921
- }
27922
- }
27923
- function resultChangeType(type) {
27924
- switch (type) {
27925
- case 0 /* Added */:
27926
- return 'added';
27927
- case 2 /* Modified */:
27928
- case 3 /* Metadata */:
27929
- return 'modified';
27930
- case 1 /* Removed */:
27931
- return 'removed';
27932
- default:
27933
- return fail();
27934
- }
27935
- }
27936
- // TODO(firestoreexp): Add tests for snapshotEqual with different snapshot
27937
- // metadata
27938
- /**
27939
- * Returns true if the provided snapshots are equal.
27940
- *
27941
- * @param left - A snapshot to compare.
27942
- * @param right - A snapshot to compare.
27943
- * @returns true if the snapshots are equal.
27944
- */
27945
- function snapshotEqual(left, right) {
27946
- if (left instanceof DocumentSnapshot && right instanceof DocumentSnapshot) {
27947
- return (left._firestore === right._firestore &&
27948
- left._key.isEqual(right._key) &&
27949
- (left._document === null
27950
- ? right._document === null
27951
- : left._document.isEqual(right._document)) &&
27952
- left._converter === right._converter);
27953
- }
27954
- else if (left instanceof QuerySnapshot && right instanceof QuerySnapshot) {
27955
- return (left._firestore === right._firestore &&
27956
- queryEqual(left.query, right.query) &&
27957
- left.metadata.isEqual(right.metadata) &&
27958
- left._snapshot.isEqual(right._snapshot));
27959
- }
27960
- return false;
27961
- }
27962
-
27963
- /**
27964
- * @license
27965
- * Copyright 2020 Google LLC
27966
- *
27967
- * Licensed under the Apache License, Version 2.0 (the "License");
27968
- * you may not use this file except in compliance with the License.
27969
- * You may obtain a copy of the License at
27970
- *
27971
- * http://www.apache.org/licenses/LICENSE-2.0
27972
- *
27973
- * Unless required by applicable law or agreed to in writing, software
27974
- * distributed under the License is distributed on an "AS IS" BASIS,
27975
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27976
- * See the License for the specific language governing permissions and
27977
- * limitations under the License.
27978
- */
27979
- function validateHasExplicitOrderByForLimitToLast(query) {
27980
- if (query.limitType === "L" /* Last */ &&
27981
- query.explicitOrderBy.length === 0) {
27982
- throw new FirestoreError(Code.UNIMPLEMENTED, 'limitToLast() queries require specifying at least one orderBy() clause');
27983
- }
27984
- }
27985
- /**
27986
- * A `QueryConstraint` is used to narrow the set of documents returned by a
27987
- * Firestore query. `QueryConstraint`s are created by invoking {@link where},
27988
- * {@link orderBy}, {@link (startAt:1)}, {@link (startAfter:1)}, {@link
27989
- * endBefore:1}, {@link (endAt:1)}, {@link limit} or {@link limitToLast} and
27990
- * can then be passed to {@link query} to create a new query instance that
27991
- * also contains this `QueryConstraint`.
27992
- */
27993
- class QueryConstraint {
27994
- }
27995
- /**
27996
- * Creates a new immutable instance of {@link Query} that is extended to also include
27997
- * additional query constraints.
27998
- *
27999
- * @param query - The {@link Query} instance to use as a base for the new constraints.
28000
- * @param queryConstraints - The list of {@link QueryConstraint}s to apply.
28001
- * @throws if any of the provided query constraints cannot be combined with the
28002
- * existing or new constraints.
28003
- */
28004
- function query(query, ...queryConstraints) {
28005
- for (const constraint of queryConstraints) {
28006
- query = constraint._apply(query);
28007
- }
28008
- return query;
28009
- }
28010
- class QueryFilterConstraint extends QueryConstraint {
28011
- constructor(_field, _op, _value) {
28012
- super();
28013
- this._field = _field;
28014
- this._op = _op;
28015
- this._value = _value;
28016
- this.type = 'where';
28017
- }
28018
- _apply(query) {
28019
- const reader = newUserDataReader(query.firestore);
28020
- const filter = newQueryFilter(query._query, 'where', reader, query.firestore._databaseId, this._field, this._op, this._value);
28021
- return new Query(query.firestore, query.converter, queryWithAddedFilter(query._query, filter));
28022
- }
28023
- }
28024
- /**
28025
- * Creates a {@link QueryConstraint} that enforces that documents must contain the
28026
- * specified field and that the value should satisfy the relation constraint
28027
- * provided.
28028
- *
28029
- * @param fieldPath - The path to compare
28030
- * @param opStr - The operation string (e.g "&lt;", "&lt;=", "==", "&lt;",
28031
- * "&lt;=", "!=").
28032
- * @param value - The value for comparison
28033
- * @returns The created {@link Query}.
28034
- */
28035
- function where(fieldPath, opStr, value) {
28036
- const op = opStr;
28037
- const field = fieldPathFromArgument('where', fieldPath);
28038
- return new QueryFilterConstraint(field, op, value);
28039
- }
28040
- class QueryOrderByConstraint extends QueryConstraint {
28041
- constructor(_field, _direction) {
28042
- super();
28043
- this._field = _field;
28044
- this._direction = _direction;
28045
- this.type = 'orderBy';
28046
- }
28047
- _apply(query) {
28048
- const orderBy = newQueryOrderBy(query._query, this._field, this._direction);
28049
- return new Query(query.firestore, query.converter, queryWithAddedOrderBy(query._query, orderBy));
28050
- }
28051
- }
28052
- /**
28053
- * Creates a {@link QueryConstraint} that sorts the query result by the
28054
- * specified field, optionally in descending order instead of ascending.
28055
- *
28056
- * @param fieldPath - The field to sort by.
28057
- * @param directionStr - Optional direction to sort by ('asc' or 'desc'). If
28058
- * not specified, order will be ascending.
28059
- * @returns The created {@link Query}.
28099
+ * Creates a {@link QueryConstraint} that sorts the query result by the
28100
+ * specified field, optionally in descending order instead of ascending.
28101
+ *
28102
+ * @param fieldPath - The field to sort by.
28103
+ * @param directionStr - Optional direction to sort by ('asc' or 'desc'). If
28104
+ * not specified, order will be ascending.
28105
+ * @returns The created {@link Query}.
28060
28106
  */
28061
28107
  function orderBy(fieldPath, directionStr = 'asc') {
28062
28108
  const direction = directionStr;
@@ -28420,31 +28466,6 @@ function validateOrderByAndInequalityMatch(baseQuery, inequality, orderBy) {
28420
28466
  }
28421
28467
  }
28422
28468
 
28423
- /**
28424
- * @license
28425
- * Copyright 2022 Google LLC
28426
- *
28427
- * Licensed under the Apache License, Version 2.0 (the "License");
28428
- * you may not use this file except in compliance with the License.
28429
- * You may obtain a copy of the License at
28430
- *
28431
- * http://www.apache.org/licenses/LICENSE-2.0
28432
- *
28433
- * Unless required by applicable law or agreed to in writing, software
28434
- * distributed under the License is distributed on an "AS IS" BASIS,
28435
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28436
- * See the License for the specific language governing permissions and
28437
- * limitations under the License.
28438
- */
28439
- const DEFAULT_TRANSACTION_OPTIONS = {
28440
- maxAttempts: 5
28441
- };
28442
- function validateTransactionOptions(options) {
28443
- if (options.maxAttempts < 1) {
28444
- throw new FirestoreError(Code.INVALID_ARGUMENT, 'Max attempts must be at least 1');
28445
- }
28446
- }
28447
-
28448
28469
  /**
28449
28470
  * @license
28450
28471
  * Copyright 2020 Google LLC
@@ -28619,221 +28640,276 @@ class LiteUserDataWriter extends AbstractUserDataWriter {
28619
28640
  * limitations under the License.
28620
28641
  */
28621
28642
  /**
28622
- * A write batch, used to perform multiple writes as a single atomic unit.
28623
- *
28624
- * A `WriteBatch` object can be acquired by calling {@link writeBatch}. It
28625
- * provides methods for adding writes to the write batch. None of the writes
28626
- * will be committed (or visible locally) until {@link WriteBatch.commit} is
28627
- * called.
28643
+ * Metadata about a snapshot, describing the state of the snapshot.
28628
28644
  */
28629
- class WriteBatch {
28645
+ class SnapshotMetadata {
28630
28646
  /** @hideconstructor */
28631
- constructor(_firestore, _commitHandler) {
28632
- this._firestore = _firestore;
28633
- this._commitHandler = _commitHandler;
28634
- this._mutations = [];
28635
- this._committed = false;
28636
- this._dataReader = newUserDataReader(_firestore);
28647
+ constructor(hasPendingWrites, fromCache) {
28648
+ this.hasPendingWrites = hasPendingWrites;
28649
+ this.fromCache = fromCache;
28637
28650
  }
28638
- set(documentRef, data, options) {
28639
- this._verifyNotCommitted();
28640
- const ref = validateReference(documentRef, this._firestore);
28641
- const convertedValue = applyFirestoreDataConverter(ref.converter, data, options);
28642
- const parsed = parseSetData(this._dataReader, 'WriteBatch.set', ref._key, convertedValue, ref.converter !== null, options);
28643
- this._mutations.push(parsed.toMutation(ref._key, Precondition.none()));
28644
- return this;
28651
+ /**
28652
+ * Returns true if this `SnapshotMetadata` is equal to the provided one.
28653
+ *
28654
+ * @param other - The `SnapshotMetadata` to compare against.
28655
+ * @returns true if this `SnapshotMetadata` is equal to the provided one.
28656
+ */
28657
+ isEqual(other) {
28658
+ return (this.hasPendingWrites === other.hasPendingWrites &&
28659
+ this.fromCache === other.fromCache);
28645
28660
  }
28646
- update(documentRef, fieldOrUpdateData, value, ...moreFieldsAndValues) {
28647
- this._verifyNotCommitted();
28648
- const ref = validateReference(documentRef, this._firestore);
28649
- // For Compat types, we have to "extract" the underlying types before
28650
- // performing validation.
28651
- fieldOrUpdateData = getModularInstance(fieldOrUpdateData);
28652
- let parsed;
28653
- if (typeof fieldOrUpdateData === 'string' ||
28654
- fieldOrUpdateData instanceof FieldPath) {
28655
- parsed = parseUpdateVarargs(this._dataReader, 'WriteBatch.update', ref._key, fieldOrUpdateData, value, moreFieldsAndValues);
28656
- }
28657
- else {
28658
- parsed = parseUpdateData(this._dataReader, 'WriteBatch.update', ref._key, fieldOrUpdateData);
28659
- }
28660
- this._mutations.push(parsed.toMutation(ref._key, Precondition.exists(true)));
28661
- return this;
28661
+ }
28662
+ /**
28663
+ * A `DocumentSnapshot` contains data read from a document in your Firestore
28664
+ * database. The data can be extracted with `.data()` or `.get(<field>)` to
28665
+ * get a specific field.
28666
+ *
28667
+ * For a `DocumentSnapshot` that points to a non-existing document, any data
28668
+ * access will return 'undefined'. You can use the `exists()` method to
28669
+ * explicitly verify a document's existence.
28670
+ */
28671
+ class DocumentSnapshot extends DocumentSnapshot$1 {
28672
+ /** @hideconstructor protected */
28673
+ constructor(_firestore, userDataWriter, key, document, metadata, converter) {
28674
+ super(_firestore, userDataWriter, key, document, converter);
28675
+ this._firestore = _firestore;
28676
+ this._firestoreImpl = _firestore;
28677
+ this.metadata = metadata;
28662
28678
  }
28663
28679
  /**
28664
- * Deletes the document referred to by the provided {@link DocumentReference}.
28665
- *
28666
- * @param documentRef - A reference to the document to be deleted.
28667
- * @returns This `WriteBatch` instance. Used for chaining method calls.
28680
+ * Returns whether or not the data exists. True if the document exists.
28668
28681
  */
28669
- delete(documentRef) {
28670
- this._verifyNotCommitted();
28671
- const ref = validateReference(documentRef, this._firestore);
28672
- this._mutations = this._mutations.concat(new DeleteMutation(ref._key, Precondition.none()));
28673
- return this;
28682
+ exists() {
28683
+ return super.exists();
28674
28684
  }
28675
28685
  /**
28676
- * Commits all of the writes in this write batch as a single atomic unit.
28686
+ * Retrieves all fields in the document as an `Object`. Returns `undefined` if
28687
+ * the document doesn't exist.
28677
28688
  *
28678
- * The result of these writes will only be reflected in document reads that
28679
- * occur after the returned promise resolves. If the client is offline, the
28680
- * write fails. If you would like to see local modifications or buffer writes
28681
- * until the client is online, use the full Firestore SDK.
28689
+ * By default, `serverTimestamp()` values that have not yet been
28690
+ * set to their final value will be returned as `null`. You can override
28691
+ * this by passing an options object.
28682
28692
  *
28683
- * @returns A `Promise` resolved once all of the writes in the batch have been
28684
- * successfully written to the backend as an atomic unit (note that it won't
28685
- * resolve while you're offline).
28693
+ * @param options - An options object to configure how data is retrieved from
28694
+ * the snapshot (for example the desired behavior for server timestamps that
28695
+ * have not yet been set to their final value).
28696
+ * @returns An `Object` containing all fields in the document or `undefined` if
28697
+ * the document doesn't exist.
28686
28698
  */
28687
- commit() {
28688
- this._verifyNotCommitted();
28689
- this._committed = true;
28690
- if (this._mutations.length > 0) {
28691
- return this._commitHandler(this._mutations);
28699
+ data(options = {}) {
28700
+ if (!this._document) {
28701
+ return undefined;
28702
+ }
28703
+ else if (this._converter) {
28704
+ // We only want to use the converter and create a new DocumentSnapshot
28705
+ // if a converter has been provided.
28706
+ const snapshot = new QueryDocumentSnapshot(this._firestore, this._userDataWriter, this._key, this._document, this.metadata,
28707
+ /* converter= */ null);
28708
+ return this._converter.fromFirestore(snapshot, options);
28709
+ }
28710
+ else {
28711
+ return this._userDataWriter.convertValue(this._document.data.value, options.serverTimestamps);
28692
28712
  }
28693
- return Promise.resolve();
28694
28713
  }
28695
- _verifyNotCommitted() {
28696
- if (this._committed) {
28697
- throw new FirestoreError(Code.FAILED_PRECONDITION, 'A write batch can no longer be used after commit() ' +
28698
- 'has been called.');
28714
+ /**
28715
+ * Retrieves the field specified by `fieldPath`. Returns `undefined` if the
28716
+ * document or field doesn't exist.
28717
+ *
28718
+ * By default, a `serverTimestamp()` that has not yet been set to
28719
+ * its final value will be returned as `null`. You can override this by
28720
+ * passing an options object.
28721
+ *
28722
+ * @param fieldPath - The path (for example 'foo' or 'foo.bar') to a specific
28723
+ * field.
28724
+ * @param options - An options object to configure how the field is retrieved
28725
+ * from the snapshot (for example the desired behavior for server timestamps
28726
+ * that have not yet been set to their final value).
28727
+ * @returns The data at the specified field location or undefined if no such
28728
+ * field exists in the document.
28729
+ */
28730
+ // We are using `any` here to avoid an explicit cast by our users.
28731
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28732
+ get(fieldPath, options = {}) {
28733
+ if (this._document) {
28734
+ const value = this._document.data.field(fieldPathFromArgument('DocumentSnapshot.get', fieldPath));
28735
+ if (value !== null) {
28736
+ return this._userDataWriter.convertValue(value, options.serverTimestamps);
28737
+ }
28699
28738
  }
28739
+ return undefined;
28700
28740
  }
28701
28741
  }
28702
- function validateReference(documentRef, firestore) {
28703
- documentRef = getModularInstance(documentRef);
28704
- if (documentRef.firestore !== firestore) {
28705
- throw new FirestoreError(Code.INVALID_ARGUMENT, 'Provided document reference is from a different Firestore instance.');
28706
- }
28707
- else {
28708
- return documentRef;
28709
- }
28710
- }
28711
-
28712
28742
  /**
28713
- * @license
28714
- * Copyright 2020 Google LLC
28715
- *
28716
- * Licensed under the Apache License, Version 2.0 (the "License");
28717
- * you may not use this file except in compliance with the License.
28718
- * You may obtain a copy of the License at
28719
- *
28720
- * http://www.apache.org/licenses/LICENSE-2.0
28743
+ * A `QueryDocumentSnapshot` contains data read from a document in your
28744
+ * Firestore database as part of a query. The document is guaranteed to exist
28745
+ * and its data can be extracted with `.data()` or `.get(<field>)` to get a
28746
+ * specific field.
28721
28747
  *
28722
- * Unless required by applicable law or agreed to in writing, software
28723
- * distributed under the License is distributed on an "AS IS" BASIS,
28724
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28725
- * See the License for the specific language governing permissions and
28726
- * limitations under the License.
28748
+ * A `QueryDocumentSnapshot` offers the same API surface as a
28749
+ * `DocumentSnapshot`. Since query results contain only existing documents, the
28750
+ * `exists` property will always be true and `data()` will never return
28751
+ * 'undefined'.
28727
28752
  */
28728
- // TODO(mrschmidt) Consider using `BaseTransaction` as the base class in the
28729
- // legacy SDK.
28753
+ class QueryDocumentSnapshot extends DocumentSnapshot {
28754
+ /**
28755
+ * Retrieves all fields in the document as an `Object`.
28756
+ *
28757
+ * By default, `serverTimestamp()` values that have not yet been
28758
+ * set to their final value will be returned as `null`. You can override
28759
+ * this by passing an options object.
28760
+ *
28761
+ * @override
28762
+ * @param options - An options object to configure how data is retrieved from
28763
+ * the snapshot (for example the desired behavior for server timestamps that
28764
+ * have not yet been set to their final value).
28765
+ * @returns An `Object` containing all fields in the document.
28766
+ */
28767
+ data(options = {}) {
28768
+ return super.data(options);
28769
+ }
28770
+ }
28730
28771
  /**
28731
- * A reference to a transaction.
28732
- *
28733
- * The `Transaction` object passed to a transaction's `updateFunction` provides
28734
- * the methods to read and write data within the transaction context. See
28735
- * {@link runTransaction}.
28772
+ * A `QuerySnapshot` contains zero or more `DocumentSnapshot` objects
28773
+ * representing the results of a query. The documents can be accessed as an
28774
+ * array via the `docs` property or enumerated using the `forEach` method. The
28775
+ * number of documents can be determined via the `empty` and `size`
28776
+ * properties.
28736
28777
  */
28737
- class Transaction$1 {
28778
+ class QuerySnapshot {
28738
28779
  /** @hideconstructor */
28739
- constructor(_firestore, _transaction) {
28780
+ constructor(_firestore, _userDataWriter, query, _snapshot) {
28740
28781
  this._firestore = _firestore;
28741
- this._transaction = _transaction;
28742
- this._dataReader = newUserDataReader(_firestore);
28782
+ this._userDataWriter = _userDataWriter;
28783
+ this._snapshot = _snapshot;
28784
+ this.metadata = new SnapshotMetadata(_snapshot.hasPendingWrites, _snapshot.fromCache);
28785
+ this.query = query;
28786
+ }
28787
+ /** An array of all the documents in the `QuerySnapshot`. */
28788
+ get docs() {
28789
+ const result = [];
28790
+ this.forEach(doc => result.push(doc));
28791
+ return result;
28792
+ }
28793
+ /** The number of documents in the `QuerySnapshot`. */
28794
+ get size() {
28795
+ return this._snapshot.docs.size;
28796
+ }
28797
+ /** True if there are no documents in the `QuerySnapshot`. */
28798
+ get empty() {
28799
+ return this.size === 0;
28743
28800
  }
28744
28801
  /**
28745
- * Reads the document referenced by the provided {@link DocumentReference}.
28802
+ * Enumerates all of the documents in the `QuerySnapshot`.
28746
28803
  *
28747
- * @param documentRef - A reference to the document to be read.
28748
- * @returns A `DocumentSnapshot` with the read data.
28804
+ * @param callback - A callback to be called with a `QueryDocumentSnapshot` for
28805
+ * each document in the snapshot.
28806
+ * @param thisArg - The `this` binding for the callback.
28749
28807
  */
28750
- get(documentRef) {
28751
- const ref = validateReference(documentRef, this._firestore);
28752
- const userDataWriter = new LiteUserDataWriter(this._firestore);
28753
- return this._transaction.lookup([ref._key]).then(docs => {
28754
- if (!docs || docs.length !== 1) {
28755
- return fail();
28756
- }
28757
- const doc = docs[0];
28758
- if (doc.isFoundDocument()) {
28759
- return new DocumentSnapshot$1(this._firestore, userDataWriter, doc.key, doc, ref.converter);
28760
- }
28761
- else if (doc.isNoDocument()) {
28762
- return new DocumentSnapshot$1(this._firestore, userDataWriter, ref._key, null, ref.converter);
28763
- }
28764
- else {
28765
- throw fail();
28766
- }
28808
+ forEach(callback, thisArg) {
28809
+ this._snapshot.docs.forEach(doc => {
28810
+ callback.call(thisArg, new QueryDocumentSnapshot(this._firestore, this._userDataWriter, doc.key, doc, new SnapshotMetadata(this._snapshot.mutatedKeys.has(doc.key), this._snapshot.fromCache), this.query.converter));
28767
28811
  });
28768
28812
  }
28769
- set(documentRef, value, options) {
28770
- const ref = validateReference(documentRef, this._firestore);
28771
- const convertedValue = applyFirestoreDataConverter(ref.converter, value, options);
28772
- const parsed = parseSetData(this._dataReader, 'Transaction.set', ref._key, convertedValue, ref.converter !== null, options);
28773
- this._transaction.set(ref._key, parsed);
28774
- return this;
28775
- }
28776
- update(documentRef, fieldOrUpdateData, value, ...moreFieldsAndValues) {
28777
- const ref = validateReference(documentRef, this._firestore);
28778
- // For Compat types, we have to "extract" the underlying types before
28779
- // performing validation.
28780
- fieldOrUpdateData = getModularInstance(fieldOrUpdateData);
28781
- let parsed;
28782
- if (typeof fieldOrUpdateData === 'string' ||
28783
- fieldOrUpdateData instanceof FieldPath) {
28784
- parsed = parseUpdateVarargs(this._dataReader, 'Transaction.update', ref._key, fieldOrUpdateData, value, moreFieldsAndValues);
28785
- }
28786
- else {
28787
- parsed = parseUpdateData(this._dataReader, 'Transaction.update', ref._key, fieldOrUpdateData);
28788
- }
28789
- this._transaction.update(ref._key, parsed);
28790
- return this;
28791
- }
28792
28813
  /**
28793
- * Deletes the document referred to by the provided {@link DocumentReference}.
28814
+ * Returns an array of the documents changes since the last snapshot. If this
28815
+ * is the first snapshot, all documents will be in the list as 'added'
28816
+ * changes.
28794
28817
  *
28795
- * @param documentRef - A reference to the document to be deleted.
28796
- * @returns This `Transaction` instance. Used for chaining method calls.
28818
+ * @param options - `SnapshotListenOptions` that control whether metadata-only
28819
+ * changes (i.e. only `DocumentSnapshot.metadata` changed) should trigger
28820
+ * snapshot events.
28797
28821
  */
28798
- delete(documentRef) {
28799
- const ref = validateReference(documentRef, this._firestore);
28800
- this._transaction.delete(ref._key);
28801
- return this;
28822
+ docChanges(options = {}) {
28823
+ const includeMetadataChanges = !!options.includeMetadataChanges;
28824
+ if (includeMetadataChanges && this._snapshot.excludesMetadataChanges) {
28825
+ throw new FirestoreError(Code.INVALID_ARGUMENT, 'To include metadata changes with your document changes, you must ' +
28826
+ 'also pass { includeMetadataChanges:true } to onSnapshot().');
28827
+ }
28828
+ if (!this._cachedChanges ||
28829
+ this._cachedChangesIncludeMetadataChanges !== includeMetadataChanges) {
28830
+ this._cachedChanges = changesFromSnapshot(this, includeMetadataChanges);
28831
+ this._cachedChangesIncludeMetadataChanges = includeMetadataChanges;
28832
+ }
28833
+ return this._cachedChanges;
28834
+ }
28835
+ }
28836
+ /** Calculates the array of `DocumentChange`s for a given `ViewSnapshot`. */
28837
+ function changesFromSnapshot(querySnapshot, includeMetadataChanges) {
28838
+ if (querySnapshot._snapshot.oldDocs.isEmpty()) {
28839
+ let index = 0;
28840
+ return querySnapshot._snapshot.docChanges.map(change => {
28841
+ const doc = new QueryDocumentSnapshot(querySnapshot._firestore, querySnapshot._userDataWriter, change.doc.key, change.doc, new SnapshotMetadata(querySnapshot._snapshot.mutatedKeys.has(change.doc.key), querySnapshot._snapshot.fromCache), querySnapshot.query.converter);
28842
+ return {
28843
+ type: 'added',
28844
+ doc,
28845
+ oldIndex: -1,
28846
+ newIndex: index++
28847
+ };
28848
+ });
28849
+ }
28850
+ else {
28851
+ // A `DocumentSet` that is updated incrementally as changes are applied to use
28852
+ // to lookup the index of a document.
28853
+ let indexTracker = querySnapshot._snapshot.oldDocs;
28854
+ return querySnapshot._snapshot.docChanges
28855
+ .filter(change => includeMetadataChanges || change.type !== 3 /* Metadata */)
28856
+ .map(change => {
28857
+ const doc = new QueryDocumentSnapshot(querySnapshot._firestore, querySnapshot._userDataWriter, change.doc.key, change.doc, new SnapshotMetadata(querySnapshot._snapshot.mutatedKeys.has(change.doc.key), querySnapshot._snapshot.fromCache), querySnapshot.query.converter);
28858
+ let oldIndex = -1;
28859
+ let newIndex = -1;
28860
+ if (change.type !== 0 /* Added */) {
28861
+ oldIndex = indexTracker.indexOf(change.doc.key);
28862
+ indexTracker = indexTracker.delete(change.doc.key);
28863
+ }
28864
+ if (change.type !== 1 /* Removed */) {
28865
+ indexTracker = indexTracker.add(change.doc);
28866
+ newIndex = indexTracker.indexOf(change.doc.key);
28867
+ }
28868
+ return {
28869
+ type: resultChangeType(change.type),
28870
+ doc,
28871
+ oldIndex,
28872
+ newIndex
28873
+ };
28874
+ });
28875
+ }
28876
+ }
28877
+ function resultChangeType(type) {
28878
+ switch (type) {
28879
+ case 0 /* Added */:
28880
+ return 'added';
28881
+ case 2 /* Modified */:
28882
+ case 3 /* Metadata */:
28883
+ return 'modified';
28884
+ case 1 /* Removed */:
28885
+ return 'removed';
28886
+ default:
28887
+ return fail();
28802
28888
  }
28803
- }
28804
-
28805
- /**
28806
- * @license
28807
- * Copyright 2017 Google LLC
28808
- *
28809
- * Licensed under the Apache License, Version 2.0 (the "License");
28810
- * you may not use this file except in compliance with the License.
28811
- * You may obtain a copy of the License at
28812
- *
28813
- * http://www.apache.org/licenses/LICENSE-2.0
28814
- *
28815
- * Unless required by applicable law or agreed to in writing, software
28816
- * distributed under the License is distributed on an "AS IS" BASIS,
28817
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28818
- * See the License for the specific language governing permissions and
28819
- * limitations under the License.
28820
- */
28821
- function isPartialObserver(obj) {
28822
- return implementsAnyMethods(obj, ['next', 'error', 'complete']);
28823
28889
  }
28890
+ // TODO(firestoreexp): Add tests for snapshotEqual with different snapshot
28891
+ // metadata
28824
28892
  /**
28825
- * Returns true if obj is an object and contains at least one of the specified
28826
- * methods.
28893
+ * Returns true if the provided snapshots are equal.
28894
+ *
28895
+ * @param left - A snapshot to compare.
28896
+ * @param right - A snapshot to compare.
28897
+ * @returns true if the snapshots are equal.
28827
28898
  */
28828
- function implementsAnyMethods(obj, methods) {
28829
- if (typeof obj !== 'object' || obj === null) {
28830
- return false;
28899
+ function snapshotEqual(left, right) {
28900
+ if (left instanceof DocumentSnapshot && right instanceof DocumentSnapshot) {
28901
+ return (left._firestore === right._firestore &&
28902
+ left._key.isEqual(right._key) &&
28903
+ (left._document === null
28904
+ ? right._document === null
28905
+ : left._document.isEqual(right._document)) &&
28906
+ left._converter === right._converter);
28831
28907
  }
28832
- const object = obj;
28833
- for (const method of methods) {
28834
- if (method in object && typeof object[method] === 'function') {
28835
- return true;
28836
- }
28908
+ else if (left instanceof QuerySnapshot && right instanceof QuerySnapshot) {
28909
+ return (left._firestore === right._firestore &&
28910
+ queryEqual(left.query, right.query) &&
28911
+ left.metadata.isEqual(right.metadata) &&
28912
+ left._snapshot.isEqual(right._snapshot));
28837
28913
  }
28838
28914
  return false;
28839
28915
  }
@@ -29102,6 +29178,307 @@ function convertToDocSnapshot(firestore, ref, snapshot) {
29102
29178
  return new DocumentSnapshot(firestore, userDataWriter, ref._key, doc, new SnapshotMetadata(snapshot.hasPendingWrites, snapshot.fromCache), ref.converter);
29103
29179
  }
29104
29180
 
29181
+ /**
29182
+ * @license
29183
+ * Copyright 2022 Google LLC
29184
+ *
29185
+ * Licensed under the Apache License, Version 2.0 (the "License");
29186
+ * you may not use this file except in compliance with the License.
29187
+ * You may obtain a copy of the License at
29188
+ *
29189
+ * http://www.apache.org/licenses/LICENSE-2.0
29190
+ *
29191
+ * Unless required by applicable law or agreed to in writing, software
29192
+ * distributed under the License is distributed on an "AS IS" BASIS,
29193
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29194
+ * See the License for the specific language governing permissions and
29195
+ * limitations under the License.
29196
+ */
29197
+ /**
29198
+ * Compares two `AggregateQuerySnapshot` instances for equality.
29199
+ *
29200
+ * Two `AggregateQuerySnapshot` instances are considered "equal" if they have
29201
+ * underlying queries that compare equal, and the same data.
29202
+ *
29203
+ * @param left - The first `AggregateQuerySnapshot` to compare.
29204
+ * @param right - The second `AggregateQuerySnapshot` to compare.
29205
+ *
29206
+ * @returns `true` if the objects are "equal", as defined above, or `false`
29207
+ * otherwise.
29208
+ */
29209
+ function aggregateQuerySnapshotEqual(left, right) {
29210
+ return (queryEqual(left.query, right.query) && deepEqual(left.data(), right.data()));
29211
+ }
29212
+
29213
+ /**
29214
+ * @license
29215
+ * Copyright 2022 Google LLC
29216
+ *
29217
+ * Licensed under the Apache License, Version 2.0 (the "License");
29218
+ * you may not use this file except in compliance with the License.
29219
+ * You may obtain a copy of the License at
29220
+ *
29221
+ * http://www.apache.org/licenses/LICENSE-2.0
29222
+ *
29223
+ * Unless required by applicable law or agreed to in writing, software
29224
+ * distributed under the License is distributed on an "AS IS" BASIS,
29225
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29226
+ * See the License for the specific language governing permissions and
29227
+ * limitations under the License.
29228
+ */
29229
+ /**
29230
+ * Calculates the number of documents in the result set of the given query,
29231
+ * without actually downloading the documents.
29232
+ *
29233
+ * Using this function to count the documents is efficient because only the
29234
+ * final count, not the documents' data, is downloaded. This function can even
29235
+ * count the documents if the result set would be prohibitively large to
29236
+ * download entirely (e.g. thousands of documents).
29237
+ *
29238
+ * The result received from the server is presented, unaltered, without
29239
+ * considering any local state. That is, documents in the local cache are not
29240
+ * taken into consideration, neither are local modifications not yet
29241
+ * synchronized with the server. Previously-downloaded results, if any, are not
29242
+ * used: every request using this source necessarily involves a round trip to
29243
+ * the server.
29244
+ *
29245
+ * @param query - The query whose result set size to calculate.
29246
+ * @returns A Promise that will be resolved with the count; the count can be
29247
+ * retrieved from `snapshot.data().count`, where `snapshot` is the
29248
+ * `AggregateQuerySnapshot` to which the returned Promise resolves.
29249
+ */
29250
+ function getCountFromServer(query) {
29251
+ const firestore = cast(query.firestore, Firestore);
29252
+ const client = ensureFirestoreConfigured(firestore);
29253
+ const userDataWriter = new ExpUserDataWriter(firestore);
29254
+ return firestoreClientRunCountQuery(client, query, userDataWriter);
29255
+ }
29256
+
29257
+ /**
29258
+ * @license
29259
+ * Copyright 2022 Google LLC
29260
+ *
29261
+ * Licensed under the Apache License, Version 2.0 (the "License");
29262
+ * you may not use this file except in compliance with the License.
29263
+ * You may obtain a copy of the License at
29264
+ *
29265
+ * http://www.apache.org/licenses/LICENSE-2.0
29266
+ *
29267
+ * Unless required by applicable law or agreed to in writing, software
29268
+ * distributed under the License is distributed on an "AS IS" BASIS,
29269
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29270
+ * See the License for the specific language governing permissions and
29271
+ * limitations under the License.
29272
+ */
29273
+ const DEFAULT_TRANSACTION_OPTIONS = {
29274
+ maxAttempts: 5
29275
+ };
29276
+ function validateTransactionOptions(options) {
29277
+ if (options.maxAttempts < 1) {
29278
+ throw new FirestoreError(Code.INVALID_ARGUMENT, 'Max attempts must be at least 1');
29279
+ }
29280
+ }
29281
+
29282
+ /**
29283
+ * @license
29284
+ * Copyright 2020 Google LLC
29285
+ *
29286
+ * Licensed under the Apache License, Version 2.0 (the "License");
29287
+ * you may not use this file except in compliance with the License.
29288
+ * You may obtain a copy of the License at
29289
+ *
29290
+ * http://www.apache.org/licenses/LICENSE-2.0
29291
+ *
29292
+ * Unless required by applicable law or agreed to in writing, software
29293
+ * distributed under the License is distributed on an "AS IS" BASIS,
29294
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29295
+ * See the License for the specific language governing permissions and
29296
+ * limitations under the License.
29297
+ */
29298
+ /**
29299
+ * A write batch, used to perform multiple writes as a single atomic unit.
29300
+ *
29301
+ * A `WriteBatch` object can be acquired by calling {@link writeBatch}. It
29302
+ * provides methods for adding writes to the write batch. None of the writes
29303
+ * will be committed (or visible locally) until {@link WriteBatch.commit} is
29304
+ * called.
29305
+ */
29306
+ class WriteBatch {
29307
+ /** @hideconstructor */
29308
+ constructor(_firestore, _commitHandler) {
29309
+ this._firestore = _firestore;
29310
+ this._commitHandler = _commitHandler;
29311
+ this._mutations = [];
29312
+ this._committed = false;
29313
+ this._dataReader = newUserDataReader(_firestore);
29314
+ }
29315
+ set(documentRef, data, options) {
29316
+ this._verifyNotCommitted();
29317
+ const ref = validateReference(documentRef, this._firestore);
29318
+ const convertedValue = applyFirestoreDataConverter(ref.converter, data, options);
29319
+ const parsed = parseSetData(this._dataReader, 'WriteBatch.set', ref._key, convertedValue, ref.converter !== null, options);
29320
+ this._mutations.push(parsed.toMutation(ref._key, Precondition.none()));
29321
+ return this;
29322
+ }
29323
+ update(documentRef, fieldOrUpdateData, value, ...moreFieldsAndValues) {
29324
+ this._verifyNotCommitted();
29325
+ const ref = validateReference(documentRef, this._firestore);
29326
+ // For Compat types, we have to "extract" the underlying types before
29327
+ // performing validation.
29328
+ fieldOrUpdateData = getModularInstance(fieldOrUpdateData);
29329
+ let parsed;
29330
+ if (typeof fieldOrUpdateData === 'string' ||
29331
+ fieldOrUpdateData instanceof FieldPath) {
29332
+ parsed = parseUpdateVarargs(this._dataReader, 'WriteBatch.update', ref._key, fieldOrUpdateData, value, moreFieldsAndValues);
29333
+ }
29334
+ else {
29335
+ parsed = parseUpdateData(this._dataReader, 'WriteBatch.update', ref._key, fieldOrUpdateData);
29336
+ }
29337
+ this._mutations.push(parsed.toMutation(ref._key, Precondition.exists(true)));
29338
+ return this;
29339
+ }
29340
+ /**
29341
+ * Deletes the document referred to by the provided {@link DocumentReference}.
29342
+ *
29343
+ * @param documentRef - A reference to the document to be deleted.
29344
+ * @returns This `WriteBatch` instance. Used for chaining method calls.
29345
+ */
29346
+ delete(documentRef) {
29347
+ this._verifyNotCommitted();
29348
+ const ref = validateReference(documentRef, this._firestore);
29349
+ this._mutations = this._mutations.concat(new DeleteMutation(ref._key, Precondition.none()));
29350
+ return this;
29351
+ }
29352
+ /**
29353
+ * Commits all of the writes in this write batch as a single atomic unit.
29354
+ *
29355
+ * The result of these writes will only be reflected in document reads that
29356
+ * occur after the returned promise resolves. If the client is offline, the
29357
+ * write fails. If you would like to see local modifications or buffer writes
29358
+ * until the client is online, use the full Firestore SDK.
29359
+ *
29360
+ * @returns A `Promise` resolved once all of the writes in the batch have been
29361
+ * successfully written to the backend as an atomic unit (note that it won't
29362
+ * resolve while you're offline).
29363
+ */
29364
+ commit() {
29365
+ this._verifyNotCommitted();
29366
+ this._committed = true;
29367
+ if (this._mutations.length > 0) {
29368
+ return this._commitHandler(this._mutations);
29369
+ }
29370
+ return Promise.resolve();
29371
+ }
29372
+ _verifyNotCommitted() {
29373
+ if (this._committed) {
29374
+ throw new FirestoreError(Code.FAILED_PRECONDITION, 'A write batch can no longer be used after commit() ' +
29375
+ 'has been called.');
29376
+ }
29377
+ }
29378
+ }
29379
+ function validateReference(documentRef, firestore) {
29380
+ documentRef = getModularInstance(documentRef);
29381
+ if (documentRef.firestore !== firestore) {
29382
+ throw new FirestoreError(Code.INVALID_ARGUMENT, 'Provided document reference is from a different Firestore instance.');
29383
+ }
29384
+ else {
29385
+ return documentRef;
29386
+ }
29387
+ }
29388
+
29389
+ /**
29390
+ * @license
29391
+ * Copyright 2020 Google LLC
29392
+ *
29393
+ * Licensed under the Apache License, Version 2.0 (the "License");
29394
+ * you may not use this file except in compliance with the License.
29395
+ * You may obtain a copy of the License at
29396
+ *
29397
+ * http://www.apache.org/licenses/LICENSE-2.0
29398
+ *
29399
+ * Unless required by applicable law or agreed to in writing, software
29400
+ * distributed under the License is distributed on an "AS IS" BASIS,
29401
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29402
+ * See the License for the specific language governing permissions and
29403
+ * limitations under the License.
29404
+ */
29405
+ // TODO(mrschmidt) Consider using `BaseTransaction` as the base class in the
29406
+ // legacy SDK.
29407
+ /**
29408
+ * A reference to a transaction.
29409
+ *
29410
+ * The `Transaction` object passed to a transaction's `updateFunction` provides
29411
+ * the methods to read and write data within the transaction context. See
29412
+ * {@link runTransaction}.
29413
+ */
29414
+ class Transaction$1 {
29415
+ /** @hideconstructor */
29416
+ constructor(_firestore, _transaction) {
29417
+ this._firestore = _firestore;
29418
+ this._transaction = _transaction;
29419
+ this._dataReader = newUserDataReader(_firestore);
29420
+ }
29421
+ /**
29422
+ * Reads the document referenced by the provided {@link DocumentReference}.
29423
+ *
29424
+ * @param documentRef - A reference to the document to be read.
29425
+ * @returns A `DocumentSnapshot` with the read data.
29426
+ */
29427
+ get(documentRef) {
29428
+ const ref = validateReference(documentRef, this._firestore);
29429
+ const userDataWriter = new LiteUserDataWriter(this._firestore);
29430
+ return this._transaction.lookup([ref._key]).then(docs => {
29431
+ if (!docs || docs.length !== 1) {
29432
+ return fail();
29433
+ }
29434
+ const doc = docs[0];
29435
+ if (doc.isFoundDocument()) {
29436
+ return new DocumentSnapshot$1(this._firestore, userDataWriter, doc.key, doc, ref.converter);
29437
+ }
29438
+ else if (doc.isNoDocument()) {
29439
+ return new DocumentSnapshot$1(this._firestore, userDataWriter, ref._key, null, ref.converter);
29440
+ }
29441
+ else {
29442
+ throw fail();
29443
+ }
29444
+ });
29445
+ }
29446
+ set(documentRef, value, options) {
29447
+ const ref = validateReference(documentRef, this._firestore);
29448
+ const convertedValue = applyFirestoreDataConverter(ref.converter, value, options);
29449
+ const parsed = parseSetData(this._dataReader, 'Transaction.set', ref._key, convertedValue, ref.converter !== null, options);
29450
+ this._transaction.set(ref._key, parsed);
29451
+ return this;
29452
+ }
29453
+ update(documentRef, fieldOrUpdateData, value, ...moreFieldsAndValues) {
29454
+ const ref = validateReference(documentRef, this._firestore);
29455
+ // For Compat types, we have to "extract" the underlying types before
29456
+ // performing validation.
29457
+ fieldOrUpdateData = getModularInstance(fieldOrUpdateData);
29458
+ let parsed;
29459
+ if (typeof fieldOrUpdateData === 'string' ||
29460
+ fieldOrUpdateData instanceof FieldPath) {
29461
+ parsed = parseUpdateVarargs(this._dataReader, 'Transaction.update', ref._key, fieldOrUpdateData, value, moreFieldsAndValues);
29462
+ }
29463
+ else {
29464
+ parsed = parseUpdateData(this._dataReader, 'Transaction.update', ref._key, fieldOrUpdateData);
29465
+ }
29466
+ this._transaction.update(ref._key, parsed);
29467
+ return this;
29468
+ }
29469
+ /**
29470
+ * Deletes the document referred to by the provided {@link DocumentReference}.
29471
+ *
29472
+ * @param documentRef - A reference to the document to be deleted.
29473
+ * @returns This `Transaction` instance. Used for chaining method calls.
29474
+ */
29475
+ delete(documentRef) {
29476
+ const ref = validateReference(documentRef, this._firestore);
29477
+ this._transaction.delete(ref._key);
29478
+ return this;
29479
+ }
29480
+ }
29481
+
29105
29482
  /**
29106
29483
  * @license
29107
29484
  * Copyright 2020 Google LLC
@@ -29387,5 +29764,5 @@ function tryGetString(data, property) {
29387
29764
  */
29388
29765
  registerFirestore('node');
29389
29766
 
29390
- export { AbstractUserDataWriter, Bytes, CACHE_SIZE_UNLIMITED, CollectionReference, DocumentReference, DocumentSnapshot, FieldPath, FieldValue, Firestore, FirestoreError, GeoPoint, LoadBundleTask, Query, QueryConstraint, QueryDocumentSnapshot, QuerySnapshot, SnapshotMetadata, Timestamp, Transaction, WriteBatch, DatabaseId as _DatabaseId, DocumentKey as _DocumentKey, EmptyAppCheckTokenProvider as _EmptyAppCheckTokenProvider, EmptyAuthCredentialsProvider as _EmptyAuthCredentialsProvider, FieldPath$1 as _FieldPath, cast as _cast, debugAssert as _debugAssert, isBase64Available as _isBase64Available, logWarn as _logWarn, validateIsNotUsedTogether as _validateIsNotUsedTogether, addDoc, arrayRemove, arrayUnion, clearIndexedDbPersistence, collection, collectionGroup, connectFirestoreEmulator, deleteDoc, deleteField, disableNetwork, doc, documentId, enableIndexedDbPersistence, enableMultiTabIndexedDbPersistence, enableNetwork, endAt, endBefore, ensureFirestoreConfigured, executeWrite, getDoc, getDocFromCache, getDocFromServer, getDocs, getDocsFromCache, getDocsFromServer, getFirestore, increment, initializeFirestore, limit, limitToLast, loadBundle, namedQuery, onSnapshot, onSnapshotsInSync, orderBy, query, queryEqual, refEqual, runTransaction, serverTimestamp, setDoc, setIndexConfiguration, setLogLevel, snapshotEqual, startAfter, startAt, terminate, updateDoc, waitForPendingWrites, where, writeBatch };
29767
+ export { AbstractUserDataWriter, AggregateField, AggregateQuerySnapshot, Bytes, CACHE_SIZE_UNLIMITED, CollectionReference, DocumentReference, DocumentSnapshot, FieldPath, FieldValue, Firestore, FirestoreError, GeoPoint, LoadBundleTask, Query, QueryConstraint, QueryDocumentSnapshot, QuerySnapshot, SnapshotMetadata, Timestamp, Transaction, WriteBatch, DatabaseId as _DatabaseId, DocumentKey as _DocumentKey, EmptyAppCheckTokenProvider as _EmptyAppCheckTokenProvider, EmptyAuthCredentialsProvider as _EmptyAuthCredentialsProvider, FieldPath$1 as _FieldPath, cast as _cast, debugAssert as _debugAssert, isBase64Available as _isBase64Available, logWarn as _logWarn, validateIsNotUsedTogether as _validateIsNotUsedTogether, addDoc, aggregateQuerySnapshotEqual, arrayRemove, arrayUnion, clearIndexedDbPersistence, collection, collectionGroup, connectFirestoreEmulator, deleteDoc, deleteField, disableNetwork, doc, documentId, enableIndexedDbPersistence, enableMultiTabIndexedDbPersistence, enableNetwork, endAt, endBefore, ensureFirestoreConfigured, executeWrite, getCountFromServer, getDoc, getDocFromCache, getDocFromServer, getDocs, getDocsFromCache, getDocsFromServer, getFirestore, increment, initializeFirestore, limit, limitToLast, loadBundle, namedQuery, onSnapshot, onSnapshotsInSync, orderBy, query, queryEqual, refEqual, runTransaction, serverTimestamp, setDoc, setIndexConfiguration, setLogLevel, snapshotEqual, startAfter, startAt, terminate, updateDoc, waitForPendingWrites, where, writeBatch };
29391
29768
  //# sourceMappingURL=index.node.mjs.map