Skip to content

Add method to get task documents#516

Open
claudeaceae wants to merge 2 commits intomeilisearch:mainfrom
claudeaceae:feat/get-task-documents
Open

Add method to get task documents#516
claudeaceae wants to merge 2 commits intomeilisearch:mainfrom
claudeaceae:feat/get-task-documents

Conversation

@claudeaceae
Copy link
Copy Markdown

@claudeaceae claudeaceae commented Mar 25, 2026

Summary

  • Adds getTaskDocuments method implementing GET /tasks/{taskUid}/documents (Meilisearch v1.13)
  • Handles NDJSON response format by parsing each newline-delimited JSON line
  • Includes callback-based and async/await APIs
  • Adds unit tests for normal and empty responses
  • Adds code sample under get_task_documents_1

Closes #513

Summary by CodeRabbit

  • New Features

    • You can now retrieve documents associated with a specific task, including an async/await convenience variant.
  • Documentation

    • Added a usage example demonstrating how to fetch task documents.
  • Tests

    • Added test coverage for task document retrieval, including success, empty response, and malformed-response scenarios.

Implements the endpoint introduced in Meilisearch v1.13 for retrieving
documents processed by a given task. Handles NDJSON response format by
parsing each line as a separate JSON document.

Closes meilisearch#513

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 25, 2026

📝 Walkthrough

Walkthrough

Added support for retrieving documents for a task via GET /tasks/{taskUid}/documents: a new Tasks implementation that decodes NDJSON, a public client-facing method, an async/await overload, unit tests, and a documentation code sample.

Changes

Cohort / File(s) Summary
Client surface
Sources/MeiliSearch/Client.swift
Added public generic getTaskDocuments<T>(taskUid:_:) forwarding to Tasks.
Tasks implementation
Sources/MeiliSearch/Tasks.swift
Added getTaskDocuments<T> that issues GET /tasks/{taskUid}/documents, validates response, and decodes NDJSON via new decodeNDJSON<T>(_:) helper.
Async API
Sources/MeiliSearch/Async/Client+async.swift
Added public func getTaskDocuments<T>(taskUid: Int) async throws -> [T] bridging the callback API with withCheckedThrowingContinuation.
Tests
Tests/MeiliSearchUnitTests/TasksTests.swift
Added async tests for successful NDJSON decoding, empty-response handling, and malformed-response error case.
Docs / Examples
.code-samples.meilisearch.yaml
Added get_task_documents_1 async usage example demonstrating try await client.getTaskDocuments(taskUid: 1) and printing decoded documents.

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant Tasks as Tasks
    participant HTTP as HTTP Request
    participant Decoder as NDJSON Decoder
    participant Continuation as Async Continuation

    Client->>Tasks: getTaskDocuments(taskUid, completion)
    Tasks->>HTTP: GET /tasks/{taskUid}/documents
    HTTP-->>Tasks: NDJSON payload (raw Data)
    Tasks->>Decoder: decodeNDJSON(data)
    Decoder->>Decoder: split lines & decode each JSON line
    Decoder-->>Tasks: [T] (decoded documents)
    Tasks->>Client: completion(.success([T]))

    Client->>Client: async overload (withCheckedThrowingContinuation)
    Client->>Tasks: getTaskDocuments(taskUid, completion) via continuation bridge
    Tasks-->>Continuation: resume(return or throw)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I nibble NDJSON lines with care,
Each JSON nibble—decoded, fair.
From callback burrow to async lair,
Documents hop out into the air. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'Add method to get task documents' accurately summarizes the main change—adding a new getTaskDocuments method to the SDK.
Linked Issues check ✅ Passed All coding objectives from issue #513 are met: new getTaskDocuments method added [#513], test cases included [#513], and code sample added [#513].
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the getTaskDocuments functionality specified in issue #513; no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
Sources/MeiliSearch/Tasks.swift (1)

165-177: Consider a lower-allocation NDJSON decode path.

Current decoding is correct, but converting Data -> String -> Data per line adds avoidable copies for large task outputs. Splitting raw bytes by newline and decoding each chunk would be leaner.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/MeiliSearch/Tasks.swift` around lines 165 - 177, The current
decodeNDJSON converts Data -> String -> Data per line causing extra allocations;
change it to split the raw Data by newline bytes and decode each Data slice
directly. In decodeNDJSON<T: Decodable>, remove the String conversion and use
Data's byte-splitting (e.g., data.split(separator: 0x0A)) to get per-line Data
chunks, skip empty chunks, optionally trim a trailing CR (0x0D) from each chunk,
and pass each chunk directly to Constants.customJSONDecoder.decode(T.self, from:
chunk); keep throwing MeiliSearch.Error.invalidJSON on any non-UTF8/invalid
chunk paths as before.
Tests/MeiliSearchUnitTests/TasksTests.swift (1)

41-51: Please add one malformed-NDJSON test case.

You now cover happy and empty paths; adding a malformed line case would lock down error behavior for the new parser.

Example test shape
+  func testGetTaskDocumentsMalformedResponse() async {
+    session.pushData("""
+    {"id":1}
+    not-json
+    """)
+
+    struct SimpleDoc: Decodable { let id: Int }
+
+    do {
+      _ = try await self.client.getTaskDocuments(taskUid: 1) as [SimpleDoc]
+      XCTFail("Expected decoding to fail")
+    } catch {
+      XCTAssertNotNil(error)
+    }
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Tests/MeiliSearchUnitTests/TasksTests.swift` around lines 41 - 51, Add a new
async test (e.g., testGetTaskDocumentsMalformedNDJSON) mirroring
testGetTaskDocumentsEmptyResponse but push a malformed NDJSON payload into the
fake session using session.pushData (for example one valid JSON line then a
broken line like "{\"id\":1}\n{\"id\":}" or a non-JSON line), declare the same
SimpleDoc struct used by testGetTaskDocumentsEmptyResponse, then call try await
self.client.getTaskDocuments(taskUid: 1) and assert that it throws (use
XCTAssertThrowsError or await XCTAssertThrowsError) and optionally verify the
thrown error is a DecodingError; reference client.getTaskDocuments and
session.pushData when locating where to add the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Sources/MeiliSearch/Tasks.swift`:
- Around line 165-177: The current decodeNDJSON converts Data -> String -> Data
per line causing extra allocations; change it to split the raw Data by newline
bytes and decode each Data slice directly. In decodeNDJSON<T: Decodable>, remove
the String conversion and use Data's byte-splitting (e.g., data.split(separator:
0x0A)) to get per-line Data chunks, skip empty chunks, optionally trim a
trailing CR (0x0D) from each chunk, and pass each chunk directly to
Constants.customJSONDecoder.decode(T.self, from: chunk); keep throwing
MeiliSearch.Error.invalidJSON on any non-UTF8/invalid chunk paths as before.

In `@Tests/MeiliSearchUnitTests/TasksTests.swift`:
- Around line 41-51: Add a new async test (e.g.,
testGetTaskDocumentsMalformedNDJSON) mirroring testGetTaskDocumentsEmptyResponse
but push a malformed NDJSON payload into the fake session using session.pushData
(for example one valid JSON line then a broken line like "{\"id\":1}\n{\"id\":}"
or a non-JSON line), declare the same SimpleDoc struct used by
testGetTaskDocumentsEmptyResponse, then call try await
self.client.getTaskDocuments(taskUid: 1) and assert that it throws (use
XCTAssertThrowsError or await XCTAssertThrowsError) and optionally verify the
thrown error is a DecodingError; reference client.getTaskDocuments and
session.pushData when locating where to add the test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c51b0333-da7c-40a8-8c9b-d82cdeecca46

📥 Commits

Reviewing files that changed from the base of the PR and between bbcfbb5 and c432da0.

📒 Files selected for processing (5)
  • .code-samples.meilisearch.yaml
  • Sources/MeiliSearch/Async/Client+async.swift
  • Sources/MeiliSearch/Client.swift
  • Sources/MeiliSearch/Tasks.swift
  • Tests/MeiliSearchUnitTests/TasksTests.swift

Split raw Data bytes by newline instead of converting Data -> String -> Data
per line, reducing allocations for large task outputs. Also handles \r\n
line endings. Adds test case for malformed NDJSON input.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@claudeaceae
Copy link
Copy Markdown
Author

Thanks for the review! Both nitpicks addressed in eaf2a60:

  • NDJSON decode path: Now splits raw Data bytes by 0x0A directly instead of the Data → String → Data round-trip. Also handles \r\n line endings.
  • Malformed NDJSON test: Added testGetTaskDocumentsMalformedResponse to verify error behavior on invalid input.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
Tests/MeiliSearchUnitTests/TasksTests.swift (1)

53-67: Minor: Redundant assertion in catch block.

The XCTAssertNotNil(error) assertion on line 65 is unnecessary—error within a catch block is guaranteed to be non-nil. The test already proves an error occurred by reaching the catch block without hitting XCTFail.

Consider removing the redundant assertion or, if you want stronger validation, assert on a specific error type (e.g., DecodingError).

♻️ Optional: Strengthen error validation or remove redundant assertion
     do {
       let _: [SimpleDoc] = try await self.client.getTaskDocuments(taskUid: 1)
       XCTFail("Expected decoding to fail")
     } catch {
-      XCTAssertNotNil(error)
+      XCTAssertTrue(error is DecodingError, "Expected DecodingError but got \(type(of: error))")
     }

Or simply remove the assertion if specific error type validation isn't needed:

     do {
       let _: [SimpleDoc] = try await self.client.getTaskDocuments(taskUid: 1)
       XCTFail("Expected decoding to fail")
-    } catch {
-      XCTAssertNotNil(error)
-    }
+    } catch { }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Tests/MeiliSearchUnitTests/TasksTests.swift` around lines 53 - 67, The catch
block in testGetTaskDocumentsMalformedResponse contains a redundant
XCTAssertNotNil(error); remove that assertion or replace it with a stronger
check such as asserting the error type (for example XCTAssertTrue(error is
DecodingError)) so the test either simply verifies an error was thrown by
reaching the catch or validates the error from getTaskDocuments(taskUid:) is a
DecodingError; update the testGetTaskDocumentsMalformedResponse function
accordingly (referencing the SimpleDoc struct and the call to
self.client.getTaskDocuments).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Tests/MeiliSearchUnitTests/TasksTests.swift`:
- Around line 53-67: The catch block in testGetTaskDocumentsMalformedResponse
contains a redundant XCTAssertNotNil(error); remove that assertion or replace it
with a stronger check such as asserting the error type (for example
XCTAssertTrue(error is DecodingError)) so the test either simply verifies an
error was thrown by reaching the catch or validates the error from
getTaskDocuments(taskUid:) is a DecodingError; update the
testGetTaskDocumentsMalformedResponse function accordingly (referencing the
SimpleDoc struct and the call to self.client.getTaskDocuments).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ce28f82b-1038-4511-86de-4289a8db6cc3

📥 Commits

Reviewing files that changed from the base of the PR and between c432da0 and eaf2a60.

📒 Files selected for processing (2)
  • Sources/MeiliSearch/Tasks.swift
  • Tests/MeiliSearchUnitTests/TasksTests.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • Sources/MeiliSearch/Tasks.swift

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Meilisearch v1.13.0] Add method to get tasks documents

1 participant