136 lines
5.8 KiB
Objective-C
136 lines
5.8 KiB
Objective-C
#import "ARTPaginatedResult+Private.h"
|
|
|
|
#import "ARTHttp.h"
|
|
#import "ARTAuth.h"
|
|
#import "ARTRest+Private.h"
|
|
#import "ARTNSMutableURLRequest+ARTPaginated.h"
|
|
#import "ARTNSHTTPURLResponse+ARTPaginated.h"
|
|
|
|
@implementation ARTPaginatedResult {
|
|
ARTRestInternal *_rest;
|
|
dispatch_queue_t _userQueue;
|
|
dispatch_queue_t _queue;
|
|
NSMutableURLRequest *_relFirst;
|
|
NSMutableURLRequest *_relCurrent;
|
|
NSMutableURLRequest *_relNext;
|
|
ARTPaginatedResultResponseProcessor _responseProcessor;
|
|
ARTQueuedDealloc *_dealloc;
|
|
}
|
|
|
|
@synthesize rest = _rest;
|
|
@synthesize userQueue = _userQueue;
|
|
@synthesize queue = _queue;
|
|
@synthesize relFirst = _relFirst;
|
|
@synthesize relCurrent = _relCurrent;
|
|
@synthesize relNext = _relNext;
|
|
|
|
- (instancetype)initWithItems:(NSArray *)items
|
|
rest:(ARTRestInternal *)rest
|
|
relFirst:(NSMutableURLRequest *)relFirst
|
|
relCurrent:(NSMutableURLRequest *)relCurrent
|
|
relNext:(NSMutableURLRequest *)relNext
|
|
responseProcessor:(ARTPaginatedResultResponseProcessor)responseProcessor {
|
|
if (self = [super init]) {
|
|
_items = items;
|
|
|
|
_relFirst = relFirst;
|
|
|
|
_relCurrent = relCurrent;
|
|
|
|
_relNext = relNext;
|
|
_hasNext = !!relNext;
|
|
_isLast = !_hasNext;
|
|
|
|
_rest = rest;
|
|
_userQueue = rest.userQueue;
|
|
_queue = rest.queue;
|
|
_responseProcessor = responseProcessor;
|
|
|
|
// ARTPaginatedResult doesn't need a internal counterpart, as other
|
|
// public objects do. It basically acts as a proxy to a
|
|
// strongly-referenced ARTRestInternal, so it can be thought as an
|
|
// alternative public counterpart to ARTRestInternal.
|
|
//
|
|
// So, since it's owned by user code, it should dispatch its release of
|
|
// its ARTRestInternal to the internal queue. We could take the common
|
|
// ARTQueuedDealloc as an argument as other public objects do, but
|
|
// that would just be bookkeeping since we know it will be initialized
|
|
// from the ARTRestInternal we already have access to anyway, so we can
|
|
// make our own.
|
|
_dealloc = [[ARTQueuedDealloc alloc] init:_rest queue:_queue];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)first:(void (^)(ARTPaginatedResult<id> *_Nullable result, ARTErrorInfo *_Nullable error))callback {
|
|
if (callback) {
|
|
void (^userCallback)(ARTPaginatedResult<id> *_Nullable result, ARTErrorInfo *_Nullable error) = callback;
|
|
callback = ^(ARTPaginatedResult<id> *_Nullable result, ARTErrorInfo *_Nullable error) {
|
|
dispatch_async(self->_userQueue, ^{
|
|
userCallback(result, error);
|
|
});
|
|
};
|
|
}
|
|
|
|
[self.class executePaginated:_rest withRequest:_relFirst andResponseProcessor:_responseProcessor callback:callback];
|
|
}
|
|
|
|
- (void)next:(void (^)(ARTPaginatedResult<id> *_Nullable result, ARTErrorInfo *_Nullable error))callback {
|
|
if (callback) {
|
|
void (^userCallback)(ARTPaginatedResult<id> *_Nullable result, ARTErrorInfo *_Nullable error) = callback;
|
|
callback = ^(ARTPaginatedResult<id> *_Nullable result, ARTErrorInfo *_Nullable error) {
|
|
dispatch_async(self->_userQueue, ^{
|
|
userCallback(result, error);
|
|
});
|
|
};
|
|
}
|
|
|
|
if (!_relNext) {
|
|
// If there is no next page, we can't make a request, so we answer the callback
|
|
// with a nil PaginatedResult. That's why the callback has the result as nullable
|
|
// anyway. (That, and that it can fail.)
|
|
callback(nil, nil);
|
|
return;
|
|
}
|
|
[self.class executePaginated:_rest withRequest:_relNext andResponseProcessor:_responseProcessor callback:callback];
|
|
}
|
|
|
|
+ (void)executePaginated:(ARTRestInternal *)rest withRequest:(NSMutableURLRequest *)request andResponseProcessor:(ARTPaginatedResultResponseProcessor)responseProcessor callback:(void (^)(ARTPaginatedResult<id> *_Nullable result, ARTErrorInfo *_Nullable error))callback {
|
|
[rest.logger debug:__FILE__ line:__LINE__ message:@"Paginated request: %@", request];
|
|
|
|
[rest executeRequest:request withAuthOption:ARTAuthenticationOn completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
|
|
if (error) {
|
|
callback(nil, [ARTErrorInfo createFromNSError:error]);
|
|
} else {
|
|
[[rest logger] debug:__FILE__ line:__LINE__ message:@"Paginated response: %@", response];
|
|
[[rest logger] debug:__FILE__ line:__LINE__ message:@"Paginated response data: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]];
|
|
|
|
NSError *decodeError = nil;
|
|
NSArray *items = responseProcessor(response, data, &decodeError);
|
|
|
|
if (decodeError) {
|
|
callback(nil, [ARTErrorInfo createFromNSError:decodeError]);
|
|
return;
|
|
}
|
|
|
|
NSDictionary *links = [response extractLinks];
|
|
|
|
NSMutableURLRequest *firstRel = [NSMutableURLRequest requestWithPath:links[@"first"] relativeTo:request];
|
|
NSMutableURLRequest *currentRel = [NSMutableURLRequest requestWithPath:links[@"current"] relativeTo:request];
|
|
NSMutableURLRequest *nextRel = [NSMutableURLRequest requestWithPath:links[@"next"] relativeTo:request];
|
|
|
|
ARTPaginatedResult *result = [[ARTPaginatedResult alloc] initWithItems:items
|
|
rest:rest
|
|
relFirst:firstRel
|
|
relCurrent:currentRel
|
|
relNext:nextRel
|
|
responseProcessor:responseProcessor];
|
|
|
|
callback(result, nil);
|
|
}
|
|
}];
|
|
}
|
|
|
|
@end
|