Skip to content

Commit 8ede55d

Browse files
committed
Add wait for pending update
1 parent c513fb5 commit 8ede55d

File tree

6 files changed

+176
-9
lines changed

6 files changed

+176
-9
lines changed

Sources/MeiliSearch/Client.swift

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,28 @@ public struct MeiliSearch {
373373
self.updates.getAll(UID, completion)
374374
}
375375

376+
/**
377+
Wait for an update to be processed or failed.
378+
379+
Providing an update id, returned by asynchronous MeiliSearch options, call are made
380+
to MeiliSearch to check if the update has been processed or if it has failed.
381+
382+
- parameter UID: The unique identifier of the `Index`.
383+
- parameter updateId: The id of the update.
384+
- parameter: options Optionnal configuration for timeout and interval
385+
- parameter completion: The completion closure used to notify when the server
386+
**/
387+
388+
public func waitForPendingUpdate(
389+
UID: String,
390+
update: Update,
391+
options: WaitOptions? = nil,
392+
_ completion: @escaping (Result<Update.Result, Swift.Error>
393+
) -> Void) {
394+
print("et merde")
395+
self.updates.waitForPendingUpdate(UID, update, options, completion)
396+
}
397+
376398
// MARK: Keys
377399

378400
/**
@@ -867,5 +889,4 @@ public struct MeiliSearch {
867889
_ completion: @escaping (Result<Dump, Swift.Error>) -> Void) {
868890
self.dumps.status(UID, completion)
869891
}
870-
871892
}

Sources/MeiliSearch/Error.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ public extension MeiliSearch {
6868
/// The input or output JSON is invalid.
6969
case invalidJSON
7070

71+
// TimeOut is reached in a waiting function
72+
case timeOut(timeOut: Double)
7173
// URL is invalid
7274
case invalidURL(url: String? = "")
7375

@@ -88,6 +90,8 @@ public extension MeiliSearch {
8890
return "Response decoding failed"
8991
case .invalidJSON:
9092
return "Invalid json"
93+
case .timeOut(let timeOut):
94+
return "TimeOut of \(timeOut) is reached"
9195
case .invalidURL(let url):
9296
if let strUrl: String = url {
9397
return "Invalid URL: \(strUrl)"

Sources/MeiliSearch/Model/Update.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ public struct Update: Codable, Equatable {
1111
/// The UID of the update.
1212
public let updateId: Int
1313

14+
public init(updateId: Int) {
15+
self.updateId = updateId
16+
}
1417
/// Result type for the Update.
1518
public struct Result: Codable, Equatable {
1619

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import Foundation
2+
3+
/**
4+
`WaitOptions` struct represent the options used during a waitForPendingUpdate call.
5+
*/
6+
public struct WaitOptions: Codable, Equatable {
7+
8+
// MARK: Properties
9+
10+
/// Maximum time in seconds before cancel
11+
public let timeOut: Double
12+
13+
/// Interval in seconds between each status call
14+
public let interval: Double
15+
16+
// MARK: Initializers
17+
public init(
18+
timeOut: Double? = 5,
19+
interval: Double? = 0.05
20+
) {
21+
self.timeOut = timeOut ?? 5
22+
self.interval = interval ?? 0.05
23+
}
24+
25+
// MARK: Codable Keys
26+
27+
enum CodingKeys: String, CodingKey {
28+
case timeOut
29+
case interval
30+
}
31+
32+
}

Sources/MeiliSearch/Updates.swift

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ struct Updates {
2929
completion(.failure(MeiliSearch.Error.dataNotFound))
3030
return
3131
}
32-
3332
do {
3433
let result: Update.Result = try Constants.customJSONDecoder.decode(
3534
Update.Result.self,
3635
from: data)
36+
print("BEFORE COMPLETION IN GET")
3737
completion(.success(result))
3838
} catch {
3939
completion(.failure(error))
@@ -74,7 +74,67 @@ struct Updates {
7474
}
7575

7676
}
77+
}
78+
79+
func waitForPendingUpdate(
80+
_ UID: String,
81+
_ update: Update,
82+
_ options: WaitOptions? = nil,
83+
_ completion: @escaping (Result<Update.Result, Swift.Error>) -> Void) {
7784

85+
let currentDate = Date()
86+
let waitOptions: WaitOptions = options ?? WaitOptions()
87+
var done = false
88+
while 0 - currentDate.timeIntervalSinceNow < waitOptions.timeOut || !done {
89+
print("1")
90+
print(update)
91+
let waitForGet = DispatchSemaphore(value: 0)
92+
self.get(UID, update) { result in
93+
switch result {
94+
case .success(let status):
95+
print("2")
96+
if status.status == Update.Status.processed || status.status == Update.Status.failed {
97+
print("3")
98+
done = true
99+
completion(.success(status))
100+
waitForGet.signal()
101+
return
102+
} else {
103+
print("4")
104+
sleep(1)
105+
waitForGet.signal()
106+
}
107+
case .failure(let error):
108+
print("5")
109+
done = true
110+
completion(.failure(error))
111+
waitForGet.signal()
112+
}
113+
print("6")
114+
}
115+
print("7")
116+
if done {
117+
return
118+
}
119+
print("8")
120+
waitForGet.wait() // does not work in test env
121+
print("9")
122+
}
123+
print("10")
124+
completion(.failure(MeiliSearch.Error.timeOut(timeOut: waitOptions.timeOut)))
125+
return
78126
}
79127

80128
}
129+
130+
// completion(.success(Update.Result(
131+
// status: "processed",
132+
// updateId: 1,
133+
// type: Update.Result.UpdateType(
134+
// name: "DocumentsAddition",
135+
// number: 4
136+
// ),
137+
// duration: 0.076980613,
138+
// enqueuedAt: Date("2019-12-07T21:16:09.623944Z"),
139+
// processedAt: Date("2019-12-07T21:16:09.703509Z")
140+
// )))

Tests/MeiliSearchIntegrationTests/UpdatesTests.swift

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ private struct Movie: Codable, Equatable {
2424

2525
}
2626

27+
private let movies: [Movie] = [
28+
Movie(id: 123, title: "Pride and Prejudice", comment: "A great book"),
29+
Movie(id: 456, title: "Le Petit Prince", comment: "A french book"),
30+
Movie(id: 2, title: "Le Rouge et le Noir", comment: "Another french book"),
31+
Movie(id: 1, title: "Alice In Wonderland", comment: "A weird book"),
32+
Movie(id: 1344, title: "The Hobbit", comment: "An awesome book"),
33+
Movie(id: 4, title: "Harry Potter and the Half-Blood Prince", comment: "The best book"),
34+
Movie(id: 42, title: "The Hitchhiker's Guide to the Galaxy"),
35+
Movie(id: 1844, title: "A Moreninha", comment: "A Book from Joaquim Manuel de Macedo")
36+
]
37+
2738
class UpdatesTests: XCTestCase {
2839

2940
private var client: MeiliSearch!
@@ -63,12 +74,11 @@ class UpdatesTests: XCTestCase {
6374
let documents: Data = try! JSONEncoder().encode([movie])
6475

6576
self.client.addDocuments(UID: self.uid, documents: documents, primaryKey: nil) { result in
66-
6777
switch result {
6878
case .success(let update):
69-
79+
print("YOUHOU")
80+
print(update)
7081
self.client.getUpdate(UID: self.uid, update) { (result: Result<Update.Result, Swift.Error>) in
71-
7282
switch result {
7383
case .success(let update):
7484
XCTAssertEqual("DocumentsAddition", update.type.name)
@@ -78,9 +88,7 @@ class UpdatesTests: XCTestCase {
7888
XCTFail()
7989
}
8090
expectation.fulfill()
81-
8291
}
83-
8492
case .failure:
8593
XCTFail("Failed to update movie index")
8694
}
@@ -103,7 +111,6 @@ class UpdatesTests: XCTestCase {
103111
}
104112

105113
self.client.getAllUpdates(UID: self.uid) { (result: Result<[Update.Result], Swift.Error>) in
106-
107114
switch result {
108115
case .success(let updates):
109116
updates.forEach { (update: Update.Result) in
@@ -118,11 +125,51 @@ class UpdatesTests: XCTestCase {
118125
expectation.fulfill()
119126

120127
}
121-
122128
self.wait(for: [expectation], timeout: 10.0)
123129

124130
}
125131

132+
func testWaitForPendingUpdateSuccessDefault () {
133+
let expectation = XCTestExpectation(description: "Wait for pending update with default options")
134+
135+
self.client.addDocuments(
136+
UID: self.uid,
137+
documents: movies,
138+
primaryKey: nil
139+
) { result in
140+
141+
switch result {
142+
case .success(let update):
143+
XCTAssertEqual(Update(updateId: 0), update)
144+
self.client.waitForPendingUpdate(UID: self.uid, update: update) { result in
145+
switch result {
146+
case .success(let update):
147+
XCTAssertEqual(update.status, Update.Status.processed)
148+
case .failure(let error):
149+
XCTFail(error.localizedDescription)
150+
}
151+
expectation.fulfill()
152+
153+
}
154+
case .failure(let error):
155+
print(error)
156+
XCTFail()
157+
}
158+
}
159+
self.wait(for: [expectation], timeout: 5.0)
160+
}
161+
162+
func testWaitForPendingUpdateSuccessEmptyOptions () {
163+
164+
}
165+
166+
func testWaitForPendingUpdateSuccessWithOptions () {
167+
168+
}
169+
170+
func testWaitForPendingUpdateFailure () {
171+
172+
}
126173
}
127174
// swiftlint:enable force_unwrapping
128175
// swiftlint:enable force_try

0 commit comments

Comments
 (0)