diff --git a/Code/Network/RKPaginator.h b/Code/Network/RKPaginator.h index 3b0cc80c..17a4a822 100644 --- a/Code/Network/RKPaginator.h +++ b/Code/Network/RKPaginator.h @@ -188,6 +188,14 @@ */ @property (nonatomic, readonly) NSUInteger currentPage; +/** + Returns the offset based off the page for the most recently loaded objects. + + @return The offset for the current page of objects. + @exception NSInternalInconsistencyException Raised if `isLoaded` is equal to `NO`. + */ +@property (nonatomic, readonly) NSUInteger offset; + /** Returns the number of pages in the total resource collection. diff --git a/Code/Network/RKPaginator.m b/Code/Network/RKPaginator.m index b44b05a6..21b1e1f7 100644 --- a/Code/Network/RKPaginator.m +++ b/Code/Network/RKPaginator.m @@ -36,6 +36,7 @@ static NSUInteger RKPaginatorDefaultPerPage = 25; @property (nonatomic, strong) RKObjectRequestOperation *objectRequestOperation; @property (nonatomic, copy) NSArray *responseDescriptors; @property (nonatomic, assign, readwrite) NSUInteger currentPage; +@property (nonatomic, assign, readwrite) NSUInteger offset; @property (nonatomic, assign, readwrite) NSUInteger pageCount; @property (nonatomic, assign, readwrite) NSUInteger objectCount; @property (nonatomic, assign, readwrite) BOOL loaded; @@ -71,6 +72,7 @@ static NSUInteger RKPaginatorDefaultPerPage = 25; self.currentPage = NSNotFound; self.pageCount = NSNotFound; self.objectCount = NSNotFound; + self.offset = NSNotFound; self.perPage = RKPaginatorDefaultPerPage; self.loaded = NO; } @@ -114,6 +116,11 @@ static NSUInteger RKPaginatorDefaultPerPage = 25; return _currentPage != NSNotFound; } +- (BOOL)hasOffset +{ + return _offset != NSNotFound; +} + - (BOOL)hasPageCount { return _pageCount != NSNotFound; @@ -131,6 +138,12 @@ static NSUInteger RKPaginatorDefaultPerPage = 25; return _currentPage; } +- (NSUInteger)offset +{ + if ([self hasOffset]) return _offset; + return [self hasCurrentPage] ? ((_currentPage - 1) * _perPage) : 0; +} + - (BOOL)hasNextPage { NSAssert(self.isLoaded, @"Cannot determine hasNextPage: paginator is not loaded."); @@ -227,9 +240,10 @@ static NSUInteger RKPaginatorDefaultPerPage = 25; - (NSString *)description { - return [NSString stringWithFormat:@"<%@: %p patternURL=%@ isLoaded=%@ perPage=%ld currentPage=%@ pageCount=%@ objectCount=%@>", + return [NSString stringWithFormat:@"<%@: %p patternURL=%@ isLoaded=%@ perPage=%ld currentPage=%@ offset=%@ pageCount=%@ objectCount=%@>", NSStringFromClass([self class]), self, self.patternURL, self.isLoaded ? @"YES" : @"NO", (long) self.perPage, [self hasCurrentPage] ? @(self.currentPage) : @"???", + [self hasOffset] ? @(self.offset) : @"???", [self hasPageCount] ? @(self.pageCount) : @"???", [self hasObjectCount] ? @(self.objectCount) : @"???"]; } @@ -292,4 +306,14 @@ static NSUInteger RKPaginatorDefaultPerPage = 25; self.objectCount = [objectCountNumber unsignedIntegerValue]; } +- (NSNumber *)offsetNumber +{ + return [NSNumber numberWithUnsignedInteger:self.offset]; +} + +- (void)setOffsetNumber:(NSNumber *)offsetNumber +{ + self.offset = [offsetNumber unsignedIntegerValue]; +} + @end diff --git a/Tests/Logic/ObjectMapping/RKPaginatorTest.m b/Tests/Logic/ObjectMapping/RKPaginatorTest.m index 2492e8bc..7b168551 100644 --- a/Tests/Logic/ObjectMapping/RKPaginatorTest.m +++ b/Tests/Logic/ObjectMapping/RKPaginatorTest.m @@ -36,6 +36,7 @@ @implementation RKPaginatorTest static NSString * const RKPaginatorTestResourcePathPattern = @"/paginate?per_page=:perPage&page=:currentPage"; +static NSString * const RKPaginatorTestResourcePathPatternWithOffset = @"/paginate?limit=:perPage&offset=:offset"; - (void)setUp { @@ -61,6 +62,7 @@ static NSString * const RKPaginatorTestResourcePathPattern = @"/paginate?per_pag [paginationMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"current_page" toKeyPath:@"currentPage"]]; [paginationMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"per_page" toKeyPath:@"perPage"]]; [paginationMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"total_entries" toKeyPath:@"objectCount"]]; + [paginationMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"offset" toKeyPath:@"offset"]]; return paginationMapping; } @@ -70,6 +72,11 @@ static NSString * const RKPaginatorTestResourcePathPattern = @"/paginate?per_pag return [NSURL URLWithString:RKPaginatorTestResourcePathPattern relativeToURL:[RKTestFactory baseURL]]; } +- (NSURL *)paginationOffsetURL +{ + return [NSURL URLWithString:RKPaginatorTestResourcePathPatternWithOffset relativeToURL:[RKTestFactory baseURL]]; +} + #pragma mark - Test Cases - (void)testInitCopiesPatternURL @@ -145,6 +152,17 @@ static NSString * const RKPaginatorTestResourcePathPattern = @"/paginate?per_pag expect([[mockPaginator URL] query]).to.equal(@"per_page=25&page=1"); } +- (void)testThatURLReturnedReflectsStateOfPaginatorWithOffset +{ + NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationOffsetURL]; + RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]]; + id mockPaginator = [OCMockObject partialMockForObject:paginator]; + NSUInteger currentPage = 1; + [[[mockPaginator stub] andReturnValue:OCMOCK_VALUE(currentPage)] currentPage]; + expect([[mockPaginator URL] query]).to.equal(@"limit=25&offset=0"); +} + + - (void)testLoadingAPageOfObjects { NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL]; @@ -410,4 +428,16 @@ static NSString * const RKPaginatorTestResourcePathPattern = @"/paginate?per_pag expect(paginator.objectCount).to.equal(0); } +- (void)testOffsetNumberOfNextPage +{ + NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL]; + RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]]; + [paginator loadPage:1]; + [paginator waitUntilFinished]; + expect(paginator.offset).to.equal(0); + [paginator loadNextPage]; + [paginator waitUntilFinished]; + expect(paginator.offset).to.equal(3); +} + @end