diff --git a/README.md b/README.md index 2c518cd2..c245ed87 100644 --- a/README.md +++ b/README.md @@ -149,24 +149,13 @@ With the `uid` of the task, you can check the status (`enqueued`, `canceled`, `p #### Basic Search ```swift - -let semaphore = DispatchSemaphore(value: 0) - -// Typealias that represents the result from Meilisearch. -typealias MeiliResult = Result, Swift.Error> - -// Call the function search and wait for the closure result. -client.index("movies").search(SearchParameters( query: "philoudelphia" )) { (result: MeiliResult) in - switch result { - case .success(let searchResult): - dump(searchResult) - case .failure(let error): - print(error.localizedDescription) - } - semaphore.signal() +do { + // Call the search function and wait for the result. + let result: SearchResult = try await client.index("movies").search(SearchParameters(query: "philoudelphia")) + dump(result) +} catch { + print(error.localizedDescription) } -semaphore.wait() - ``` Output: @@ -191,6 +180,8 @@ Output: Since Meilisearch is typo-tolerant, the movie `philadelphia` is a valid search response to `philoudelphia`. +> Note: All package APIs support closure-based results for backwards compatibility. Newer async/await variants are being added under [issue 332](https://github.com/meilisearch/meilisearch-swift/issues/332). + ## 🤖 Compatibility with Meilisearch This package guarantees compatibility with [version v1.x of Meilisearch](https://github.com/meilisearch/meilisearch/releases/latest), but some features may not be present. Please check the [issues](https://github.com/meilisearch/meilisearch-swift/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22+label%3Aenhancement) for more info. diff --git a/Sources/MeiliSearch/Async/Indexes+async.swift b/Sources/MeiliSearch/Async/Indexes+async.swift new file mode 100644 index 00000000..69380154 --- /dev/null +++ b/Sources/MeiliSearch/Async/Indexes+async.swift @@ -0,0 +1,19 @@ +import Foundation + +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +extension Indexes { + /** + Search in the index. + + - Parameter searchParameters: Options on search. + - Throws: Error if a failure occurred. + - Returns: On completion if the request was successful a `Searchable` instance is returned containing the values. + */ + public func search(_ searchParameters: SearchParameters) async throws -> Searchable { + try await withCheckedThrowingContinuation { continuation in + self.search.search(self.uid, searchParameters) { result in + continuation.resume(with: result) + } + } + } +} diff --git a/Sources/MeiliSearch/Indexes.swift b/Sources/MeiliSearch/Indexes.swift index e42cdfa2..0f17f895 100755 --- a/Sources/MeiliSearch/Indexes.swift +++ b/Sources/MeiliSearch/Indexes.swift @@ -26,7 +26,7 @@ public struct Indexes { private let documents: Documents // Search methods - private let search: Search + internal let search: Search // Settings methods private let settings: Settings diff --git a/Tests/MeiliSearchUnitTests/SearchTests.swift b/Tests/MeiliSearchUnitTests/SearchTests.swift index 506b7caa..a1a42f71 100644 --- a/Tests/MeiliSearchUnitTests/SearchTests.swift +++ b/Tests/MeiliSearchUnitTests/SearchTests.swift @@ -80,6 +80,46 @@ class SearchTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } + + @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) + func testSearchForBotmanMovieAsync() async throws { + let jsonString = """ + { + "hits": [ + { + "id": 29751, + "title": "Batman Unmasked: The Psychology of the Dark Knight", + "poster": "https://image.tmdb.org/t/p/w1280/jjHu128XLARc2k4cJrblAvZe0HE.jpg", + "overview": "Delve into the world of Batman and the vigilante justice tha", + "release_date": "2020-04-04T19:59:49.259572Z" + }, + { + "id": 471474, + "title": "Batman: Gotham by Gaslight", + "poster": "https://image.tmdb.org/t/p/w1280/7souLi5zqQCnpZVghaXv0Wowi0y.jpg", + "overview": "ve Victorian Age Gotham City, Batman begins his war on crime", + "release_date": "2020-04-04T19:59:49.259572Z" + } + ], + "offset": 0, + "limit": 20, + "processingTimeMs": 2, + "estimatedTotalHits": 2, + "query": "botman" + } + """ + + // Prepare the mock server + let data = jsonString.data(using: .utf8)! + let stubSearchResult: Searchable = try! Constants.customJSONDecoder.decode(Searchable.self, from: data) + session.pushData(jsonString) + + // Start the test with the mocked server + let searchParameters = SearchParameters.query("botman") + + let searchResult: Searchable = try await self.index.search(searchParameters) + XCTAssertEqual(stubSearchResult, searchResult) + } func testSearchForBotmanMovieFacets() { let jsonString = """