FSTLocalDocumentsView.mm 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "Firestore/Source/Local/FSTLocalDocumentsView.h"
  17. #include <vector>
  18. #import "Firestore/Source/Core/FSTQuery.h"
  19. #import "Firestore/Source/Model/FSTDocument.h"
  20. #import "Firestore/Source/Model/FSTMutation.h"
  21. #import "Firestore/Source/Model/FSTMutationBatch.h"
  22. #include "Firestore/core/src/firebase/firestore/local/mutation_queue.h"
  23. #include "Firestore/core/src/firebase/firestore/local/remote_document_cache.h"
  24. #include "Firestore/core/src/firebase/firestore/model/document_key.h"
  25. #include "Firestore/core/src/firebase/firestore/model/document_map.h"
  26. #include "Firestore/core/src/firebase/firestore/model/resource_path.h"
  27. #include "Firestore/core/src/firebase/firestore/model/snapshot_version.h"
  28. #include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
  29. using firebase::firestore::local::MutationQueue;
  30. using firebase::firestore::local::RemoteDocumentCache;
  31. using firebase::firestore::model::DocumentKey;
  32. using firebase::firestore::model::DocumentKeySet;
  33. using firebase::firestore::model::DocumentMap;
  34. using firebase::firestore::model::MaybeDocumentMap;
  35. using firebase::firestore::model::ResourcePath;
  36. using firebase::firestore::model::SnapshotVersion;
  37. NS_ASSUME_NONNULL_BEGIN
  38. @interface FSTLocalDocumentsView ()
  39. - (instancetype)initWithRemoteDocumentCache:(RemoteDocumentCache *)remoteDocumentCache
  40. mutationQueue:(MutationQueue *)mutationQueue
  41. NS_DESIGNATED_INITIALIZER;
  42. @end
  43. @implementation FSTLocalDocumentsView {
  44. RemoteDocumentCache *_remoteDocumentCache;
  45. MutationQueue *_mutationQueue;
  46. }
  47. + (instancetype)viewWithRemoteDocumentCache:(RemoteDocumentCache *)remoteDocumentCache
  48. mutationQueue:(MutationQueue *)mutationQueue {
  49. return [[FSTLocalDocumentsView alloc] initWithRemoteDocumentCache:remoteDocumentCache
  50. mutationQueue:mutationQueue];
  51. }
  52. - (instancetype)initWithRemoteDocumentCache:(RemoteDocumentCache *)remoteDocumentCache
  53. mutationQueue:(MutationQueue *)mutationQueue {
  54. if (self = [super init]) {
  55. _remoteDocumentCache = remoteDocumentCache;
  56. _mutationQueue = mutationQueue;
  57. }
  58. return self;
  59. }
  60. - (nullable FSTMaybeDocument *)documentForKey:(const DocumentKey &)key {
  61. std::vector<FSTMutationBatch *> batches =
  62. _mutationQueue->AllMutationBatchesAffectingDocumentKey(key);
  63. return [self documentForKey:key inBatches:batches];
  64. }
  65. // Internal version of documentForKey: which allows reusing `batches`.
  66. - (nullable FSTMaybeDocument *)documentForKey:(const DocumentKey &)key
  67. inBatches:(const std::vector<FSTMutationBatch *> &)batches {
  68. FSTMaybeDocument *_Nullable document = _remoteDocumentCache->Get(key);
  69. for (FSTMutationBatch *batch : batches) {
  70. document = [batch applyToLocalDocument:document documentKey:key];
  71. }
  72. return document;
  73. }
  74. // Returns the view of the given `docs` as they would appear after applying all
  75. // mutations in the given `batches`.
  76. - (MaybeDocumentMap)applyLocalMutationsToDocuments:(const MaybeDocumentMap &)docs
  77. fromBatches:
  78. (const std::vector<FSTMutationBatch *> &)batches {
  79. MaybeDocumentMap results;
  80. for (const auto &kv : docs) {
  81. const DocumentKey &key = kv.first;
  82. FSTMaybeDocument *localView = kv.second;
  83. for (FSTMutationBatch *batch : batches) {
  84. localView = [batch applyToLocalDocument:localView documentKey:key];
  85. }
  86. results = results.insert(key, localView);
  87. }
  88. return results;
  89. }
  90. - (MaybeDocumentMap)documentsForKeys:(const DocumentKeySet &)keys {
  91. MaybeDocumentMap docs = _remoteDocumentCache->GetAll(keys);
  92. return [self localViewsForDocuments:docs];
  93. }
  94. /**
  95. * Similar to `documentsForKeys`, but creates the local view from the given
  96. * `baseDocs` without retrieving documents from the local store.
  97. */
  98. - (MaybeDocumentMap)localViewsForDocuments:(const MaybeDocumentMap &)baseDocs {
  99. MaybeDocumentMap results;
  100. DocumentKeySet allKeys;
  101. for (const auto &kv : baseDocs) {
  102. allKeys = allKeys.insert(kv.first);
  103. }
  104. std::vector<FSTMutationBatch *> batches =
  105. _mutationQueue->AllMutationBatchesAffectingDocumentKeys(allKeys);
  106. MaybeDocumentMap docs = [self applyLocalMutationsToDocuments:baseDocs fromBatches:batches];
  107. for (const auto &kv : docs) {
  108. const DocumentKey &key = kv.first;
  109. FSTMaybeDocument *maybeDoc = kv.second;
  110. // TODO(http://b/32275378): Don't conflate missing / deleted.
  111. if (!maybeDoc) {
  112. maybeDoc = [FSTDeletedDocument documentWithKey:key
  113. version:SnapshotVersion::None()
  114. hasCommittedMutations:NO];
  115. }
  116. results = results.insert(key, maybeDoc);
  117. }
  118. return results;
  119. }
  120. - (DocumentMap)documentsMatchingQuery:(FSTQuery *)query {
  121. if (DocumentKey::IsDocumentKey(query.path)) {
  122. return [self documentsMatchingDocumentQuery:query.path];
  123. } else {
  124. return [self documentsMatchingCollectionQuery:query];
  125. }
  126. }
  127. - (DocumentMap)documentsMatchingDocumentQuery:(const ResourcePath &)docPath {
  128. DocumentMap result;
  129. // Just do a simple document lookup.
  130. FSTMaybeDocument *doc = [self documentForKey:DocumentKey{docPath}];
  131. if ([doc isKindOfClass:[FSTDocument class]]) {
  132. result = result.insert(doc.key, static_cast<FSTDocument *>(doc));
  133. }
  134. return result;
  135. }
  136. - (DocumentMap)documentsMatchingCollectionQuery:(FSTQuery *)query {
  137. DocumentMap results = _remoteDocumentCache->GetMatching(query);
  138. // Get locally persisted mutation batches.
  139. std::vector<FSTMutationBatch *> matchingBatches =
  140. _mutationQueue->AllMutationBatchesAffectingQuery(query);
  141. for (FSTMutationBatch *batch : matchingBatches) {
  142. for (FSTMutation *mutation : [batch mutations]) {
  143. // Only process documents belonging to the collection.
  144. if (!query.path.IsImmediateParentOf(mutation.key.path())) {
  145. continue;
  146. }
  147. const DocumentKey &key = mutation.key;
  148. // baseDoc may be nil for the documents that weren't yet written to the backend.
  149. FSTMaybeDocument *baseDoc = nil;
  150. auto found = results.underlying_map().find(key);
  151. if (found != results.underlying_map().end()) {
  152. baseDoc = found->second;
  153. }
  154. FSTMaybeDocument *mutatedDoc = [mutation applyToLocalDocument:baseDoc
  155. baseDocument:baseDoc
  156. localWriteTime:batch.localWriteTime];
  157. if ([mutatedDoc isKindOfClass:[FSTDocument class]]) {
  158. results = results.insert(key, static_cast<FSTDocument *>(mutatedDoc));
  159. } else {
  160. results = results.erase(key);
  161. }
  162. }
  163. }
  164. // Finally, filter out any documents that don't actually match the query. Note that the extra
  165. // reference here prevents ARC from deallocating the initial unfiltered results while we're
  166. // enumerating them.
  167. DocumentMap unfiltered = results;
  168. for (const auto &kv : unfiltered.underlying_map()) {
  169. const DocumentKey &key = kv.first;
  170. FSTDocument *doc = static_cast<FSTDocument *>(kv.second);
  171. if (![query matchesDocument:doc]) {
  172. results = results.erase(key);
  173. }
  174. }
  175. return results;
  176. }
  177. @end
  178. NS_ASSUME_NONNULL_END