Skip to content

Commit f3f91d6

Browse files
Merge pull request #666 from algolia/develop
Release 8.1.1
2 parents c47d9a6 + 35268b6 commit f3f91d6

22 files changed

+429
-96
lines changed

Sources/AlgoliaSearchClient/Command/Command+Personalization.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ extension Command {
3131
let requestOptions: RequestOptions?
3232

3333
init(strategy: PersonalizationStrategy, requestOptions: RequestOptions?) {
34+
var requestOptions = requestOptions.unwrapOrCreate()
35+
requestOptions.setHeader("application/json", forKey: .contentType)
3436
self.requestOptions = requestOptions
3537
self.urlRequest = .init(method: .post, path: .strategies >>> PersonalizationRoute.personalization, body: strategy.httpBody, requestOptions: self.requestOptions)
3638
}

Sources/AlgoliaSearchClient/Command/Command+Search.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ extension Command {
4040
}
4141

4242
init(indexName: IndexName, cursor: Cursor? = nil, requestOptions: RequestOptions?) {
43-
self.requestOptions = requestOptions.updateOrCreate(cursor.flatMap { [.cursor: $0.rawValue] } ?? [:])
43+
self.requestOptions = requestOptions.updateOrCreate(cursor.flatMap { [.cursor: $0.rawValue.addingPercentEncoding(withAllowedCharacters: .uriAllowed)] } ?? [:])
4444
let path = .indexesV1 >>> .index(indexName) >>> IndexCompletion.browse
4545
urlRequest = .init(method: .get, path: path, requestOptions: self.requestOptions)
4646
}

Sources/AlgoliaSearchClient/Models/Internal/HTTP/HTTPStatusCode.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extension HTTPStatusСode {
1313

1414
static let notFound: HTTPStatusСode = 404
1515
static let requestTimeout: HTTPStatusСode = 408
16+
static let tooManyRequests: HTTPStatusСode = 429
1617

1718
func belongs(to categories: HTTPStatusCategory...) -> Bool {
1819
return categories.map { $0.contains(self) }.contains(true)

Sources/AlgoliaSearchClient/Models/Places/PlacesQuery.swift

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,33 @@ public struct PlacesQuery {
1616
public var type: PlaceType?
1717

1818
/// If specified, restrict the search results to a specific list of countries.
19-
/// Engine default: Search on the whole planet.
19+
/// - Engine default: Search on the whole planet.
2020
public var countries: [Country]?
2121

2222
/// Force to first search around a specific latitude longitude.
2323
public var aroundLatLng: Point?
2424

2525
/// Whether or not to first search around the geolocation of the user found via his IP address.
26-
/// Engine default: true
26+
/// - Engine default: true
2727
public var aroundLatLngViaIP: Bool?
2828

2929
/// Radius in meters to search around the latitude/longitude.
3030
/// Otherwise a default radius is automatically computed given the area density.
3131
public var aroundRadius: AroundRadius?
3232

3333
/// Controls whether the _rankingInfo object should be included in the hits.
34-
/// Engine default: false
34+
/// - Engine default: false
3535
public var getRankingInfo: Bool?
3636

3737
/// Specifies how many results you want to retrieve per search.
38-
/// Engine default: 20
38+
/// - Engine default: 20
3939
public var hitsPerPage: Int?
4040

41+
/// Specifies the language of the results.
42+
///
43+
/// When set to nil, engine returns the results in all available languages
44+
/// - Remark: Cannot be set explicitly. To set the language of places query, set the `language` parameter of `PlaceClients.search` method.
45+
/// - Engine default: nil
4146
internal var language: Language?
4247

4348
public init(_ query: String? = nil) {

Sources/AlgoliaSearchClient/Transport/HTTP/HTTPRequest.swift

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ class HTTPRequest<ResponseType: Decodable, Output>: AsyncOperation, ResultContai
1414
typealias Result = Swift.Result<Output, Swift.Error>
1515

1616
let requester: HTTPRequester
17-
let hostIterator: HostIterator
1817
let retryStrategy: RetryStrategy
1918
let timeout: TimeInterval
2019
let request: URLRequest
20+
let callType: CallType
2121
let transform: (ResponseType) -> Output
2222
let completion: (Result) -> Void
23+
let hostIterator: HostIterator
2324
var didUpdateProgress: ((ProgressReporting) -> Void)?
2425

2526
var underlyingTask: (TransportTask)? {
@@ -42,19 +43,20 @@ class HTTPRequest<ResponseType: Decodable, Output>: AsyncOperation, ResultContai
4243

4344
init(requester: HTTPRequester,
4445
retryStrategy: RetryStrategy,
45-
hostIterator: HostIterator,
4646
request: URLRequest,
47+
callType: CallType,
4748
timeout: TimeInterval,
4849
transform: @escaping Transform,
4950
completion: @escaping (Result) -> Void) {
5051
self.requester = requester
5152
self.retryStrategy = retryStrategy
52-
self.hostIterator = hostIterator
5353
self.request = request
54+
self.callType = callType
5455
self.timeout = timeout
5556
self.transform = transform
5657
self.completion = completion
5758
self.underlyingTask = nil
59+
self.hostIterator = retryStrategy.retryableHosts(for: callType)
5860
}
5961

6062
override func main() {
@@ -151,12 +153,13 @@ extension HTTPRequest where ResponseType == Output {
151153
retryStrategy: RetryStrategy,
152154
hostIterator: HostIterator,
153155
request: URLRequest,
156+
callType: CallType,
154157
timeout: TimeInterval,
155158
completion: @escaping (Result) -> Void) {
156159
self.init(requester: requester,
157160
retryStrategy: retryStrategy,
158-
hostIterator: hostIterator,
159161
request: request,
162+
callType: callType,
160163
timeout: timeout,
161164
transform: { $0 },
162165
completion: completion)

Sources/AlgoliaSearchClient/Transport/HTTP/HTTPRequestBuilder.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,22 @@ class HTTPRequestBuilder {
2727
func build<Response: Decodable, Output>(for command: AlgoliaCommand, transform: @escaping (Response) -> Output, with completion: @escaping (HTTPRequest<Response, Output>.Result) -> Void) -> HTTPRequest<Response, Output> {
2828

2929
let timeout = command.requestOptions?.timeout(for: command.callType) ?? configuration.timeout(for: command.callType)
30-
let hostIterator = HostIterator(retryStrategy: retryStrategy, callType: command.callType)
3130
var request = command.urlRequest.setIfNotNil(\.credentials, to: credentials)
3231
let userAgentsValue = UserAgentController.userAgents.map(\.description).joined(separator: "; ")
3332
request.addValue(userAgentsValue, forHTTPHeaderField: HTTPHeaderKey.userAgent.rawValue)
34-
return HTTPRequest(requester: requester, retryStrategy: retryStrategy, hostIterator: hostIterator, request: request, timeout: timeout, transform: transform, completion: completion)
33+
return HTTPRequest(requester: requester,
34+
retryStrategy: retryStrategy,
35+
request: request,
36+
callType: command.callType,
37+
timeout: timeout,
38+
transform: transform,
39+
completion: completion)
3540
}
3641

3742
func build<Response: Decodable, Output>(for command: AlgoliaCommand, transform: @escaping (Response) -> Output, responseType: Output.Type) -> HTTPRequest<Response, Output> {
38-
return build(for: command, transform: transform, with: { (_:HTTPRequest<Response, Output>.Result) in })
43+
return build(for: command,
44+
transform: transform,
45+
with: { (_:HTTPRequest<Response, Output>.Result) in })
3946
}
4047

4148
}

Sources/AlgoliaSearchClient/Transport/HTTP/HTTPTransport+Error.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,21 @@ import Foundation
99

1010
extension HTTPTransport {
1111

12-
enum Error: Swift.Error {
12+
enum Error: Swift.Error, LocalizedError {
1313
case noReachableHosts
1414
case missingData
15+
case decodingFailure(Swift.Error)
16+
17+
var localizedDescription: String {
18+
switch self {
19+
case .noReachableHosts:
20+
return "All hosts are unreachable"
21+
case .missingData:
22+
return "Missing response data"
23+
case .decodingFailure:
24+
return "Response decoding failed"
25+
}
26+
}
1527
}
1628

1729
}

Sources/AlgoliaSearchClient/Transport/HTTP/HTTPTransport+Result.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ extension Result where Success: Decodable, Failure == Error {
3232
let object = try jsonDecoder.decode(Success.self, from: data)
3333
self = .success(object)
3434
} catch let error {
35-
self = .failure(error)
35+
self = .failure(HTTPTransport.Error.decodingFailure(error))
3636
}
3737

3838
}

Sources/AlgoliaSearchClient/Transport/RetryStrategy/AlgoliaRetryStrategy.swift

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,21 @@ class AlgoliaRetryStrategy: RetryStrategy {
2525
convenience init(configuration: Configuration) {
2626
self.init(hosts: configuration.hosts)
2727
}
28-
29-
func host(for callType: CallType) -> RetryableHost? {
28+
29+
func retryableHosts(for callType: CallType) -> HostIterator {
3030
return queue.sync {
31+
// Reset expired hosts
3132
hosts.resetExpired(expirationDelay: hostsExpirationDelay)
32-
33-
func firstUpHostForCallType() -> RetryableHost? {
34-
return hosts.first { $0.supports(callType) && $0.isUp }
35-
}
36-
37-
guard let host = firstUpHostForCallType() else {
33+
34+
// If all hosts of the required type are down, reset them all
35+
if !hosts.contains(where: { $0.supports(callType) && $0.isUp }) {
3836
hosts.resetAll(for: callType)
39-
return firstUpHostForCallType()
4037
}
41-
42-
return host
38+
39+
return HostIterator { [weak self] in
40+
self?.hosts.first { $0.supports(callType) && $0.isUp }
41+
}
4342
}
44-
4543
}
4644

4745
func notify<T>(host: RetryableHost, result: Result<T, Swift.Error>) -> RetryOutcome<T> {

Sources/AlgoliaSearchClient/Transport/RetryStrategy/HostIterator.swift

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,14 @@ import Foundation
99

1010
class HostIterator: IteratorProtocol {
1111

12-
var retryStrategy: RetryStrategy
13-
let callType: CallType
14-
15-
init(retryStrategy: RetryStrategy, callType: CallType) {
16-
self.retryStrategy = retryStrategy
17-
self.callType = callType
12+
var getHost: () -> RetryableHost?
13+
14+
init(getHost: @escaping () -> RetryableHost?) {
15+
self.getHost = getHost
1816
}
1917

2018
func next() -> RetryableHost? {
21-
return retryStrategy.host(for: callType)
19+
return getHost()
2220
}
2321

2422
}

0 commit comments

Comments
 (0)