From 742008b231287d19dcfe033d48cb3591e506a092 Mon Sep 17 00:00:00 2001 From: James Sherlock <15193942+Sherlouk@users.noreply.github.com> Date: Sun, 17 Sep 2023 00:44:58 +0100 Subject: [PATCH 1/8] Add internal typo-tolerance settings APIs --- Sources/MeiliSearch/Model/Setting.swift | 2 +- Sources/MeiliSearch/Model/TypoTolerance.swift | 48 ++++++++++++ .../Model/TypoToleranceResult.swift | 28 +++++++ Sources/MeiliSearch/Settings.swift | 76 +++++++++++++++++++ 4 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 Sources/MeiliSearch/Model/TypoTolerance.swift create mode 100644 Sources/MeiliSearch/Model/TypoToleranceResult.swift diff --git a/Sources/MeiliSearch/Model/Setting.swift b/Sources/MeiliSearch/Model/Setting.swift index a5fe4b04..26bb4dfe 100644 --- a/Sources/MeiliSearch/Model/Setting.swift +++ b/Sources/MeiliSearch/Model/Setting.swift @@ -4,7 +4,7 @@ import Foundation #endif /** - Settings object provided byb the user + Settings object provided by the user */ public struct Setting: Codable, Equatable { // MARK: Properties diff --git a/Sources/MeiliSearch/Model/TypoTolerance.swift b/Sources/MeiliSearch/Model/TypoTolerance.swift new file mode 100644 index 00000000..98b871a8 --- /dev/null +++ b/Sources/MeiliSearch/Model/TypoTolerance.swift @@ -0,0 +1,48 @@ +import Foundation + +/** + `TypoTolerance` settings provided by the user. + */ +public struct TypoTolerance: Codable, Equatable { + // MARK: Properties + + /// Whether typo tolerance is enabled or not + public let enabled: Bool? + + /// The minimum word size for accepting typos + public let minWordSizeForTypos: MinWordSize? + + /// An array of words for which the typo tolerance feature is disabled + public let disableOnWords: [String]? + + /// An array of attributes for which the typo tolerance feature is disabled + public let disableOnAttributes: [String]? + + public struct MinWordSize: Codable, Equatable { + /// The minimum word size for accepting 1 typo; must be between 0 and `twoTypos` + public let oneTypo: Int? + + /// The minimum word size for accepting 2 typos; must be between `oneTypo` and 255 + public let twoTypos: Int? + + public init( + oneTypo: Int? = nil, + twoTypos: Int? = nil + ) { + self.oneTypo = oneTypo + self.twoTypos = twoTypos + } + } + + public init( + enabled: Bool? = nil, + minWordSizeForTypos: TypoTolerance.MinWordSize? = nil, + disableOnWords: [String]? = nil, + disableOnAttributes: [String]? = nil + ) { + self.enabled = enabled + self.minWordSizeForTypos = minWordSizeForTypos + self.disableOnWords = disableOnWords + self.disableOnAttributes = disableOnAttributes + } +} diff --git a/Sources/MeiliSearch/Model/TypoToleranceResult.swift b/Sources/MeiliSearch/Model/TypoToleranceResult.swift new file mode 100644 index 00000000..d49c0b4d --- /dev/null +++ b/Sources/MeiliSearch/Model/TypoToleranceResult.swift @@ -0,0 +1,28 @@ +import Foundation + +/** + `TypoToleranceResult` instances represent the current typo tolerance settings. + */ +public struct TypoToleranceResult: Codable, Equatable { + // MARK: Properties + + /// Whether typo tolerance is enabled or not + public let enabled: Bool + + /// The minimum word size for accepting typos + public let minWordSizeForTypos: MinWordSize + + /// An array of words for which the typo tolerance feature is disabled + public let disableOnWords: [String] + + /// An array of attributes for which the typo tolerance feature is disabled + public let disableOnAttributes: [String] + + public struct MinWordSize: Codable, Equatable { + /// The minimum word size for accepting 1 typo; must be between 0 and `twoTypos` + public let oneTypo: Int + + /// The minimum word size for accepting 2 typos; must be between `oneTypo` and 255 + public let twoTypos: Int + } +} diff --git a/Sources/MeiliSearch/Settings.swift b/Sources/MeiliSearch/Settings.swift index 92c1937c..28cc9b20 100644 --- a/Sources/MeiliSearch/Settings.swift +++ b/Sources/MeiliSearch/Settings.swift @@ -456,4 +456,80 @@ struct Settings { } } } + + // MARK: Typo Tolerance + + func getTypoTolerance( + _ uid: String, + _ completion: @escaping (Result) -> Void) { + + self.request.get(api: "/indexes/\(uid)/settings/typo-tolerance") { result in + switch result { + case .success(let data): + guard let data: Data = data else { + completion(.failure(MeiliSearch.Error.dataNotFound)) + return + } + do { + let response: TypoToleranceResult = try Constants.customJSONDecoder.decode(TypoToleranceResult.self, from: data) + completion(.success(response)) + } catch { + completion(.failure(error)) + } + case .failure(let error): + completion(.failure(error)) + } + } + } + + func updateTypoTolerance( + _ uid: String, + _ setting: TypoTolerance, + _ completion: @escaping (Result) -> Void) { + + let data: Data + do { + data = try JSONEncoder().encode(setting) + } catch { + completion(.failure(error)) + return + } + + self.request.put(api: "/indexes/\(uid)/settings/typo-tolerance", data) { result in + switch result { + case .success(let data): + do { + let task: TaskInfo = try Constants.customJSONDecoder.decode(TaskInfo.self, from: data) + completion(.success(task)) + } catch { + completion(.failure(error)) + } + case .failure(let error): + completion(.failure(error)) + } + } + } + + func resetTypoTolerance( + _ uid: String, + _ completion: @escaping (Result) -> Void) { + + self.request.delete(api: "/indexes/\(uid)/settings/typo-tolerance") { result in + switch result { + case .success(let data): + guard let data: Data = data else { + completion(.failure(MeiliSearch.Error.dataNotFound)) + return + } + do { + let task: TaskInfo = try Constants.customJSONDecoder.decode(TaskInfo.self, from: data) + completion(.success(task)) + } catch { + completion(.failure(error)) + } + case .failure(let error): + completion(.failure(error)) + } + } + } } From f7495d7adfc7981f1cfddc0ae1ce23a5365ddc4b Mon Sep 17 00:00:00 2001 From: James Sherlock <15193942+Sherlouk@users.noreply.github.com> Date: Sun, 17 Sep 2023 00:48:22 +0100 Subject: [PATCH 2/8] Add public typo-tolerance settings APIs --- Sources/MeiliSearch/Indexes.swift | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Sources/MeiliSearch/Indexes.swift b/Sources/MeiliSearch/Indexes.swift index 97e625dc..e42cdfa2 100755 --- a/Sources/MeiliSearch/Indexes.swift +++ b/Sources/MeiliSearch/Indexes.swift @@ -1028,6 +1028,46 @@ public struct Indexes { self.settings.resetPaginationSettings(self.uid, completion) } + // MARK: Typo Tolerance + + /** + Get the typo tolerance settings. + + - parameter completion: The completion closure is used to notify when the server + completes the query request, it returns a `Result` object that contains a `TypoToleranceResult` + value if the request was successful, or `Error` if a failure occurred. + */ + public func getTypoTolerance( + _ completion: @escaping (Result) -> Void) { + self.settings.getTypoTolerance(self.uid, completion) + } + + /** + Update the typo tolerance settings. + + - parameter typoTolerance: An object containing the settings for the `Index`. + - parameter completion: The completion closure is used to notify when the server + completes the query request, it returns a `Result` object that contains `TaskInfo` + value if the request was successful, or `Error` if a failure occurred. + */ + public func updateTypoTolerance( + _ typoTolerance: TypoTolerance, + _ completion: @escaping (Result) -> Void) { + self.settings.updateTypoTolerance(self.uid, typoTolerance, completion) + } + + /** + Reset the typo tolerance settings. + + - parameter completion: The completion closure is used to notify when the server + completes the query request, it returns a `Result` object that contains `TaskInfo` + value if the request was successful, or `Error` if a failure occurred. + */ + public func resetTypoTolerance( + _ completion: @escaping (Result) -> Void) { + self.settings.resetTypoTolerance(self.uid, completion) + } + // MARK: Stats /** From df2c34eb823ce3d1828bedcebf2eda91fa41ff42 Mon Sep 17 00:00:00 2001 From: James Sherlock <15193942+Sherlouk@users.noreply.github.com> Date: Sun, 17 Sep 2023 00:54:07 +0100 Subject: [PATCH 3/8] Add unit tests for typo-tolerance APIs --- .../MeiliSearchUnitTests/SettingsTests.swift | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/Tests/MeiliSearchUnitTests/SettingsTests.swift b/Tests/MeiliSearchUnitTests/SettingsTests.swift index 5299818a..e7259fc8 100644 --- a/Tests/MeiliSearchUnitTests/SettingsTests.swift +++ b/Tests/MeiliSearchUnitTests/SettingsTests.swift @@ -852,6 +852,94 @@ class SettingsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } + + // MARK: Typo Tolerance + + func testGetTypoTolerance() { + let jsonString = """ + {"enabled":true,"minWordSizeForTypos":{"oneTypo":3,"twoTypos":7},"disableOnWords":["of", "the"],"disableOnAttributes":["genre"]} + """ + + // Prepare the mock server + session.pushData(jsonString) + + // Start the test with the mocked server + let expectation = XCTestExpectation(description: "Get displayed attribute") + + self.index.getTypoTolerance { result in + switch result { + case .success(let typoTolerance): + XCTAssertTrue(typoTolerance.enabled) + XCTAssertEqual(typoTolerance.minWordSizeForTypos.oneTypo, 3) + XCTAssertEqual(typoTolerance.minWordSizeForTypos.twoTypos, 7) + XCTAssertFalse(typoTolerance.disableOnWords.isEmpty) + XCTAssertFalse(typoTolerance.disableOnAttributes.isEmpty) + case .failure: + XCTFail("Failed to get displayed attribute") + } + expectation.fulfill() + } + + self.wait(for: [expectation], timeout: TESTS_TIME_OUT) + } + + func testUpdateTypoTolerance() { + let jsonString = """ + {"taskUid":0,"indexUid":"movies_test","status":"enqueued","type":"settingsUpdate","enqueuedAt":"2022-07-27T19:03:50.494232841Z"} + """ + + // Prepare the mock server + let decoder = JSONDecoder() + let stubTask: TaskInfo = try! decoder.decode( + TaskInfo.self, + from: jsonString.data(using: .utf8)!) + + session.pushData(jsonString) + let typoTolerance: TypoTolerance = .init(enabled: false) + + // Start the test with the mocked server + let expectation = XCTestExpectation(description: "Update displayed attribute") + + self.index.updateTypoTolerance(typoTolerance) { result in + switch result { + case .success(let update): + XCTAssertEqual(stubTask, update) + case .failure: + XCTFail("Failed to update displayed attribute") + } + expectation.fulfill() + } + + self.wait(for: [expectation], timeout: TESTS_TIME_OUT) + } + + func testResetTypoTolerance() { + let jsonString = """ + {"taskUid":0,"indexUid":"movies_test","status":"enqueued","type":"settingsUpdate","enqueuedAt":"2022-07-27T19:03:50.494232841Z"} + """ + + // Prepare the mock server + let decoder = JSONDecoder() + let stubTask: TaskInfo = try! decoder.decode( + TaskInfo.self, + from: jsonString.data(using: .utf8)!) + session.pushData(jsonString) + + // Start the test with the mocked server + let expectation = XCTestExpectation(description: "Update displayed attribute") + + self.index.resetTypoTolerance { result in + switch result { + case .success(let update): + XCTAssertEqual(stubTask, update) + case .failure: + XCTFail("Failed to update displayed attribute") + } + expectation.fulfill() + } + + self.wait(for: [expectation], timeout: TESTS_TIME_OUT) + } private func buildStubSetting(from json: String) throws -> Setting { let data = Data(json.utf8) From c494b5f90f4de7fec876fee5609b9ce4bf75c594 Mon Sep 17 00:00:00 2001 From: James Sherlock <15193942+Sherlouk@users.noreply.github.com> Date: Sun, 17 Sep 2023 01:03:23 +0100 Subject: [PATCH 4/8] Add integration tests for typo-tolerance APIs --- Sources/MeiliSearch/Model/Task.swift | 2 + Sources/MeiliSearch/Settings.swift | 2 +- .../SettingsTests.swift | 100 ++++++++++++++++++ 3 files changed, 103 insertions(+), 1 deletion(-) diff --git a/Sources/MeiliSearch/Model/Task.swift b/Sources/MeiliSearch/Model/Task.swift index 476c87d3..13a85a3b 100644 --- a/Sources/MeiliSearch/Model/Task.swift +++ b/Sources/MeiliSearch/Model/Task.swift @@ -88,6 +88,8 @@ public struct Task: Codable, Equatable { /// Settings for index level pagination rules public let pagination: Pagination? + /// Typo tolerance on settings actions + public let typoTolerance: TypoTolerance? } /// Error information in case of failed update. public let error: MeiliSearch.MSErrorResponse? diff --git a/Sources/MeiliSearch/Settings.swift b/Sources/MeiliSearch/Settings.swift index 28cc9b20..fd3c2738 100644 --- a/Sources/MeiliSearch/Settings.swift +++ b/Sources/MeiliSearch/Settings.swift @@ -495,7 +495,7 @@ struct Settings { return } - self.request.put(api: "/indexes/\(uid)/settings/typo-tolerance", data) { result in + self.request.patch(api: "/indexes/\(uid)/settings/typo-tolerance", data) { result in switch result { case .success(let data): do { diff --git a/Tests/MeiliSearchIntegrationTests/SettingsTests.swift b/Tests/MeiliSearchIntegrationTests/SettingsTests.swift index d28d51a0..5615377d 100644 --- a/Tests/MeiliSearchIntegrationTests/SettingsTests.swift +++ b/Tests/MeiliSearchIntegrationTests/SettingsTests.swift @@ -31,6 +31,12 @@ class SettingsTests: XCTestCase { private let defaultStopWords: [String] = [] private let defaultSynonyms: [String: [String]] = [:] private let defaultPagination: Pagination = .init(maxTotalHits: 1000) + private let defaultTypoToleranceResult: TypoToleranceResult = .init( + enabled: true, + minWordSizeForTypos: .init(oneTypo: 5, twoTypos: 9), + disableOnWords: [], + disableOnAttributes: [] + ) private var defaultGlobalSettings: Setting? private var defaultGlobalReturnedSettings: SettingResult? @@ -525,6 +531,100 @@ class SettingsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } + // MARK: Typo Tolerance + + func testGetTypoTolerance() { + let expectation = XCTestExpectation(description: "Get current typo tolerance") + + self.index.getTypoTolerance { result in + switch result { + case .success(let typoTolerance): + XCTAssertEqual(self.defaultTypoToleranceResult, typoTolerance) + expectation.fulfill() + case .failure(let error): + dump(error) + XCTFail("Failed to get typo tolerance") + expectation.fulfill() + } + } + + self.wait(for: [expectation], timeout: TESTS_TIME_OUT) + } + + func testUpdateTypoTolerance() { + let expectation = XCTestExpectation(description: "Update settings for typo tolerance") + + let newTypoTolerance: TypoTolerance = .init( + minWordSizeForTypos: .init( + oneTypo: 1, + twoTypos: 2 + ), + disableOnWords: ["to"], + disableOnAttributes: ["genre"] + ) + + self.index.updateTypoTolerance(newTypoTolerance) { result in + switch result { + case .success(let task): + self.client.waitForTask(task: task) { result in + switch result { + case .success(let task): + XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual(Task.Status.succeeded, task.status) + if let details = task.details { + if let typoTolerance = details.typoTolerance { + XCTAssertEqual(newTypoTolerance, typoTolerance) + } else { + XCTFail("typoTolerance should not be nil") + } + } else { + XCTFail("details should exists in details field of task") + } + expectation.fulfill() + case .failure(let error): + dump(error) + XCTFail("Failed to wait for task") + expectation.fulfill() + } + } + case .failure(let error): + dump(error) + XCTFail("Failed updating typo tolerance") + expectation.fulfill() + } + } + + self.wait(for: [expectation], timeout: TESTS_TIME_OUT) + } + + func testResetTypoTolerance() { + let expectation = XCTestExpectation(description: "Reset settings for typo tolerance") + + self.index.resetTypoTolerance { result in + switch result { + case .success(let task): + self.client.waitForTask(task: task) { result in + switch result { + case .success(let task): + XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual(Task.Status.succeeded, task.status) + expectation.fulfill() + case .failure(let error): + dump(error) + XCTFail("Failed to wait for task") + expectation.fulfill() + } + } + case .failure(let error): + dump(error) + XCTFail("Failed reseting typo tolerance") + expectation.fulfill() + } + } + + self.wait(for: [expectation], timeout: TESTS_TIME_OUT) + } + // MARK: Separator Tokens func testGetSeparatorTokens() { From 9a7db09219c1a4374b0d147fea1e4c5eda95f335 Mon Sep 17 00:00:00 2001 From: James Sherlock <15193942+Sherlouk@users.noreply.github.com> Date: Sun, 17 Sep 2023 01:08:45 +0100 Subject: [PATCH 5/8] Add typo-tolerance to existing settings APIs --- Sources/MeiliSearch/Model/Setting.swift | 7 ++++++- Sources/MeiliSearch/Model/SettingResult.swift | 3 +++ .../SettingsTests.swift | 21 ++++++++++++++----- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/Sources/MeiliSearch/Model/Setting.swift b/Sources/MeiliSearch/Model/Setting.swift index 26bb4dfe..7d46daba 100644 --- a/Sources/MeiliSearch/Model/Setting.swift +++ b/Sources/MeiliSearch/Model/Setting.swift @@ -33,6 +33,9 @@ public struct Setting: Codable, Equatable { /// List of attributes used for sorting public let sortableAttributes: [String]? + /// Settings for typo tolerance + public let typoTolerance: TypoTolerance? + /// List of tokens that will be considered as word separators by Meilisearch. public let separatorTokens: [String]? @@ -59,7 +62,8 @@ public struct Setting: Codable, Equatable { separatorTokens: [String]? = nil, nonSeparatorTokens: [String]? = nil, dictionary: [String]? = nil, - pagination: Pagination? = nil + pagination: Pagination? = nil, + typoTolerance: TypoTolerance? = nil ) { self.rankingRules = rankingRules self.searchableAttributes = searchableAttributes @@ -73,5 +77,6 @@ public struct Setting: Codable, Equatable { self.separatorTokens = separatorTokens self.dictionary = dictionary self.pagination = pagination + self.typoTolerance = typoTolerance } } diff --git a/Sources/MeiliSearch/Model/SettingResult.swift b/Sources/MeiliSearch/Model/SettingResult.swift index 2ce7fcc1..ae5efecf 100644 --- a/Sources/MeiliSearch/Model/SettingResult.swift +++ b/Sources/MeiliSearch/Model/SettingResult.swift @@ -39,4 +39,7 @@ public struct SettingResult: Codable, Equatable { /// Pagination settings for the current index public let pagination: Pagination + + /// Settings for typo tolerance + public let typoTolerance: TypoToleranceResult } diff --git a/Tests/MeiliSearchIntegrationTests/SettingsTests.swift b/Tests/MeiliSearchIntegrationTests/SettingsTests.swift index 5615377d..6fda8e84 100644 --- a/Tests/MeiliSearchIntegrationTests/SettingsTests.swift +++ b/Tests/MeiliSearchIntegrationTests/SettingsTests.swift @@ -31,6 +31,12 @@ class SettingsTests: XCTestCase { private let defaultStopWords: [String] = [] private let defaultSynonyms: [String: [String]] = [:] private let defaultPagination: Pagination = .init(maxTotalHits: 1000) + private let defaultTypoTolerance: TypoTolerance = .init( + enabled: true, + minWordSizeForTypos: .init(oneTypo: 5, twoTypos: 9), + disableOnWords: [], + disableOnAttributes: [] + ) private let defaultTypoToleranceResult: TypoToleranceResult = .init( enabled: true, minWordSizeForTypos: .init(oneTypo: 5, twoTypos: 9), @@ -74,7 +80,8 @@ class SettingsTests: XCTestCase { separatorTokens: self.defaultSeparatorTokens, nonSeparatorTokens: self.defaultNonSeparatorTokens, dictionary: self.defaultDictionary, - pagination: self.defaultPagination + pagination: self.defaultPagination, + typoTolerance: self.defaultTypoTolerance ) self.defaultGlobalReturnedSettings = SettingResult( @@ -89,7 +96,8 @@ class SettingsTests: XCTestCase { separatorTokens: self.defaultSeparatorTokens, nonSeparatorTokens: self.defaultNonSeparatorTokens, dictionary: self.defaultDictionary, - pagination: self.defaultPagination + pagination: self.defaultPagination, + typoTolerance: self.defaultTypoToleranceResult ) } @@ -1360,7 +1368,8 @@ class SettingsTests: XCTestCase { separatorTokens: [], nonSeparatorTokens: [], dictionary: [], - pagination: .init(maxTotalHits: 1000) + pagination: .init(maxTotalHits: 1000), + typoTolerance: defaultTypoToleranceResult ) let expectation = XCTestExpectation(description: "Update settings") @@ -1441,7 +1450,8 @@ class SettingsTests: XCTestCase { separatorTokens: ["&"], nonSeparatorTokens: ["#"], dictionary: ["J.K"], - pagination: .init(maxTotalHits: 500) + pagination: .init(maxTotalHits: 500), + typoTolerance: nil ) let expectedSettingResult = SettingResult( @@ -1456,7 +1466,8 @@ class SettingsTests: XCTestCase { separatorTokens: ["&"], nonSeparatorTokens: ["#"], dictionary: ["J.K"], - pagination: .init(maxTotalHits: 500) + pagination: .init(maxTotalHits: 500), + typoTolerance: defaultTypoToleranceResult ) self.index.updateSettings(newSettings) { result in From 62ae002a1ae8b597e9a6d88bdcf44b0127147f2c Mon Sep 17 00:00:00 2001 From: James Sherlock <15193942+Sherlouk@users.noreply.github.com> Date: Sun, 17 Sep 2023 11:36:37 +0100 Subject: [PATCH 6/8] Run SwiftLint (and fix formatting issues) --- Sources/MeiliSearch/Model/TypoTolerance.swift | 10 +++++----- Sources/MeiliSearch/Model/TypoToleranceResult.swift | 4 ++-- Sources/MeiliSearch/Settings.swift | 2 +- Tests/MeiliSearchUnitTests/SettingsTests.swift | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Sources/MeiliSearch/Model/TypoTolerance.swift b/Sources/MeiliSearch/Model/TypoTolerance.swift index 98b871a8..c11b0ef4 100644 --- a/Sources/MeiliSearch/Model/TypoTolerance.swift +++ b/Sources/MeiliSearch/Model/TypoTolerance.swift @@ -17,14 +17,14 @@ public struct TypoTolerance: Codable, Equatable { /// An array of attributes for which the typo tolerance feature is disabled public let disableOnAttributes: [String]? - + public struct MinWordSize: Codable, Equatable { /// The minimum word size for accepting 1 typo; must be between 0 and `twoTypos` public let oneTypo: Int? - + /// The minimum word size for accepting 2 typos; must be between `oneTypo` and 255 public let twoTypos: Int? - + public init( oneTypo: Int? = nil, twoTypos: Int? = nil @@ -33,9 +33,9 @@ public struct TypoTolerance: Codable, Equatable { self.twoTypos = twoTypos } } - + public init( - enabled: Bool? = nil, + enabled: Bool? = nil, minWordSizeForTypos: TypoTolerance.MinWordSize? = nil, disableOnWords: [String]? = nil, disableOnAttributes: [String]? = nil diff --git a/Sources/MeiliSearch/Model/TypoToleranceResult.swift b/Sources/MeiliSearch/Model/TypoToleranceResult.swift index d49c0b4d..0a849e73 100644 --- a/Sources/MeiliSearch/Model/TypoToleranceResult.swift +++ b/Sources/MeiliSearch/Model/TypoToleranceResult.swift @@ -17,11 +17,11 @@ public struct TypoToleranceResult: Codable, Equatable { /// An array of attributes for which the typo tolerance feature is disabled public let disableOnAttributes: [String] - + public struct MinWordSize: Codable, Equatable { /// The minimum word size for accepting 1 typo; must be between 0 and `twoTypos` public let oneTypo: Int - + /// The minimum word size for accepting 2 typos; must be between `oneTypo` and 255 public let twoTypos: Int } diff --git a/Sources/MeiliSearch/Settings.swift b/Sources/MeiliSearch/Settings.swift index fd3c2738..9bc21846 100644 --- a/Sources/MeiliSearch/Settings.swift +++ b/Sources/MeiliSearch/Settings.swift @@ -456,7 +456,7 @@ struct Settings { } } } - + // MARK: Typo Tolerance func getTypoTolerance( diff --git a/Tests/MeiliSearchUnitTests/SettingsTests.swift b/Tests/MeiliSearchUnitTests/SettingsTests.swift index e7259fc8..538c3b7d 100644 --- a/Tests/MeiliSearchUnitTests/SettingsTests.swift +++ b/Tests/MeiliSearchUnitTests/SettingsTests.swift @@ -852,7 +852,7 @@ class SettingsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - + // MARK: Typo Tolerance func testGetTypoTolerance() { From 330acbc88c460972164754ca52289b3d2b266b24 Mon Sep 17 00:00:00 2001 From: James Sherlock <15193942+Sherlouk@users.noreply.github.com> Date: Thu, 21 Sep 2023 23:18:16 +0100 Subject: [PATCH 7/8] Patch Unit Tests --- Tests/MeiliSearchUnitTests/SettingsTests.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Tests/MeiliSearchUnitTests/SettingsTests.swift b/Tests/MeiliSearchUnitTests/SettingsTests.swift index 538c3b7d..642000d9 100644 --- a/Tests/MeiliSearchUnitTests/SettingsTests.swift +++ b/Tests/MeiliSearchUnitTests/SettingsTests.swift @@ -39,6 +39,15 @@ class SettingsTests: XCTestCase { "synonyms": { "wolverine": ["xmen", "logan"], "logan": ["wolverine", "xmen"] + }, + "typoTolerance": { + "enabled": true, + "minWordSizeForTypos": { + "oneTypo": 5, + "twoTypos": 9 + }, + "disableOnWords": [], + "disableOnAttributes": [] } } """ From 8c6620fd49e4c9039ddb324a99ad32384feb8851 Mon Sep 17 00:00:00 2001 From: James Sherlock <15193942+Sherlouk@users.noreply.github.com> Date: Wed, 27 Sep 2023 16:54:16 +0100 Subject: [PATCH 8/8] Refactor after Rebase --- Sources/MeiliSearch/Settings.swift | 121 +++++++++++------------------ 1 file changed, 45 insertions(+), 76 deletions(-) diff --git a/Sources/MeiliSearch/Settings.swift b/Sources/MeiliSearch/Settings.swift index 9bc21846..58b4bfe4 100644 --- a/Sources/MeiliSearch/Settings.swift +++ b/Sources/MeiliSearch/Settings.swift @@ -372,6 +372,51 @@ struct Settings { resetSetting(uid: uid, key: "pagination", completion: completion) } + // MARK: Typo Tolerance + + func getTypoTolerance( + _ uid: String, + _ completion: @escaping (Result) -> Void) { + + getSetting(uid: uid, key: "typo-tolerance", completion: completion) + } + + func updateTypoTolerance( + _ uid: String, + _ setting: TypoTolerance, + _ completion: @escaping (Result) -> Void) { + + let data: Data + do { + data = try JSONEncoder().encode(setting) + } catch { + completion(.failure(error)) + return + } + + // this uses patch instead of put for networking, so shouldn't use the reusable 'updateSetting' function + self.request.patch(api: "/indexes/\(uid)/settings/typo-tolerance", data) { result in + switch result { + case .success(let data): + do { + let task: TaskInfo = try Constants.customJSONDecoder.decode(TaskInfo.self, from: data) + completion(.success(task)) + } catch { + completion(.failure(error)) + } + case .failure(let error): + completion(.failure(error)) + } + } + } + + func resetTypoTolerance( + _ uid: String, + _ completion: @escaping (Result) -> Void) { + + resetSetting(uid: uid, key: "typo-tolerance", completion: completion) + } + // MARK: Reusable Requests private func getSetting( @@ -456,80 +501,4 @@ struct Settings { } } } - - // MARK: Typo Tolerance - - func getTypoTolerance( - _ uid: String, - _ completion: @escaping (Result) -> Void) { - - self.request.get(api: "/indexes/\(uid)/settings/typo-tolerance") { result in - switch result { - case .success(let data): - guard let data: Data = data else { - completion(.failure(MeiliSearch.Error.dataNotFound)) - return - } - do { - let response: TypoToleranceResult = try Constants.customJSONDecoder.decode(TypoToleranceResult.self, from: data) - completion(.success(response)) - } catch { - completion(.failure(error)) - } - case .failure(let error): - completion(.failure(error)) - } - } - } - - func updateTypoTolerance( - _ uid: String, - _ setting: TypoTolerance, - _ completion: @escaping (Result) -> Void) { - - let data: Data - do { - data = try JSONEncoder().encode(setting) - } catch { - completion(.failure(error)) - return - } - - self.request.patch(api: "/indexes/\(uid)/settings/typo-tolerance", data) { result in - switch result { - case .success(let data): - do { - let task: TaskInfo = try Constants.customJSONDecoder.decode(TaskInfo.self, from: data) - completion(.success(task)) - } catch { - completion(.failure(error)) - } - case .failure(let error): - completion(.failure(error)) - } - } - } - - func resetTypoTolerance( - _ uid: String, - _ completion: @escaping (Result) -> Void) { - - self.request.delete(api: "/indexes/\(uid)/settings/typo-tolerance") { result in - switch result { - case .success(let data): - guard let data: Data = data else { - completion(.failure(MeiliSearch.Error.dataNotFound)) - return - } - do { - let task: TaskInfo = try Constants.customJSONDecoder.decode(TaskInfo.self, from: data) - completion(.success(task)) - } catch { - completion(.failure(error)) - } - case .failure(let error): - completion(.failure(error)) - } - } - } }