Skip to content

Commit 9b606ed

Browse files
committed
Add async overload for search API
This acts as an example for the conversation being held in issue #332. Async/await continues to grow in popularity and all modern codebases are moving towards its usage. This commit demonstrates how we can add support for Swift Concurrency without breaking existing compatibility with older operating systems. For a test I have taken an existing test, copied it, and converted it for async/await. In this instance, removing the XCTestExpectation and simply using an async test available since Xcode 13 back in September 2021.
1 parent 65d40d7 commit 9b606ed

File tree

2 files changed

+61
-1
lines changed

2 files changed

+61
-1
lines changed

Sources/MeiliSearch/Indexes.swift

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public struct Indexes {
2626
private let documents: Documents
2727

2828
// Search methods
29-
private let search: Search
29+
fileprivate let search: Search
3030

3131
// Settings methods
3232
private let settings: Settings
@@ -900,3 +900,23 @@ public struct Indexes {
900900
}
901901
}
902902
}
903+
904+
// MARK: Swift Concurrency (Async/Await)
905+
906+
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
907+
extension Indexes {
908+
/**
909+
Search in the index.
910+
911+
- Parameter searchParameters: Options on search.
912+
- Throws: Error if a failure occurred.
913+
- Returns: On completion if the request was successful a `Searchable<T>` instance is returned containing the values.
914+
*/
915+
public func search<T: Codable & Equatable>(_ searchParameters: SearchParameters) async throws -> Searchable<T> {
916+
try await withCheckedThrowingContinuation { continuation in
917+
self.search.search(self.uid, searchParameters) { result in
918+
continuation.resume(with: result)
919+
}
920+
}
921+
}
922+
}

Tests/MeiliSearchUnitTests/SearchTests.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,46 @@ class SearchTests: XCTestCase {
8080

8181
self.wait(for: [expectation], timeout: TESTS_TIME_OUT)
8282
}
83+
84+
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
85+
func testSearchForBotmanMovieAsync() async throws {
86+
let jsonString = """
87+
{
88+
"hits": [
89+
{
90+
"id": 29751,
91+
"title": "Batman Unmasked: The Psychology of the Dark Knight",
92+
"poster": "https://image.tmdb.org/t/p/w1280/jjHu128XLARc2k4cJrblAvZe0HE.jpg",
93+
"overview": "Delve into the world of Batman and the vigilante justice tha",
94+
"release_date": "2020-04-04T19:59:49.259572Z"
95+
},
96+
{
97+
"id": 471474,
98+
"title": "Batman: Gotham by Gaslight",
99+
"poster": "https://image.tmdb.org/t/p/w1280/7souLi5zqQCnpZVghaXv0Wowi0y.jpg",
100+
"overview": "ve Victorian Age Gotham City, Batman begins his war on crime",
101+
"release_date": "2020-04-04T19:59:49.259572Z"
102+
}
103+
],
104+
"offset": 0,
105+
"limit": 20,
106+
"processingTimeMs": 2,
107+
"estimatedTotalHits": 2,
108+
"query": "botman"
109+
}
110+
"""
111+
112+
// Prepare the mock server
113+
let data = jsonString.data(using: .utf8)!
114+
let stubSearchResult: Searchable<Movie> = try! Constants.customJSONDecoder.decode(Searchable<Movie>.self, from: data)
115+
session.pushData(jsonString)
116+
117+
// Start the test with the mocked server
118+
let searchParameters = SearchParameters.query("botman")
119+
120+
let searchResult: Searchable<Movie> = try await self.index.search(searchParameters)
121+
XCTAssertEqual(stubSearchResult, searchResult)
122+
}
83123

84124
func testSearchForBotmanMovieFacets() {
85125
let jsonString = """

0 commit comments

Comments
 (0)