Skip to content

Commit b572eb4

Browse files
mikelehenCorrob
authored andcommitted
Port FIRDocumentChange to C++. (#2687)
* Create C++ api::DocumentChange class. * Make FIRDocumentChange a wrapper over api::DocumentChange. * Moved documentChangesForSnapshot helper from FIRDocumentChange to where it's used in QuerySnapshot. I think this is cleaner.
1 parent 7cf3fc6 commit b572eb4

File tree

9 files changed

+277
-184
lines changed

9 files changed

+277
-184
lines changed

Firestore/Example/Tests/API/FIRQuerySnapshotTests.mm

Lines changed: 16 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,6 @@
4242

4343
NS_ASSUME_NONNULL_BEGIN
4444

45-
@interface FIRDocumentChange ()
46-
47-
// Expose initializer for testing.
48-
- (instancetype)initWithType:(FIRDocumentChangeType)type
49-
document:(FIRQueryDocumentSnapshot *)document
50-
oldIndex:(NSUInteger)oldIndex
51-
newIndex:(NSUInteger)newIndex;
52-
53-
@end
54-
5545
@interface FIRQuerySnapshotTests : XCTestCase
5646
@end
5747

@@ -91,56 +81,40 @@ - (void)testIncludeMetadataChanges {
9181
DocumentSet oldDocuments = FSTTestDocSet(FSTDocumentComparatorByKey, @[ doc1Old, doc2Old ]);
9282
DocumentSet newDocuments = FSTTestDocSet(FSTDocumentComparatorByKey, @[ doc2New, doc2New ]);
9383
std::vector<DocumentViewChange> documentChanges{
94-
DocumentViewChange{doc1New, DocumentViewChange::Type::kMetadata},
95-
DocumentViewChange{doc2New, DocumentViewChange::Type::kModified},
84+
DocumentViewChange(doc1New, DocumentViewChange::Type::kMetadata),
85+
DocumentViewChange(doc2New, DocumentViewChange::Type::kModified),
9686
};
9787

9888
Firestore *firestore = FSTTestFirestore().wrapped;
9989
FSTQuery *query = FSTTestQuery("foo");
100-
ViewSnapshot viewSnapshot{query,
101-
newDocuments,
102-
oldDocuments,
103-
std::move(documentChanges),
104-
/*mutated_keys=*/DocumentKeySet{},
90+
ViewSnapshot viewSnapshot(query, newDocuments, oldDocuments, std::move(documentChanges),
91+
/*mutated_keys=*/DocumentKeySet(),
10592
/*from_cache=*/false,
10693
/*sync_state_changed=*/true,
107-
/*excludes_metadata_changes=*/false};
94+
/*excludes_metadata_changes=*/false);
10895
SnapshotMetadata metadata(/*pending_writes=*/false, /*from_cache=*/false);
10996
FIRQuerySnapshot *snapshot = [[FIRQuerySnapshot alloc] initWithFirestore:firestore
11097
originalQuery:query
11198
snapshot:std::move(viewSnapshot)
11299
metadata:std::move(metadata)];
113100

114-
FIRQueryDocumentSnapshot *doc1Snap =
115-
[[FIRQueryDocumentSnapshot alloc] initWithFirestore:firestore
116-
documentKey:doc1New.key
117-
document:doc1New
118-
fromCache:false
119-
hasPendingWrites:false];
120-
FIRQueryDocumentSnapshot *doc2Snap =
121-
[[FIRQueryDocumentSnapshot alloc] initWithFirestore:firestore
122-
documentKey:doc2New.key
123-
document:doc2New
124-
fromCache:false
125-
hasPendingWrites:false];
101+
DocumentSnapshot doc1Snap(firestore, doc1New.key, doc1New, SnapshotMetadata());
102+
DocumentSnapshot doc2Snap(firestore, doc2New.key, doc2New, SnapshotMetadata());
126103

127104
NSArray<FIRDocumentChange *> *changesWithoutMetadata = @[
128-
[[FIRDocumentChange alloc] initWithType:FIRDocumentChangeTypeModified
129-
document:doc2Snap
130-
oldIndex:1
131-
newIndex:1],
105+
[[FIRDocumentChange alloc]
106+
initWithDocumentChange:DocumentChange(DocumentChange::Type::Modified, doc2Snap,
107+
/*old_index=*/1, /*new_index=*/1)],
132108
];
133109
XCTAssertEqualObjects(snapshot.documentChanges, changesWithoutMetadata);
134110

135111
NSArray<FIRDocumentChange *> *changesWithMetadata = @[
136-
[[FIRDocumentChange alloc] initWithType:FIRDocumentChangeTypeModified
137-
document:doc1Snap
138-
oldIndex:0
139-
newIndex:0],
140-
[[FIRDocumentChange alloc] initWithType:FIRDocumentChangeTypeModified
141-
document:doc2Snap
142-
oldIndex:1
143-
newIndex:1],
112+
[[FIRDocumentChange alloc]
113+
initWithDocumentChange:DocumentChange(DocumentChange::Type::Modified, doc1Snap,
114+
/*old_index=*/0, /*new_index=*/0)],
115+
[[FIRDocumentChange alloc]
116+
initWithDocumentChange:DocumentChange(DocumentChange::Type::Modified, doc2Snap,
117+
/*old_index=*/1, /*new_index=*/1)],
144118
];
145119
XCTAssertEqualObjects([snapshot documentChangesWithIncludeMetadataChanges:YES],
146120
changesWithMetadata);

Firestore/Source/API/FIRDocumentChange+Internal.h

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,17 @@
1616

1717
#import "FIRDocumentChange.h"
1818

19-
#include "Firestore/core/src/firebase/firestore/api/firestore.h"
20-
#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h"
19+
#import <Foundation/Foundation.h>
2120

22-
@class FIRFirestore;
21+
#include "Firestore/core/src/firebase/firestore/api/document_change.h"
22+
23+
using firebase::firestore::api::DocumentChange;
2324

2425
NS_ASSUME_NONNULL_BEGIN
2526

26-
/** Internal FIRDocumentChange API we don't want exposed in our public header files. */
27-
@interface FIRDocumentChange (Internal)
27+
@interface FIRDocumentChange (/* Init */)
2828

29-
/** Calculates the array of FIRDocumentChange's based on the given FSTViewSnapshot. */
30-
+ (NSArray<FIRDocumentChange *> *)
31-
documentChangesForSnapshot:(const firebase::firestore::core::ViewSnapshot &)snapshot
32-
includeMetadataChanges:(bool)includeMetadataChanges
33-
firestore:(firebase::firestore::api::Firestore *)firestore;
29+
- (instancetype)initWithDocumentChange:(DocumentChange &&)documentChange NS_DESIGNATED_INITIALIZER;
3430

3531
@end
3632

Firestore/Source/API/FIRDocumentChange.mm

Lines changed: 34 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -14,128 +14,24 @@
1414
* limitations under the License.
1515
*/
1616

17-
#import "FIRDocumentChange.h"
17+
#import "Firestore/Source/API/FIRDocumentChange+Internal.h"
1818

1919
#import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h"
20-
#import "Firestore/Source/API/FIRFirestore+Internal.h"
21-
#import "Firestore/Source/Core/FSTQuery.h"
22-
#import "Firestore/Source/Model/FSTDocument.h"
2320

24-
#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h"
25-
#include "Firestore/core/src/firebase/firestore/model/document_set.h"
21+
#include "Firestore/core/src/firebase/firestore/api/document_change.h"
2622
#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
2723

28-
using firebase::firestore::api::Firestore;
29-
using firebase::firestore::core::DocumentViewChange;
30-
using firebase::firestore::core::ViewSnapshot;
31-
using firebase::firestore::model::DocumentSet;
24+
using firebase::firestore::api::DocumentChange;
3225

3326
NS_ASSUME_NONNULL_BEGIN
3427

35-
@interface FIRDocumentChange ()
36-
37-
- (instancetype)initWithType:(FIRDocumentChangeType)type
38-
document:(FIRDocumentSnapshot *)document
39-
oldIndex:(NSUInteger)oldIndex
40-
newIndex:(NSUInteger)newIndex NS_DESIGNATED_INITIALIZER;
41-
42-
@end
43-
44-
@implementation FIRDocumentChange (Internal)
45-
46-
+ (FIRDocumentChangeType)documentChangeTypeForChange:(const DocumentViewChange &)change {
47-
switch (change.type()) {
48-
case DocumentViewChange::Type::kAdded:
49-
return FIRDocumentChangeTypeAdded;
50-
case DocumentViewChange::Type::kModified:
51-
case DocumentViewChange::Type::kMetadata:
52-
return FIRDocumentChangeTypeModified;
53-
case DocumentViewChange::Type::kRemoved:
54-
return FIRDocumentChangeTypeRemoved;
55-
}
56-
57-
HARD_FAIL("Unknown DocumentViewChange::Type: %s", change.type());
28+
@implementation FIRDocumentChange {
29+
DocumentChange _documentChange;
5830
}
5931

60-
+ (NSArray<FIRDocumentChange *> *)documentChangesForSnapshot:(const ViewSnapshot &)snapshot
61-
includeMetadataChanges:(bool)includeMetadataChanges
62-
firestore:(Firestore *)firestore {
63-
if (snapshot.old_documents().empty()) {
64-
// Special case the first snapshot because index calculation is easy and fast. Also all changes
65-
// on the first snapshot are adds so there are also no metadata-only changes to filter out.
66-
FSTDocument *_Nullable lastDocument = nil;
67-
NSUInteger index = 0;
68-
NSMutableArray<FIRDocumentChange *> *changes = [NSMutableArray array];
69-
for (const DocumentViewChange &change : snapshot.document_changes()) {
70-
FIRQueryDocumentSnapshot *document = [[FIRQueryDocumentSnapshot alloc]
71-
initWithFirestore:firestore
72-
documentKey:change.document().key
73-
document:change.document()
74-
fromCache:snapshot.from_cache()
75-
hasPendingWrites:snapshot.mutated_keys().contains(change.document().key)];
76-
HARD_ASSERT(change.type() == DocumentViewChange::Type::kAdded,
77-
"Invalid event type for first snapshot");
78-
HARD_ASSERT(!lastDocument || snapshot.query().comparator(lastDocument, change.document()) ==
79-
NSOrderedAscending,
80-
"Got added events in wrong order");
81-
[changes addObject:[[FIRDocumentChange alloc] initWithType:FIRDocumentChangeTypeAdded
82-
document:document
83-
oldIndex:NSNotFound
84-
newIndex:index++]];
85-
}
86-
return changes;
87-
} else {
88-
// A DocumentSet that is updated incrementally as changes are applied to use to lookup the index
89-
// of a document.
90-
DocumentSet indexTracker = snapshot.old_documents();
91-
NSMutableArray<FIRDocumentChange *> *changes = [NSMutableArray array];
92-
for (const DocumentViewChange &change : snapshot.document_changes()) {
93-
if (!includeMetadataChanges && change.type() == DocumentViewChange::Type::kMetadata) {
94-
continue;
95-
}
96-
97-
FIRQueryDocumentSnapshot *document = [[FIRQueryDocumentSnapshot alloc]
98-
initWithFirestore:firestore
99-
documentKey:change.document().key
100-
document:change.document()
101-
fromCache:snapshot.from_cache()
102-
hasPendingWrites:snapshot.mutated_keys().contains(change.document().key)];
103-
104-
size_t oldIndex = DocumentSet::npos;
105-
size_t newIndex = DocumentSet::npos;
106-
if (change.type() != DocumentViewChange::Type::kAdded) {
107-
oldIndex = indexTracker.IndexOf(change.document().key);
108-
HARD_ASSERT(oldIndex != DocumentSet::npos, "Index for document not found");
109-
indexTracker = indexTracker.erase(change.document().key);
110-
}
111-
if (change.type() != DocumentViewChange::Type::kRemoved) {
112-
indexTracker = indexTracker.insert(change.document());
113-
newIndex = indexTracker.IndexOf(change.document().key);
114-
}
115-
[FIRDocumentChange documentChangeTypeForChange:change];
116-
FIRDocumentChangeType type = [FIRDocumentChange documentChangeTypeForChange:change];
117-
[changes addObject:[[FIRDocumentChange alloc] initWithType:type
118-
document:document
119-
oldIndex:oldIndex
120-
newIndex:newIndex]];
121-
}
122-
return changes;
123-
}
124-
}
125-
126-
@end
127-
128-
@implementation FIRDocumentChange
129-
130-
- (instancetype)initWithType:(FIRDocumentChangeType)type
131-
document:(FIRQueryDocumentSnapshot *)document
132-
oldIndex:(NSUInteger)oldIndex
133-
newIndex:(NSUInteger)newIndex {
32+
- (instancetype)initWithDocumentChange:(DocumentChange &&)documentChange {
13433
if (self = [super init]) {
135-
_type = type;
136-
_document = document;
137-
_oldIndex = oldIndex;
138-
_newIndex = newIndex;
34+
_documentChange = std::move(documentChange);
13935
}
14036
return self;
14137
}
@@ -145,16 +41,36 @@ - (BOOL)isEqual:(nullable id)other {
14541
if (![other isKindOfClass:[FIRDocumentChange class]]) return NO;
14642

14743
FIRDocumentChange *change = (FIRDocumentChange *)other;
148-
return self.type == change.type && [self.document isEqual:change.document] &&
149-
self.oldIndex == change.oldIndex && self.newIndex == change.newIndex;
44+
return _documentChange == change->_documentChange;
15045
}
15146

15247
- (NSUInteger)hash {
153-
NSUInteger result = (NSUInteger)self.type;
154-
result = result * 31u + [self.document hash];
155-
result = result * 31u + (NSUInteger)self.oldIndex;
156-
result = result * 31u + (NSUInteger)self.newIndex;
157-
return result;
48+
return _documentChange.Hash();
49+
}
50+
51+
- (FIRDocumentChangeType)type {
52+
switch (_documentChange.type()) {
53+
case DocumentChange::Type::Added:
54+
return FIRDocumentChangeTypeAdded;
55+
case DocumentChange::Type::Modified:
56+
return FIRDocumentChangeTypeModified;
57+
case DocumentChange::Type::Removed:
58+
return FIRDocumentChangeTypeRemoved;
59+
}
60+
61+
HARD_FAIL("Unknown DocumentChange::Type: %s", _documentChange.type());
62+
}
63+
64+
- (FIRQueryDocumentSnapshot *)document {
65+
return [[FIRQueryDocumentSnapshot alloc] initWithSnapshot:_documentChange.document()];
66+
}
67+
68+
- (NSUInteger)oldIndex {
69+
return _documentChange.old_index();
70+
}
71+
72+
- (NSUInteger)newIndex {
73+
return _documentChange.new_index();
15874
}
15975

16076
@end

Firestore/Source/API/FIRQuerySnapshot.mm

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,15 +123,15 @@ - (NSInteger)count {
123123

124124
- (NSArray<FIRDocumentChange *> *)documentChangesWithIncludeMetadataChanges:
125125
(BOOL)includeMetadataChanges {
126-
if (includeMetadataChanges && _snapshot->view_snapshot().excludes_metadata_changes()) {
127-
ThrowInvalidArgument("To include metadata changes with your document changes, you must call "
128-
"addSnapshotListener(includeMetadataChanges: true).");
129-
}
130-
131126
if (!_documentChanges || _documentChangesIncludeMetadataChanges != includeMetadataChanges) {
132-
_documentChanges = [FIRDocumentChange documentChangesForSnapshot:_snapshot->view_snapshot()
133-
includeMetadataChanges:includeMetadataChanges
134-
firestore:_snapshot->firestore()];
127+
NSMutableArray *documentChanges = [NSMutableArray array];
128+
_snapshot->ForEachChange(
129+
static_cast<bool>(includeMetadataChanges), [&documentChanges](DocumentChange change) {
130+
[documentChanges
131+
addObject:[[FIRDocumentChange alloc] initWithDocumentChange:std::move(change)]];
132+
});
133+
134+
_documentChanges = documentChanges;
135135
_documentChangesIncludeMetadataChanges = includeMetadataChanges;
136136
}
137137
return _documentChanges;

0 commit comments

Comments
 (0)