9
9
10
10
#import " PFObjectBatchController.h"
11
11
12
+ #import < Bolts/Bolts.h>
13
+
12
14
#import " BFTask+Private.h"
13
15
#import " PFAssert.h"
14
16
#import " PFCommandResult.h"
19
21
#import " PFObjectPrivate.h"
20
22
#import " PFQueryPrivate.h"
21
23
#import " PFRESTQueryCommand.h"
24
+ #import " PFRESTObjectCommand.h"
25
+ #import " PFRESTObjectBatchCommand.h"
22
26
23
27
@implementation PFObjectBatchController
24
28
@@ -98,10 +102,86 @@ - (BFTask *)_processFetchResultAsync:(NSDictionary *)result forObjects:(NSArray
98
102
}];
99
103
}
100
104
105
+ // /--------------------------------------
106
+ #pragma mark - Delete
107
+ // /--------------------------------------
108
+
109
+ - (BFTask *)deleteObjectsAsync : (NSArray *)objects withSessionToken : (NSString *)sessionToken {
110
+ if (objects.count == 0 ) {
111
+ return [BFTask taskWithResult: objects];
112
+ }
113
+
114
+ @weakify (self);
115
+ return [[BFTask taskFromExecutor: [BFExecutor defaultPriorityBackgroundExecutor ] withBlock: ^id {
116
+ @strongify (self);
117
+ NSArray *objectBatches = [PFInternalUtils arrayBySplittingArray: objects
118
+ withMaximumComponentsPerSegment: PFRESTObjectBatchCommandSubcommandsLimit];
119
+ NSMutableArray *tasks = [NSMutableArray arrayWithCapacity: objectBatches.count];
120
+ for (NSArray *batch in objectBatches) {
121
+ PFRESTCommand *command = [self _deleteCommandForObjects: batch withSessionToken: sessionToken];
122
+ BFTask *task = [[self .dataSource.commandRunner runCommandAsync: command
123
+ withOptions: PFCommandRunningOptionRetryIfFailed] continueWithSuccessBlock: ^id (BFTask *task) {
124
+ PFCommandResult *result = task.result ;
125
+ return [self _processDeleteResultsAsync: [result result ] forObjects: batch];
126
+ }];
127
+ [tasks addObject: task];
128
+ }
129
+ return [[BFTask taskForCompletionOfAllTasks: tasks] continueWithBlock: ^id (BFTask *task) {
130
+ NSError *taskError = task.error ;
131
+ if (taskError && [taskError.domain isEqualToString: BFTaskErrorDomain]) {
132
+ NSArray *taskErrors = taskError.userInfo [@" errors" ];
133
+ NSMutableArray *errors = [NSMutableArray array ];
134
+ for (NSError *error in taskErrors) {
135
+ if ([error.domain isEqualToString: BFTaskErrorDomain]) {
136
+ [errors addObjectsFromArray: error.userInfo[@" errors" ]];
137
+ } else {
138
+ [errors addObject: error];
139
+ }
140
+ }
141
+ return [BFTask taskWithError: [NSError errorWithDomain: BFTaskErrorDomain
142
+ code: kBFMultipleErrorsError
143
+ userInfo: @{ @" errors" : errors }]];
144
+ }
145
+ return task;
146
+ }];
147
+ }] continueWithSuccessResult: objects];
148
+ }
149
+
150
+ - (PFRESTCommand *)_deleteCommandForObjects : (NSArray *)objects withSessionToken : (NSString *)sessionToken {
151
+ NSMutableArray *commands = [NSMutableArray arrayWithCapacity: objects.count];
152
+ for (PFObject *object in objects) {
153
+ [object checkDeleteParams ];
154
+ PFRESTCommand *deleteCommand = [PFRESTObjectCommand deleteObjectCommandForObjectState: object._state
155
+ withSessionToken: sessionToken];
156
+ [commands addObject: deleteCommand];
157
+ }
158
+ return [PFRESTObjectBatchCommand batchCommandWithCommands: commands sessionToken: sessionToken];
159
+ }
160
+
161
+ - (BFTask *)_processDeleteResultsAsync : (NSArray *)results forObjects : (NSArray *)objects {
162
+ NSMutableArray *tasks = [NSMutableArray arrayWithCapacity: results.count];
163
+ [results enumerateObjectsUsingBlock: ^(NSDictionary *result, NSUInteger idx, BOOL *stop) {
164
+ PFObject *object = objects[idx];
165
+ NSDictionary *errorResult = result[@" error" ];
166
+ NSDictionary *successResult = result[@" success" ];
167
+
168
+ id <PFObjectControlling> controller = [[object class ] objectController ];
169
+ BFTask *task = [controller processDeleteResultAsync: successResult forObject: object];
170
+ if (errorResult) {
171
+ task = [task continueWithBlock: ^id (BFTask *task) {
172
+ return [BFTask taskWithError: [PFErrorUtilities errorFromResult: errorResult]];
173
+ }];
174
+ }
175
+ [tasks addObject: task];
176
+ }];
177
+ return [BFTask taskForCompletionOfAllTasks: tasks];
178
+ }
179
+
101
180
// /--------------------------------------
102
181
#pragma mark - Utilities
103
182
// /--------------------------------------
104
183
184
+ // TODO: (nlutsenko) Convert to use `uniqueObjectsArrayFromArray:usingFilter:`
105
185
+ (NSArray *)uniqueObjectsArrayFromArray : (NSArray *)objects omitObjectsWithData : (BOOL )omitFetched {
106
186
if (objects.count == 0 ) {
107
187
return objects;
@@ -115,6 +195,7 @@ + (NSArray *)uniqueObjectsArrayFromArray:(NSArray *)objects omitObjectsWithData:
115
195
continue ;
116
196
}
117
197
198
+ // TODO: (nlutsenko) Convert to using errors instead of assertions.
118
199
PFParameterAssert ([className isEqualToString: object.parseClassName],
119
200
@" All object should be in the same class." );
120
201
PFParameterAssert (object.objectId != nil ,
@@ -126,4 +207,24 @@ + (NSArray *)uniqueObjectsArrayFromArray:(NSArray *)objects omitObjectsWithData:
126
207
return [set allObjects ];
127
208
}
128
209
210
+ + (NSArray *)uniqueObjectsArrayFromArray : (NSArray *)objects usingFilter : (BOOL (^)(PFObject *object))filter {
211
+ if (objects.count == 0 ) {
212
+ return objects;
213
+ }
214
+
215
+ NSMutableDictionary *uniqueObjects = [NSMutableDictionary dictionary ];
216
+ for (PFObject *object in objects) {
217
+ if (!filter (object)) {
218
+ continue ;
219
+ }
220
+
221
+ // Use stringWithFormat: in case objectId or parseClassName are nil.
222
+ NSString *objectIdentifier = [NSString stringWithFormat: @" %@%@ " , object.parseClassName, object.objectId];
223
+ if (!uniqueObjects[objectIdentifier]) {
224
+ uniqueObjects[objectIdentifier] = object;
225
+ }
226
+ }
227
+ return [uniqueObjects allValues ];
228
+ }
229
+
129
230
@end
0 commit comments