Skip to content
Open
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
3 changes: 3 additions & 0 deletions .code-samples.meilisearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@ get_task_1: |-
print(error)
}
}
get_task_documents_1: |-
let documents: [MyDocument] = try await client.getTaskDocuments(taskUid: 1)
print(documents)
get_all_tasks_1: |-
client.getTasks { (result) in
switch result {
Expand Down
11 changes: 11 additions & 0 deletions Sources/MeiliSearch/Async/Client+async.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,17 @@ extension MeiliSearch {
}
}

/**
See `getTaskDocuments(taskUid:_:)`
*/
public func getTaskDocuments<T>(taskUid: Int) async throws -> [T] where T: Decodable {
try await withCheckedThrowingContinuation { continuation in
self.getTaskDocuments(taskUid: taskUid) { (result: Result<[T], Swift.Error>) in
continuation.resume(with: result)
}
}
}

/**
See `cancelTasks(filter:completion:)`
*/
Expand Down
16 changes: 16 additions & 0 deletions Sources/MeiliSearch/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,22 @@ public struct MeiliSearch {
self.tasks.getTasks(params: params, completion)
}

/**
Retrieve the list of documents that were processed or affected by a given task.
Only available for document-related tasks.

- parameter taskUid: The task unique identifier.
- parameter completion: The completion closure is used to notify when the server
completes the query request, it returns a `Result` object that contains `[T]` value.
If the request was successful or `Error` if a failure occurred.
*/
public func getTaskDocuments<T>(
taskUid: Int,
_ completion: @escaping (Result<[T], Swift.Error>) -> Void)
where T: Decodable {
self.tasks.getTaskDocuments(taskUid: taskUid, completion)
}

/**
Cancel any number of enqueued or processing tasks, stopping them from continuing to run

Expand Down
42 changes: 42 additions & 0 deletions Sources/MeiliSearch/Tasks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,48 @@ struct Tasks {
}
}

// MARK: Get Task Documents

func getTaskDocuments<T>(
taskUid: Int,
_ completion: @escaping (Result<[T], Swift.Error>) -> Void)
where T: Decodable {
self.request.get(api: "/tasks/\(taskUid)/documents") { result in
switch result {
case .success(let data):
guard let data = data else {
completion(.failure(MeiliSearch.Error.dataNotFound))
return
}
do {
let documents: [T] = try Tasks.decodeNDJSON(data)
completion(.success(documents))
} catch {
completion(.failure(error))
}
case .failure(let error):
completion(.failure(error))
}
}
}

private static func decodeNDJSON<T: Decodable>(_ data: Data) throws -> [T] {
let decoder = Constants.customJSONDecoder
let newline = UInt8(0x0A)
let cr = UInt8(0x0D)
let chunks = data.split(separator: newline, omittingEmptySubsequences: true)
return try chunks.map { chunk in
var lineData = Data(chunk)
if lineData.last == cr {
lineData.removeLast()
}
guard !lineData.isEmpty else {
throw MeiliSearch.Error.invalidJSON
}
return try decoder.decode(T.self, from: lineData)
}
}

// MARK: Cancel Tasks

func cancelTasks(
Expand Down
53 changes: 53 additions & 0 deletions Tests/MeiliSearchUnitTests/TasksTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,59 @@ class TasksTests: XCTestCase {
index = client.index(self.uid)
}

func testGetTaskDocumentsFromClient() async throws {
let ndjsonString = """
{"id":1,"title":"Movie 1"}
{"id":2,"title":"Movie 2"}
"""

struct SimpleDoc: Decodable, Equatable {
let id: Int
let title: String
}

session.pushData(ndjsonString)

let documents: [SimpleDoc] = try await self.client.getTaskDocuments(taskUid: 1)

XCTAssertEqual(documents.count, 2)
XCTAssertEqual(documents[0].id, 1)
XCTAssertEqual(documents[0].title, "Movie 1")
XCTAssertEqual(documents[1].id, 2)
XCTAssertEqual(documents[1].title, "Movie 2")

let requestPath = self.session.nextDataTask.request?.url?.path
XCTAssertEqual(requestPath, "/tasks/1/documents")
}

func testGetTaskDocumentsEmptyResponse() async throws {
session.pushData("")

struct SimpleDoc: Decodable, Equatable {
let id: Int
}

let documents: [SimpleDoc] = try await self.client.getTaskDocuments(taskUid: 1)

XCTAssertEqual(documents.count, 0)
}

func testGetTaskDocumentsMalformedResponse() async throws {
session.pushData("""
{"id":1}
not-json
""")

struct SimpleDoc: Decodable { let id: Int }

do {
let _: [SimpleDoc] = try await self.client.getTaskDocuments(taskUid: 1)
XCTFail("Expected decoding to fail")
} catch {
XCTAssertNotNil(error)
}
}

func testGetTasksWithParametersFromClient() async throws {
let jsonString = """
{
Expand Down