Skip to content

Commit 1f138d1

Browse files
bors[bot]ppamorim
andauthored
Merge #53
53: Add support to Encodable types for addDocuments function r=curquiza a=ppamorim ## Summary - Function `addDocuments<T>` added. Now it's possible to send objects that are `Codable/Encodable` and the SDK will automatically encode the values to JSON. A custom encoder can be set by adding `encoder` in the call. ## Additions - Fixed bug in the `ClientTests.swift` file ## Local tests - [X] Unit tests passed - [X] Integration tests passed ## Problems Users are forced to wrap the object to `[]` when using `addDocuments` function with objects that are `Codable/Encodable`. I tried to create a wrapper function for this but Swift doesn't like the direct conversion from `T` to `[T]`. Co-authored-by: Pedro Paulo de Amorim <[email protected]>
2 parents aa61cdc + e1181db commit 1f138d1

File tree

6 files changed

+199
-17
lines changed

6 files changed

+199
-17
lines changed

Sources/MeiliSearch/Client.swift

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,36 @@ public struct MeiliSearch {
143143
For a partial update of the document see `updateDocument`.
144144

145145
- parameter UID: The unique identifier for the Document's index to be found.
146-
- parameter documents: The documents data (JSON) to be processed.
146+
- parameter documents: The documents to be processed.
147+
- parameter completion: The completion closure used to notify when the server
148+
completes the update request, it returns a `Result` object that contains `Update`
149+
value. If the request was sucessful or `Error` if a failure occured.
150+
*/
151+
public func addDocuments<T>(
152+
UID: String,
153+
documents: [T],
154+
encoder: JSONEncoder? = nil,
155+
primaryKey: String?,
156+
_ completion: @escaping (Result<Update, Swift.Error>) -> Void) where T: Encodable {
157+
self.documents.add(
158+
UID,
159+
documents,
160+
encoder,
161+
primaryKey,
162+
completion)
163+
}
164+
165+
/**
166+
Add a list of documents as data or replace them if they already exist.
167+
168+
If you send an already existing document (same id) the whole existing document will
169+
be overwritten by the new document. Fields previously in the document not present in
170+
the new document are removed.
171+
172+
For a partial update of the document see `updateDocument`.
173+
174+
- parameter UID: The unique identifier for the Document's index to be found.
175+
- parameter documents: The data to be processed.
147176
- parameter completion: The completion closure used to notify when the server
148177
completes the update request, it returns a `Result` object that contains `Update`
149178
value. If the request was sucessful or `Error` if a failure occured.

Sources/MeiliSearch/Constants.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,11 @@ struct Constants {
77
decoder.dateDecodingStrategy = .formatted(Formatter.iso8601)
88
return decoder
99
}()
10+
11+
static let customJSONEecoder: JSONEncoder = {
12+
let encoder = JSONEncoder()
13+
encoder.dateEncodingStrategy = .formatted(Formatter.iso8601)
14+
return encoder
15+
}()
16+
1017
}

Sources/MeiliSearch/Documents.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct Documents {
7575
_ document: Data,
7676
_ primaryKey: String?,
7777
_ completion: @escaping (Result<Update, Swift.Error>) -> Void) {
78+
7879
var query: String = "/indexes/\(UID)/documents"
7980
if let primaryKey: String = primaryKey {
8081
query += "?primaryKey=\(primaryKey)"
@@ -94,6 +95,42 @@ struct Documents {
9495
}
9596
}
9697

98+
func add<T>(
99+
_ UID: String,
100+
_ documents: [T],
101+
_ encoder: JSONEncoder? = nil,
102+
_ primaryKey: String?,
103+
_ completion: @escaping (Result<Update, Swift.Error>) -> Void) where T: Encodable {
104+
105+
var query: String = "/indexes/\(UID)/documents"
106+
if let primaryKey: String = primaryKey {
107+
query += "?primaryKey=\(primaryKey)"
108+
}
109+
110+
let data: Data!
111+
112+
switch encodeJSON(documents, encoder) {
113+
case .success(let documentData):
114+
data = documentData
115+
case .failure(let error):
116+
completion(.failure(error))
117+
return
118+
}
119+
120+
request.post(api: query, data) { result in
121+
122+
switch result {
123+
case .success(let data):
124+
125+
Documents.decodeJSON(data, completion: completion)
126+
127+
case .failure(let error):
128+
completion(.failure(error))
129+
}
130+
131+
}
132+
}
133+
97134
func update(
98135
_ UID: String,
99136
_ document: Data,
@@ -217,4 +254,16 @@ struct Documents {
217254
}
218255
}
219256

257+
private func encodeJSON<T: Encodable>(
258+
_ documents: [T],
259+
_ encoder: JSONEncoder?) -> Result<Data, Swift.Error> {
260+
do {
261+
let data: Data = try (encoder ?? Constants.customJSONEecoder)
262+
.encode(documents)
263+
return .success(data)
264+
} catch {
265+
return .failure(error)
266+
}
267+
}
268+
220269
}

Tests/MeiliSearchIntegrationTests/DocumentsTests.swift

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,12 @@ class DocumentsTests: XCTestCase {
6666
}
6767

6868
func testAddAndGetDocuments() {
69-
let documents: Data = try! JSONEncoder().encode(movies)
7069

7170
let expectation = XCTestExpectation(description: "Add or replace Movies document")
7271

7372
self.client.addDocuments(
7473
UID: self.uid,
75-
documents: documents,
74+
documents: movies,
7675
primaryKey: nil
7776
) { result in
7877

@@ -112,6 +111,53 @@ class DocumentsTests: XCTestCase {
112111

113112
}
114113

114+
func testAddDataAndGetDocuments() {
115+
let documents: Data = try! JSONEncoder().encode(movies)
116+
117+
let expectation = XCTestExpectation(description: "Add or replace Movies document")
118+
119+
self.client.addDocuments(
120+
UID: self.uid,
121+
documents: documents,
122+
primaryKey: nil
123+
) { result in
124+
125+
switch result {
126+
case .success(let update):
127+
128+
XCTAssertEqual(Update(updateId: 0), update)
129+
130+
Thread.sleep(forTimeInterval: 1.0)
131+
132+
self.client.getDocuments(
133+
UID: self.uid,
134+
limit: 20
135+
) { (result: Result<[Movie], Swift.Error>) in
136+
137+
switch result {
138+
case .success(let returnedMovies):
139+
140+
movies.forEach { (movie: Movie) in
141+
XCTAssertTrue(returnedMovies.contains(movie))
142+
}
143+
144+
case .failure(let error):
145+
print(error)
146+
XCTFail()
147+
}
148+
149+
expectation.fulfill()
150+
}
151+
152+
case .failure(let error):
153+
print(error)
154+
XCTFail()
155+
}
156+
}
157+
self.wait(for: [expectation], timeout: 5.0)
158+
159+
}
160+
115161
func testGetOneDocumentAndFail() {
116162

117163
let getExpectation = XCTestExpectation(description: "Get one document and fail")
@@ -194,25 +240,26 @@ class DocumentsTests: XCTestCase {
194240

195241
case .success(let update):
196242

243+
197244
XCTAssertEqual(Update(updateId: 0), update)
198245

199246
Thread.sleep(forTimeInterval: 1.0)
200247

201-
self.client.getDocument(
202-
UID: self.uid,
203-
identifier: "10"
204-
) { (result: Result<Movie, Swift.Error>) in
248+
self.client.getDocument(
249+
UID: self.uid,
250+
identifier: "10"
251+
) { (result: Result<Movie, Swift.Error>) in
205252

206-
switch result {
207-
case .success(let returnedMovie):
208-
XCTAssertEqual(movie, returnedMovie)
209-
case .failure(let error):
210-
print(error)
211-
XCTFail()
212-
}
213-
expectation.fulfill()
253+
switch result {
254+
case .success(let returnedMovie):
255+
XCTAssertEqual(movie, returnedMovie)
256+
case .failure(let error):
257+
print(error)
258+
XCTFail()
259+
}
260+
expectation.fulfill()
214261

215-
}
262+
}
216263

217264
case .failure(let error):
218265
print(error)
@@ -439,6 +486,7 @@ class DocumentsTests: XCTestCase {
439486

440487
static var allTests = [
441488
("testAddAndGetDocuments", testAddAndGetDocuments),
489+
("testAddDataAndGetDocuments", testAddDataAndGetDocuments),
442490
("testGetOneDocumentAndFail", testGetOneDocumentAndFail),
443491
("testAddAndGetOneDocumentWithIntIdentifierAndSucceed", testAddAndGetOneDocumentWithIntIdentifierAndSucceed),
444492
("testAddAndGetOneDocuments", testAddAndGetOneDocuments),

Tests/MeiliSearchUnitTests/ClientTests.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ import XCTest
33

44
class ClientTests: XCTestCase {
55

6+
private let session = MockURLSession()
7+
68
func testValidHostURL() {
7-
XCTAssertNotNil(try? MeiliSearch(Config(hostURL: "http://localhost:7700", apiKey: "masterKey")))
9+
session.pushEmpty(code: 200)
10+
XCTAssertNotNil(try? MeiliSearch(Config.default(apiKey: "masterKey", session: session)))
811
}
912

1013
func testEmptyHostURL() {

Tests/MeiliSearchUnitTests/DocumentsTests.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,51 @@ class DocumentsTests: XCTestCase {
4747

4848
let uid: String = "Movies"
4949

50+
let movie = Movie(
51+
id: 287947,
52+
title: "Shazam",
53+
overview: "A boy is given the ability to become an adult superhero in times of need with a single magic word.",
54+
releaseDate: Date(timeIntervalSince1970: TimeInterval(1553299200)))
55+
56+
let expectation = XCTestExpectation(description: "Add or replace Movies document")
57+
58+
self.client.addDocuments(
59+
UID: uid,
60+
documents: [movie],
61+
primaryKey: "") { result in
62+
63+
switch result {
64+
case .success(let update):
65+
XCTAssertEqual(stubUpdate, update)
66+
expectation.fulfill()
67+
case .failure:
68+
XCTFail("Failed to add or replace Movies document")
69+
}
70+
71+
}
72+
73+
self.wait(for: [expectation], timeout: 1.0)
74+
75+
}
76+
77+
func testAddDataDocuments() {
78+
79+
//Prepare the mock server
80+
81+
let jsonString = """
82+
{"updateId":0}
83+
"""
84+
85+
let decoder: JSONDecoder = JSONDecoder()
86+
let jsonData = jsonString.data(using: .utf8)!
87+
let stubUpdate: Update = try! decoder.decode(Update.self, from: jsonData)
88+
89+
session.pushData(jsonString, code: 202)
90+
91+
// Start the test with the mocked server
92+
93+
let uid: String = "Movies"
94+
5095
let documentJsonString = """
5196
[{
5297
"id": 287947,
@@ -358,6 +403,7 @@ class DocumentsTests: XCTestCase {
358403

359404
static var allTests = [
360405
("testAddDocuments", testAddDocuments),
406+
("testAddDataDocuments", testAddDataDocuments),
361407
("testUpdateDocuments", testUpdateDocuments),
362408
("testGetDocument", testGetDocument),
363409
("testGetDocuments", testGetDocuments),

0 commit comments

Comments
 (0)