From 0ee478f92d5ccef24d644e588b741f19e9addae9 Mon Sep 17 00:00:00 2001 From: James Sherlock <15193942+Sherlouk@users.noreply.github.com> Date: Thu, 28 Sep 2023 21:03:32 +0100 Subject: [PATCH 1/7] Fix Xcode 15 URL Bug Confirmed regression with Xcode 15 upgrade, this change reverts back to original solution. We may wish to improve input validation in a future commit. --- README.md | 1 + Sources/MeiliSearch/Config.swift | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c245ed87..194a6f95 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ To do a simple search using the client, you can create a Swift script like this: import MeiliSearch // Create a new client instance of Meilisearch. + // Note: you should provide a fully qualified URL, with scheme, into the client initialiser. let client = try! MeiliSearch(host: "http://localhost:7700") struct Movie: Codable, Equatable { diff --git a/Sources/MeiliSearch/Config.swift b/Sources/MeiliSearch/Config.swift index 5dec4234..c3a1681d 100755 --- a/Sources/MeiliSearch/Config.swift +++ b/Sources/MeiliSearch/Config.swift @@ -47,8 +47,14 @@ public class Config { Validate if the Meilisearch provided host is a well formatted URL. */ func validate() throws -> Config { - guard URL(string: host) != nil else { - throw MeiliSearch.Error.hostNotValid + if #available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) { + guard URL(string: host, encodingInvalidCharacters: false) != nil else { + throw MeiliSearch.Error.hostNotValid + } + } else { + guard URL(string: host) != nil else { + throw MeiliSearch.Error.hostNotValid + } } return self } From 637b2bce721c34a61bcca41e7a29775957e1feb8 Mon Sep 17 00:00:00 2001 From: James Sherlock <15193942+Sherlouk@users.noreply.github.com> Date: Thu, 28 Sep 2023 21:05:47 +0100 Subject: [PATCH 2/7] Reduce Document Protocol Conformance Requirements Previously we were requiring Codable (Decodable & Encodable) and Equatable protocol conformance on all documents returned by a search. For a simple read-only client this is unnecesary complexity. This is a simple non-breaking tweak to make it easier for clients. --- Sources/MeiliSearch/Async/Indexes+async.swift | 2 +- Sources/MeiliSearch/Indexes.swift | 2 +- Sources/MeiliSearch/Search.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/MeiliSearch/Async/Indexes+async.swift b/Sources/MeiliSearch/Async/Indexes+async.swift index 69380154..13757d7a 100644 --- a/Sources/MeiliSearch/Async/Indexes+async.swift +++ b/Sources/MeiliSearch/Async/Indexes+async.swift @@ -9,7 +9,7 @@ extension Indexes { - 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 { + 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 0f17f895..3a2c6d9d 100755 --- a/Sources/MeiliSearch/Indexes.swift +++ b/Sources/MeiliSearch/Indexes.swift @@ -465,7 +465,7 @@ public struct Indexes { public func search( _ searchParameters: SearchParameters, _ completion: @escaping (Result, Swift.Error>) -> Void) - where T: Codable, T: Equatable { + where T: Decodable { self.search.search(self.uid, searchParameters, completion) } diff --git a/Sources/MeiliSearch/Search.swift b/Sources/MeiliSearch/Search.swift index 101b0bf4..1e8b8133 100644 --- a/Sources/MeiliSearch/Search.swift +++ b/Sources/MeiliSearch/Search.swift @@ -18,7 +18,7 @@ struct Search { _ uid: String, _ searchParameters: SearchParameters, _ completion: @escaping (Result, Swift.Error>) -> Void) - where T: Codable, T: Equatable { + where T: Decodable { let data: Data do { data = try JSONEncoder().encode(searchParameters) From 3f9e1815cd3d584163b842f1c03ba12ef0ff7474 Mon Sep 17 00:00:00 2001 From: James Sherlock <15193942+Sherlouk@users.noreply.github.com> Date: Thu, 28 Sep 2023 21:11:52 +0100 Subject: [PATCH 3/7] Add a search with filters area to README --- README.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/README.md b/README.md index 194a6f95..857f2426 100644 --- a/README.md +++ b/README.md @@ -183,6 +183,48 @@ Since Meilisearch is typo-tolerant, the movie `philadelphia` is a valid search r > 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). +#### Custom Search With Filters + +If you want to enable filtering, you must add your attributes to the `filterableAttributes` index setting. + +```swift +index.updateFilterableAttributes(["id", "genres"]) { result in + // Handle Result in Closure +} +``` + +You only need to perform this operation once. + +Note that MeiliSearch will rebuild your index whenever you update `filterableAttributes`. Depending on the size of your dataset, this might take time. You can track the process using the [update status](https://docs.meilisearch.com/reference/api/updates.html#get-an-update-status). + +Then, you can perform the search: + +```swift +let searchParameters = SearchParameters( + query: "wonder", + filter: "id > 1 AND genres = Action" +) + +let response: Searchable = try await index.search(searchParameters) +``` + +```json +{ + "hits": [ + { + "id": 2, + "title": "Wonder Woman", + "genres": ["Action","Adventure"] + } + ], + "offset": 0, + "limit": 20, + "nbHits": 1, + "processingTimeMs": 0, + "query": "wonder" +} +``` + ## 🤖 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. From 31409711f309217cc80a8c913afa28e270b9cacf Mon Sep 17 00:00:00 2001 From: James Sherlock <15193942+Sherlouk@users.noreply.github.com> Date: Thu, 28 Sep 2023 21:28:31 +0100 Subject: [PATCH 4/7] Tweak Solution for Backwards Compatibility This isn't as resilient as it was previously, but catches a very common use case. Docs updated. --- README.md | 13 ++++++++++++- Sources/MeiliSearch/Config.swift | 13 +++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 857f2426..b6fe07a0 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,18 @@ curl -L https://install.meilisearch.com | sh NB: you can also download Meilisearch from **Homebrew** or **APT** or even run it using **Docker**. +### Import + +After installing `meilisearch-swift`, you must import it into your application. + +```swift +import MeiliSearch + +let client = try! MeiliSearch(host: "http://localhost:7700") +``` + +When initialising the MeiliSearch client, you must provide a fully qualified URL including scheme. + ## 🎬 Getting started To do a simple search using the client, you can create a Swift script like this: @@ -105,7 +117,6 @@ To do a simple search using the client, you can create a Swift script like this: import MeiliSearch // Create a new client instance of Meilisearch. - // Note: you should provide a fully qualified URL, with scheme, into the client initialiser. let client = try! MeiliSearch(host: "http://localhost:7700") struct Movie: Codable, Equatable { diff --git a/Sources/MeiliSearch/Config.swift b/Sources/MeiliSearch/Config.swift index c3a1681d..90b8a113 100755 --- a/Sources/MeiliSearch/Config.swift +++ b/Sources/MeiliSearch/Config.swift @@ -47,14 +47,11 @@ public class Config { Validate if the Meilisearch provided host is a well formatted URL. */ func validate() throws -> Config { - if #available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) { - guard URL(string: host, encodingInvalidCharacters: false) != nil else { - throw MeiliSearch.Error.hostNotValid - } - } else { - guard URL(string: host) != nil else { - throw MeiliSearch.Error.hostNotValid - } + guard let url = URL(string: host) else { + throw MeiliSearch.Error.hostNotValid + } + if url.scheme == nil { + throw MeiliSearch.Error.hostNotValid } return self } From 4bf8c1fb8c127bb3e2021f480abe72dfe4bd4979 Mon Sep 17 00:00:00 2001 From: James Sherlock <15193942+Sherlouk@users.noreply.github.com> Date: Thu, 28 Sep 2023 21:32:42 +0100 Subject: [PATCH 5/7] Update Incorrect Test 1234 is not a valid URL and shouldn't have passed in the first place. --- Tests/MeiliSearchUnitTests/ClientTests.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/MeiliSearchUnitTests/ClientTests.swift b/Tests/MeiliSearchUnitTests/ClientTests.swift index 1a2caa30..66d87836 100644 --- a/Tests/MeiliSearchUnitTests/ClientTests.swift +++ b/Tests/MeiliSearchUnitTests/ClientTests.swift @@ -13,7 +13,9 @@ class ClientTests: XCTestCase { } func testWrongHostURL() { - XCTAssertNotNil(try MeiliSearch(host: "1234")) + XCTAssertThrowsError(try MeiliSearch(host: "1234")) { error in + XCTAssertEqual(error as! MeiliSearch.Error, MeiliSearch.Error.hostNotValid) + } } func testNotValidHostURL() { From 55f7e2571ebdfb6b1414efed92f610b1aced10e9 Mon Sep 17 00:00:00 2001 From: James Sherlock <15193942+Sherlouk@users.noreply.github.com> Date: Mon, 2 Oct 2023 21:41:41 +0100 Subject: [PATCH 6/7] Patch Old Swift Compatibility No functionality change other than using an approach which is compatible with more versions of Swift, addressing some issues caused by other PRs --- Sources/MeiliSearch/Settings.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/MeiliSearch/Settings.swift b/Sources/MeiliSearch/Settings.swift index 58b4bfe4..1291c26d 100644 --- a/Sources/MeiliSearch/Settings.swift +++ b/Sources/MeiliSearch/Settings.swift @@ -445,10 +445,10 @@ struct Settings { } } - private func updateSetting( + private func updateSetting( uid: String, key: String?, - data: Encodable, + data: T, completion: @escaping (Result) -> Void ) { let body: Data From 4d93a1139728a0fd3c7c79e8e2c86f9fcd6d93d9 Mon Sep 17 00:00:00 2001 From: James Sherlock <15193942+Sherlouk@users.noreply.github.com> Date: Thu, 5 Oct 2023 11:05:55 +0100 Subject: [PATCH 7/7] Simplify README --- README.md | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/README.md b/README.md index b6fe07a0..c63689ef 100644 --- a/README.md +++ b/README.md @@ -95,18 +95,6 @@ curl -L https://install.meilisearch.com | sh NB: you can also download Meilisearch from **Homebrew** or **APT** or even run it using **Docker**. -### Import - -After installing `meilisearch-swift`, you must import it into your application. - -```swift -import MeiliSearch - -let client = try! MeiliSearch(host: "http://localhost:7700") -``` - -When initialising the MeiliSearch client, you must provide a fully qualified URL including scheme. - ## 🎬 Getting started To do a simple search using the client, you can create a Swift script like this: @@ -117,6 +105,7 @@ To do a simple search using the client, you can create a Swift script like this: import MeiliSearch // Create a new client instance of Meilisearch. + // Note: You must provide a fully qualified URL including scheme. let client = try! MeiliSearch(host: "http://localhost:7700") struct Movie: Codable, Equatable {