Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pagination utilities #44

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions Sources/SDK/Requests/MoltinRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,33 @@ public class MoltinRequest {
return self
}

/**
Construct a pagination request, and return an instance of type `T`, which must be `Codable`

- Author:
Craig Tweedy

- parameters:
- withURL: The URL constructed from a path to call
- completionHandler: The handler to be called on success or failure
- returns:
A instance of `MoltinRequest` which encapsulates the request.
*/
@discardableResult internal func paginationRequest<T: Codable>(withURL url: URL, completionHandler: @escaping CollectionRequestHandler<T>) -> Self {

let urlRequest = URLRequest(url: url)

self.send(withURLRequest: urlRequest) { (data, response, error) in
if error != nil {
completionHandler(.failure(error: MoltinError.responseError(underlyingError: error)))
return
}
self.parser.collectionHandler(withData: data, withResponse: response, completionHandler: completionHandler)
}

return self
}

private func send(withURLRequest urlRequest: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) {
self.auth.authenticate { [weak self] (result) in
switch result {
Expand Down
4 changes: 4 additions & 0 deletions Sources/SDK/Utils/Error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public enum MoltinError: Error {
case unacceptableRequest
/// Thrown if no data was returned from the API
case noData
/// Thrown if no next or previous page for this call was available
case noPageAvailable
}

extension MoltinError: LocalizedError {
Expand All @@ -46,6 +48,8 @@ extension MoltinError: LocalizedError {
return "Could not compose request"
case .couldNotSetData:
return "Could not serialize data"
case .noPageAvailable:
return "No page available"
}
}
}
92 changes: 92 additions & 0 deletions Sources/SDK/Utils/Pagination.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,98 @@ open class PaginatedResponse<T: Codable>: Codable {
public var links: [String: String?]?
/// The meta information for this response
public var meta: PaginationMeta?

/**
Get the next page for this response

- Author:
Craig Tweedy

- parameters:
- withConfig: The moltin config to use
- withCompletion: The handler to be called on success or failure
- returns:
A instance of `MoltinRequest` which encapsulates the request.
*/
@discardableResult public func next(withConfig config: MoltinConfig, withCompletion completionHandler: @escaping (Result<PaginatedResponse<T>>) -> Void) -> MoltinRequest? {
guard let page = self.links?["next"] as? String,
let url = URL(string: page) else {
completionHandler(.failure(error: MoltinError.noPageAvailable))
return nil
}

let request = MoltinRequest(withConfiguration: config)
return request.paginationRequest(withURL: url, completionHandler: completionHandler)
}

/**
Get the previous page for this response

- Author:
Craig Tweedy

- parameters:
- withConfig: The moltin config to use
- withCompletion: The handler to be called on success or failure
- returns:
A instance of `MoltinRequest` which encapsulates the request.
*/
@discardableResult public func previous(withConfig config: MoltinConfig, withCompletion completionHandler: @escaping (Result<PaginatedResponse<T>>) -> Void) -> MoltinRequest? {
guard let page = self.links?["prev"] as? String,
let url = URL(string: page) else {
completionHandler(.failure(error: MoltinError.noPageAvailable))
return nil
}

let request = MoltinRequest(withConfiguration: config)
return request.paginationRequest(withURL: url, completionHandler: completionHandler)
}

/**
Get the first page for this response

- Author:
Craig Tweedy

- parameters:
- withConfig: The moltin config to use
- withCompletion: The handler to be called on success or failure
- returns:
A instance of `MoltinRequest` which encapsulates the request.
*/
@discardableResult public func first(withConfig config: MoltinConfig, withCompletion completionHandler: @escaping (Result<PaginatedResponse<T>>) -> Void) -> MoltinRequest? {
guard let page = self.links?["first"] as? String,
let url = URL(string: page) else {
completionHandler(.failure(error: MoltinError.noPageAvailable))
return nil
}

let request = MoltinRequest(withConfiguration: config)
return request.paginationRequest(withURL: url, completionHandler: completionHandler)
}

/**
Get the last page for this response

- Author:
Craig Tweedy

- parameters:
- withConfig: The moltin config to use
- withCompletion: The handler to be called on success or failure
- returns:
A instance of `MoltinRequest` which encapsulates the request.
*/
@discardableResult public func last(withConfig config: MoltinConfig, withCompletion completionHandler: @escaping (Result<PaginatedResponse<T>>) -> Void) -> MoltinRequest? {
guard let page = self.links?["last"] as? String,
let url = URL(string: page) else {
completionHandler(.failure(error: MoltinError.noPageAvailable))
return nil
}

let request = MoltinRequest(withConfiguration: config)
return request.paginationRequest(withURL: url, completionHandler: completionHandler)
}
}

/// `PaginationMeta` gives information about the pagination details to the user, such as result information and page information
Expand Down
20 changes: 11 additions & 9 deletions moltin.playground/Contents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,6 @@ PlaygroundPage.current.needsIndefiniteExecution = true

let moltin = Moltin(withClientID: "j6hSilXRQfxKohTndUuVrErLcSJWP15P347L6Im0M4")

moltin.product.all { (result: Result<PaginatedResponse<[Product]>>) in
switch result {
case .success(let products):
print(products)
case .failure(let error):
print(error)
}
}

moltin.product.all { (result) in
guard case .success(let products) = result else {
// something went wrong
Expand All @@ -25,4 +16,15 @@ moltin.product.all { (result) in
}

print(products)

products.next(withConfig: moltin.config) { (paginatedResult) in
guard case .success(let nextPage) = paginatedResult else {
// something went wrong
if case .failure(let error) = paginatedResult { print(error) }
return
}

print(nextPage)

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,68 +4,40 @@
<dict>
<key>SchemeUserState</key>
<dict>
<key>moltin WatchKit Example.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>5</integer>
</dict>
<key>moltin WatchKit Example.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>5</integer>
</dict>
<key>moltin iOS Example.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>4</integer>
</dict>
<key>moltin iOS Example.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>4</integer>
<integer>1</integer>
</dict>
<key>moltin iOS Tests.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>3</integer>
<integer>2</integer>
</dict>
<key>moltin iOS.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
</dict>
<key>moltin tvOS Example.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>6</integer>
<integer>0</integer>
</dict>
<key>moltin tvOS Example.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>6</integer>
</dict>
<key>moltin tvOS Tests.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>5</integer>
</dict>
<key>moltin tvOS.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
<integer>3</integer>
</dict>
<key>moltin watchOS.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>C392EA11203DB7EB006CD1D0</key>
<dict>
<key>primary</key>
<true/>
<integer>5</integer>
</dict>
</dict>
</dict>
Expand Down