1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
/*
* 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/API/FIRTransaction+Internal.h"
#import "Firestore/Source/API/FIRDocumentReference+Internal.h"
#import "Firestore/Source/API/FIRDocumentSnapshot+Internal.h"
#import "Firestore/Source/API/FIRFirestore+Internal.h"
#import "Firestore/Source/API/FSTUserDataConverter.h"
#import "Firestore/Source/Core/FSTTransaction.h"
#import "Firestore/Source/Model/FSTDocument.h"
#import "Firestore/Source/Util/FSTAssert.h"
#import "Firestore/Source/Util/FSTUsageValidation.h"
NS_ASSUME_NONNULL_BEGIN
#pragma mark - FIRTransaction
@interface FIRTransaction ()
- (instancetype)initWithTransaction:(FSTTransaction *)transaction
firestore:(FIRFirestore *)firestore NS_DESIGNATED_INITIALIZER;
@property(nonatomic, strong, readonly) FSTTransaction *internalTransaction;
@property(nonatomic, strong, readonly) FIRFirestore *firestore;
@end
@implementation FIRTransaction (Internal)
+ (instancetype)transactionWithFSTTransaction:(FSTTransaction *)transaction
firestore:(FIRFirestore *)firestore {
return [[FIRTransaction alloc] initWithTransaction:transaction firestore:firestore];
}
@end
@implementation FIRTransaction
- (instancetype)initWithTransaction:(FSTTransaction *)transaction
firestore:(FIRFirestore *)firestore {
self = [super init];
if (self) {
_internalTransaction = transaction;
_firestore = firestore;
}
return self;
}
- (FIRTransaction *)setData:(NSDictionary<NSString *, id> *)data
forDocument:(FIRDocumentReference *)document {
return [self setData:data forDocument:document merge:NO];
}
- (FIRTransaction *)setData:(NSDictionary<NSString *, id> *)data
forDocument:(FIRDocumentReference *)document
merge:(BOOL)merge {
[self validateReference:document];
FSTParsedSetData *parsed = merge
? [self.firestore.dataConverter parsedMergeData:data fieldMask:nil]
: [self.firestore.dataConverter parsedSetData:data];
[self.internalTransaction setData:parsed forDocument:document.key];
return self;
}
- (FIRTransaction *)setData:(NSDictionary<NSString *, id> *)data
forDocument:(FIRDocumentReference *)document
mergeFields:(NSArray<id> *)mergeFields {
[self validateReference:document];
FSTParsedSetData *parsed =
[self.firestore.dataConverter parsedMergeData:data fieldMask:mergeFields];
[self.internalTransaction setData:parsed forDocument:document.key];
return self;
}
- (FIRTransaction *)updateData:(NSDictionary<id, id> *)fields
forDocument:(FIRDocumentReference *)document {
[self validateReference:document];
FSTParsedUpdateData *parsed = [self.firestore.dataConverter parsedUpdateData:fields];
[self.internalTransaction updateData:parsed forDocument:document.key];
return self;
}
- (FIRTransaction *)deleteDocument:(FIRDocumentReference *)document {
[self validateReference:document];
[self.internalTransaction deleteDocument:document.key];
return self;
}
- (void)getDocument:(FIRDocumentReference *)document
completion:(void (^)(FIRDocumentSnapshot *_Nullable document,
NSError *_Nullable error))completion {
[self validateReference:document];
[self.internalTransaction
lookupDocumentsForKeys:{document.key}
completion:^(NSArray<FSTMaybeDocument *> *_Nullable documents,
NSError *_Nullable error) {
if (error) {
completion(nil, error);
return;
}
FSTAssert(documents.count == 1,
@"Mismatch in docs returned from document lookup.");
FSTMaybeDocument *internalDoc = documents.firstObject;
if ([internalDoc isKindOfClass:[FSTDeletedDocument class]]) {
completion(nil, nil);
return;
}
FIRDocumentSnapshot *doc =
[FIRDocumentSnapshot snapshotWithFirestore:self.firestore
documentKey:internalDoc.key
document:(FSTDocument *)internalDoc
fromCache:NO];
completion(doc, nil);
}];
}
- (FIRDocumentSnapshot *_Nullable)getDocument:(FIRDocumentReference *)document
error:(NSError *__autoreleasing *)error {
[self validateReference:document];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block FIRDocumentSnapshot *result;
// We have to explicitly assign the innerError into a local to cause it to retain correctly.
__block NSError *outerError = nil;
[self getDocument:document
completion:^(FIRDocumentSnapshot *_Nullable snapshot, NSError *_Nullable innerError) {
result = snapshot;
outerError = innerError;
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
if (error) {
*error = outerError;
}
return result;
}
- (void)validateReference:(FIRDocumentReference *)reference {
if (reference.firestore != self.firestore) {
FSTThrowInvalidArgument(@"Provided document reference is from a different Firestore instance.");
}
}
@end
NS_ASSUME_NONNULL_END
|