Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .code-samples.meilisearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1575,3 +1575,8 @@ landing_getting_started_1: |-
print(error)
}
}
swap_indexes_1: |-
let task = try await self.client.swapIndexes([
("indexA", "indexB"),
("indexX", "indexY")
])
11 changes: 11 additions & 0 deletions Sources/MeiliSearch/Async/Client+async.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ extension MeiliSearch {
}
}

/**
See `swapIndexes(_:_:)`
*/
public func swapIndexes(_ pairs: [(String, String)]) async throws -> TaskInfo {
try await withCheckedThrowingContinuation { continuation in
self.swapIndexes(pairs) { result in
continuation.resume(with: result)
}
}
}

/**
See `waitForTask(taskUid:options:_:)`
*/
Expand Down
8 changes: 7 additions & 1 deletion Sources/MeiliSearch/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,13 @@ public struct MeiliSearch {
self.index(uid).delete(completion)
}

// MARK: WAIT FOR TASK
public func swapIndexes(
_ pairs: [(String, String)],
_ completion: @escaping (Result<TaskInfo, Swift.Error>) -> Void) {
Indexes.swapIndexes(pairs: pairs, request: request, completion)
}

// MARK: Wait for Task

/**
Wait for a task to be successful or fail.
Expand Down
48 changes: 39 additions & 9 deletions Sources/MeiliSearch/Indexes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,40 @@ public struct Indexes {
}
}

static func swapIndexes(
pairs: [(old: String, new: String)],
request: Request,
_ completion: @escaping (Result<TaskInfo, Swift.Error>) -> Void) {

let swapIndexPayload: [SwapIndexPayload] = pairs.map {
SwapIndexPayload(indexes: [ $0.old, $0.new ])
}

let data: Data
do {
data = try JSONEncoder().encode(swapIndexPayload)
} catch {
completion(.failure(MeiliSearch.Error.invalidJSON))
return
}

request.post(api: "/swap-indexes", data) { result in
switch result {
case .success(let data):
do {
let taskInfo: TaskInfo = try Constants.customJSONDecoder.decode(
TaskInfo.self,
from: data)
completion(.success(taskInfo))
} catch {
completion(.failure(error))
}
case .failure(let error):
completion(.failure(error))
}
}
}

/**
Update the index primaryKey.

Expand Down Expand Up @@ -1089,15 +1123,11 @@ public struct Indexes {
}

struct CreateIndexPayload: Codable {
public let uid: String
public let primaryKey: String?
let uid: String
let primaryKey: String?
}

public init(
uid: String,
primaryKey: String? = nil
) {
self.uid = uid
self.primaryKey = primaryKey
}
public struct SwapIndexPayload: Codable, Equatable {
public let indexes: [String]
}
}
3 changes: 2 additions & 1 deletion Sources/MeiliSearch/Model/Task/TaskDetails.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ public extension Task {
}

struct TaskIndexSwapDetails: Decodable, Equatable {
// To be populated under https://github.com/meilisearch/meilisearch-swift/issues/367
/// Object containing the payload for the indexSwap task
public let swaps: [Indexes.SwapIndexPayload]
}

struct TaskCancellationDetails: Decodable, Equatable {
Expand Down
6 changes: 6 additions & 0 deletions Sources/MeiliSearch/Model/Task/TaskInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,10 @@ public struct TaskInfo: Codable, Equatable {
public enum CodingKeys: String, CodingKey {
case taskUid, indexUid, status, type, enqueuedAt
}

@discardableResult
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
public func wait(on client: MeiliSearch, options: WaitOptions? = nil) async throws -> Task {
try await client.waitForTask(task: self, options: options)
}
}
44 changes: 44 additions & 0 deletions Tests/MeiliSearchIntegrationTests/IndexesTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,50 @@ class IndexesTests: XCTestCase {
self.wait(for: [updateExpectation], timeout: TESTS_TIME_OUT)
}

func testSwapIndex() async throws {
let documents: [Movie] = [
Movie(id: 123, title: "Pride and Prejudice", comment: "A great book"),
Movie(id: 456, title: "Le Petit Prince", comment: "A french book"),
]

// Remove indexes (if present)
try await client.deleteIndex("indexA").wait(on: client)
try await client.deleteIndex("indexB").wait(on: client)

// Create destination index
try await client.createIndex(uid: "indexA").wait(on: client)

// Create source index
try await client.createIndex(uid: "indexB").wait(on: client)
try await client.index("indexB").addDocuments(documents: documents).wait(on: client)
try await client.index("indexB").updateStopWords(["test"]).wait(on: client)

// Verify indexA (destination) does not have any stop words or documents
let stopWords: [String] = try await client.index("indexA").getStopWords()
XCTAssertEqual(stopWords, [])

let movies: DocumentsResults<Movie> = try await client.index("indexA").getDocuments()
XCTAssertEqual(movies.total, 0)

// Replace indexes
let task = try await client.swapIndexes([("indexA", "indexB")]).wait(on: client)
XCTAssertEqual(task.type, .indexSwap)

guard case .indexSwap(let value) = task.details else {
XCTFail("Task Not a Swap")
return
}

XCTAssertEqual(value.swaps[0], .init(indexes: ["indexA", "indexB"]))

// Verify indexA (now source) does have stop words and documents
let stopWordsNew: [String] = try await client.index("indexA").getStopWords()
XCTAssertEqual(stopWordsNew, ["test"])

let moviesNew: DocumentsResults<Movie> = try await client.index("indexA").getDocuments()
XCTAssertEqual(moviesNew.total, 2)
}

func testDeleteIndex() {

let createExpectation = XCTestExpectation(description: "Create Movies index")
Expand Down