diff options
author | Gil <mcg@google.com> | 2018-01-31 11:23:55 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-31 11:23:55 -0800 |
commit | 729b8d176c75ecc0cbbd137cc6811116a64e310a (patch) | |
tree | 22b793b03611ce5ad615b7c7d9579f5ba5206b4a /Firestore/Source/Local/FSTLocalDocumentsView.mm | |
parent | 693d0649bfcc9c32201e2431ae08ea85fdbdb617 (diff) |
Move all Firestore Objective-C to Objective-C++ (#734)
* Move all Firestore files to Objective-C++
* Update project file references
* Don't use module imports from Objective-C++
* Use extern "C" for C-accessible globals
* Work around more stringent type checking in Objective-C++
* NSMutableDictionary ivars aren't implicitly casted to NSDictionary
* FSTMaybeDocument callback can't be passed a function that accepts
FSTDocument
* NSComparisonResult can't be multiplied by -1 without casting
* Add a #include <inttypes.h> where needed
* Avoid using C++ keywords as variables
* Remove #if __cplusplus guards
Diffstat (limited to 'Firestore/Source/Local/FSTLocalDocumentsView.mm')
-rw-r--r-- | Firestore/Source/Local/FSTLocalDocumentsView.mm | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/Firestore/Source/Local/FSTLocalDocumentsView.mm b/Firestore/Source/Local/FSTLocalDocumentsView.mm new file mode 100644 index 0000000..0e88958 --- /dev/null +++ b/Firestore/Source/Local/FSTLocalDocumentsView.mm @@ -0,0 +1,182 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "Firestore/Source/Local/FSTLocalDocumentsView.h" + +#import "Firestore/Source/Core/FSTQuery.h" +#import "Firestore/Source/Core/FSTSnapshotVersion.h" +#import "Firestore/Source/Local/FSTMutationQueue.h" +#import "Firestore/Source/Local/FSTRemoteDocumentCache.h" +#import "Firestore/Source/Model/FSTDocument.h" +#import "Firestore/Source/Model/FSTDocumentDictionary.h" +#import "Firestore/Source/Model/FSTDocumentKey.h" +#import "Firestore/Source/Model/FSTMutation.h" +#import "Firestore/Source/Model/FSTMutationBatch.h" +#import "Firestore/Source/Util/FSTAssert.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FSTLocalDocumentsView () +- (instancetype)initWithRemoteDocumentCache:(id<FSTRemoteDocumentCache>)remoteDocumentCache + mutationQueue:(id<FSTMutationQueue>)mutationQueue + NS_DESIGNATED_INITIALIZER; +@property(nonatomic, strong, readonly) id<FSTRemoteDocumentCache> remoteDocumentCache; +@property(nonatomic, strong, readonly) id<FSTMutationQueue> mutationQueue; +@end + +@implementation FSTLocalDocumentsView + ++ (instancetype)viewWithRemoteDocumentCache:(id<FSTRemoteDocumentCache>)remoteDocumentCache + mutationQueue:(id<FSTMutationQueue>)mutationQueue { + return [[FSTLocalDocumentsView alloc] initWithRemoteDocumentCache:remoteDocumentCache + mutationQueue:mutationQueue]; +} + +- (instancetype)initWithRemoteDocumentCache:(id<FSTRemoteDocumentCache>)remoteDocumentCache + mutationQueue:(id<FSTMutationQueue>)mutationQueue { + if (self = [super init]) { + _remoteDocumentCache = remoteDocumentCache; + _mutationQueue = mutationQueue; + } + return self; +} + +- (nullable FSTMaybeDocument *)documentForKey:(FSTDocumentKey *)key { + FSTMaybeDocument *_Nullable remoteDoc = [self.remoteDocumentCache entryForKey:key]; + return [self localDocument:remoteDoc key:key]; +} + +- (FSTMaybeDocumentDictionary *)documentsForKeys:(FSTDocumentKeySet *)keys { + FSTMaybeDocumentDictionary *results = [FSTMaybeDocumentDictionary maybeDocumentDictionary]; + for (FSTDocumentKey *key in keys.objectEnumerator) { + // TODO(mikelehen): PERF: Consider fetching all remote documents at once rather than one-by-one. + FSTMaybeDocument *maybeDoc = [self documentForKey:key]; + // TODO(http://b/32275378): Don't conflate missing / deleted. + if (!maybeDoc) { + maybeDoc = [FSTDeletedDocument documentWithKey:key version:[FSTSnapshotVersion noVersion]]; + } + results = [results dictionaryBySettingObject:maybeDoc forKey:key]; + } + return results; +} + +- (FSTDocumentDictionary *)documentsMatchingQuery:(FSTQuery *)query { + if ([FSTDocumentKey isDocumentKey:query.path]) { + return [self documentsMatchingDocumentQuery:query.path]; + } else { + return [self documentsMatchingCollectionQuery:query]; + } +} + +- (FSTDocumentDictionary *)documentsMatchingDocumentQuery:(FSTResourcePath *)docPath { + FSTDocumentDictionary *result = [FSTDocumentDictionary documentDictionary]; + // Just do a simple document lookup. + FSTMaybeDocument *doc = [self documentForKey:[FSTDocumentKey keyWithPath:docPath]]; + if ([doc isKindOfClass:[FSTDocument class]]) { + result = [result dictionaryBySettingObject:(FSTDocument *)doc forKey:doc.key]; + } + return result; +} + +- (FSTDocumentDictionary *)documentsMatchingCollectionQuery:(FSTQuery *)query { + // Query the remote documents and overlay mutations. + // TODO(mikelehen): There may be significant overlap between the mutations affecting these + // remote documents and the allMutationBatchesAffectingQuery mutations. Consider optimizing. + __block FSTDocumentDictionary *results = [self.remoteDocumentCache documentsMatchingQuery:query]; + results = [self localDocuments:results]; + + // Now use the mutation queue to discover any other documents that may match the query after + // applying mutations. + FSTDocumentKeySet *matchingKeys = [FSTDocumentKeySet keySet]; + NSArray<FSTMutationBatch *> *matchingMutationBatches = + [self.mutationQueue allMutationBatchesAffectingQuery:query]; + for (FSTMutationBatch *batch in matchingMutationBatches) { + for (FSTMutation *mutation in batch.mutations) { + // TODO(mikelehen): PERF: Check if this mutation actually affects the query to reduce work. + + // If the key is already in the results, we can skip it. + if (![results containsKey:mutation.key]) { + matchingKeys = [matchingKeys setByAddingObject:mutation.key]; + } + } + } + + // Now add in results for the matchingKeys. + for (FSTDocumentKey *key in matchingKeys.objectEnumerator) { + FSTMaybeDocument *doc = [self documentForKey:key]; + if ([doc isKindOfClass:[FSTDocument class]]) { + results = [results dictionaryBySettingObject:(FSTDocument *)doc forKey:key]; + } + } + + // Finally, filter out any documents that don't actually match the query. Note that the extra + // reference here prevents ARC from deallocating the initial unfiltered results while we're + // enumerating them. + FSTDocumentDictionary *unfiltered = results; + [unfiltered + enumerateKeysAndObjectsUsingBlock:^(FSTDocumentKey *key, FSTDocument *doc, BOOL *stop) { + if (![query matchesDocument:doc]) { + results = [results dictionaryByRemovingObjectForKey:key]; + } + }]; + + return results; +} + +/** + * Takes a remote document and applies local mutations to generate the local view of the + * document. + * + * @param document The base remote document to apply mutations to. + * @param documentKey The key of the document (necessary when remoteDocument is nil). + */ +- (nullable FSTMaybeDocument *)localDocument:(nullable FSTMaybeDocument *)document + key:(FSTDocumentKey *)documentKey { + NSArray<FSTMutationBatch *> *batches = + [self.mutationQueue allMutationBatchesAffectingDocumentKey:documentKey]; + for (FSTMutationBatch *batch in batches) { + document = [batch applyTo:document documentKey:documentKey]; + } + + return document; +} + +/** + * Takes a set of remote documents and applies local mutations to generate the local view of + * the documents. + * + * @param documents The base remote documents to apply mutations to. + * @return The local view of the documents. + */ +- (FSTDocumentDictionary *)localDocuments:(FSTDocumentDictionary *)documents { + __block FSTDocumentDictionary *result = documents; + [documents enumerateKeysAndObjectsUsingBlock:^(FSTDocumentKey *key, FSTDocument *remoteDocument, + BOOL *stop) { + FSTMaybeDocument *mutatedDoc = [self localDocument:remoteDocument key:key]; + if ([mutatedDoc isKindOfClass:[FSTDeletedDocument class]]) { + result = [result dictionaryByRemovingObjectForKey:key]; + } else if ([mutatedDoc isKindOfClass:[FSTDocument class]]) { + result = [result dictionaryBySettingObject:(FSTDocument *)mutatedDoc forKey:key]; + } else { + FSTFail(@"Unknown document: %@", mutatedDoc); + } + }]; + return result; +} + +@end + +NS_ASSUME_NONNULL_END |