Skip to content

Commit fc8e08d

Browse files
committed
Add Cluster Operations
1 parent dc1fd7f commit fc8e08d

File tree

5 files changed

+211
-1
lines changed

5 files changed

+211
-1
lines changed

Sources/Typesense/Client.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,8 @@ public struct Client {
2323
public func aliases() -> Alias {
2424
return Alias(config: self.configuration)
2525
}
26+
27+
public func operations() -> Operations {
28+
return Operations(config: self.configuration)
29+
}
2630
}

Sources/Typesense/Operations.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import Foundation
2+
3+
public struct Operations {
4+
var apiCall: ApiCall
5+
var RESOURCEPATH = "operations"
6+
7+
public init(config: Configuration) {
8+
apiCall = ApiCall(config: config)
9+
}
10+
11+
public func getHealth() async throws -> (HealthStatus?, URLResponse?) {
12+
let (data, response) = try await apiCall.get(endPoint: "health")
13+
if let result = data {
14+
let health = try decoder.decode(HealthStatus.self, from: result)
15+
return (health, response)
16+
}
17+
return (nil, nil)
18+
}
19+
20+
public func getStats() async throws -> (Data?, URLResponse?) {
21+
let (data, response) = try await apiCall.get(endPoint: "stats.json")
22+
return (data, response)
23+
}
24+
25+
public func getMetrics() async throws -> (Data?, URLResponse?) {
26+
let (data, response) = try await apiCall.get(endPoint: "metrics.json")
27+
return (data, response)
28+
}
29+
30+
public func vote() async throws -> (SuccessStatus?, URLResponse?) {
31+
let (data, response) = try await apiCall.post(endPoint: "\(RESOURCEPATH)/vote", body: Data())
32+
if let result = data {
33+
let success = try decoder.decode(SuccessStatus.self, from: result)
34+
return (success, response)
35+
}
36+
return (nil, nil)
37+
}
38+
39+
public func snapshot(path: String? = "/tmp/typesense-data-snapshot") async throws -> (SuccessStatus?, URLResponse?) {
40+
let snapshotQueryParam = URLQueryItem(name: "snapshot_path", value: path)
41+
let (data, response) = try await apiCall.post(endPoint: "\(RESOURCEPATH)/snapshot", body: Data(), queryParameters: [snapshotQueryParam])
42+
if let result = data {
43+
let success = try decoder.decode(SuccessStatus.self, from: result)
44+
return (success, response)
45+
}
46+
return (nil, nil)
47+
}
48+
49+
public func toggleSlowRequestLog(seconds: Float) async throws -> (SuccessStatus?, URLResponse?) {
50+
let durationInMs = seconds * 1000
51+
let slowReq = SlowRequest(durationInMs)
52+
let slowReqData = try encoder.encode(slowReq)
53+
let (data, response) = try await apiCall.post(endPoint: "/config", body: slowReqData)
54+
if let result = data {
55+
let success = try decoder.decode(SuccessStatus.self, from: result)
56+
return (success, response)
57+
}
58+
return (nil, nil)
59+
}
60+
61+
}

Sources/Typesense/Shared/Coders.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,15 @@ public enum ActionModes: String {
3131
case upsert = "upsert"
3232
case update = "update"
3333
}
34+
35+
public struct SlowRequest: Codable {
36+
public var logSlowRequestsTimeMs: Float?
37+
38+
public init(_ timeInMS: Float? = nil) {
39+
self.logSlowRequestsTimeMs = timeInMS
40+
}
41+
42+
public enum CodingKeys: String, CodingKey {
43+
case logSlowRequestsTimeMs = "log-slow-requests-time-ms"
44+
}
45+
}

Tests/TypesenseTests/CollectionAliasTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import XCTest
2-
32
@testable import Typesense
43

54
final class CollectionAliasTests: XCTestCase {
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import XCTest
2+
@testable import Typesense
3+
4+
final class OperationTests: XCTestCase {
5+
func testGetHealth() async {
6+
let newConfig = Configuration(nodes: [Node(host: "localhost", port: "8108", nodeProtocol: "http")], apiKey: "xyz", logger: Logger(debugMode: true))
7+
let myClient = Client(config: newConfig)
8+
9+
do {
10+
let (data, _) = try await myClient.operations().getHealth()
11+
XCTAssertNotNil(data)
12+
guard let validData = data else {
13+
throw DataError.dataNotFound
14+
}
15+
print(validData)
16+
XCTAssertEqual(validData.ok, true)
17+
} catch HTTPError.serverError(let code, let desc) {
18+
print(desc)
19+
print("The response status code is \(code)")
20+
XCTAssertTrue(false)
21+
} catch (let error) {
22+
print(error.localizedDescription)
23+
XCTAssertTrue(false) //To prevent this, check availability of Typesense Server and retry
24+
}
25+
}
26+
27+
func testGetStats() async {
28+
let newConfig = Configuration(nodes: [Node(host: "localhost", port: "8108", nodeProtocol: "http")], apiKey: "xyz", logger: Logger(debugMode: true))
29+
let myClient = Client(config: newConfig)
30+
31+
do {
32+
let (data, _) = try await myClient.operations().getStats()
33+
XCTAssertNotNil(data)
34+
guard let validData = data else {
35+
throw DataError.dataNotFound
36+
}
37+
print(String(data: validData, encoding: .utf8)!)
38+
} catch HTTPError.serverError(let code, let desc) {
39+
print(desc)
40+
print("The response status code is \(code)")
41+
XCTAssertTrue(false)
42+
} catch (let error) {
43+
print(error.localizedDescription)
44+
XCTAssertTrue(false)
45+
}
46+
}
47+
48+
func testGetMetrics() async {
49+
let newConfig = Configuration(nodes: [Node(host: "localhost", port: "8108", nodeProtocol: "http")], apiKey: "xyz", logger: Logger(debugMode: true))
50+
let myClient = Client(config: newConfig)
51+
52+
do {
53+
let (data, _) = try await myClient.operations().getMetrics()
54+
XCTAssertNotNil(data)
55+
guard let validData = data else {
56+
throw DataError.dataNotFound
57+
}
58+
print(String(data: validData, encoding: .utf8)!)
59+
} catch HTTPError.serverError(let code, let desc) {
60+
print(desc)
61+
print("The response status code is \(code)")
62+
XCTAssertTrue(false)
63+
} catch (let error) {
64+
print(error.localizedDescription)
65+
XCTAssertTrue(false)
66+
}
67+
}
68+
69+
func testVote() async {
70+
let newConfig = Configuration(nodes: [Node(host: "localhost", port: "8108", nodeProtocol: "http")], apiKey: "xyz", logger: Logger(debugMode: true))
71+
let myClient = Client(config: newConfig)
72+
73+
do {
74+
let (data, _) = try await myClient.operations().vote()
75+
XCTAssertNotNil(data)
76+
guard let validData = data else {
77+
throw DataError.dataNotFound
78+
}
79+
print(validData)
80+
XCTAssertNotNil(validData.success)
81+
} catch HTTPError.serverError(let code, let desc) {
82+
print(desc)
83+
print("The response status code is \(code)")
84+
XCTAssertTrue(false)
85+
} catch (let error) {
86+
print(error.localizedDescription)
87+
XCTAssertTrue(false)
88+
}
89+
}
90+
91+
func testSnapshot() async {
92+
let newConfig = Configuration(nodes: [Node(host: "localhost", port: "8108", nodeProtocol: "http")], apiKey: "xyz", logger: Logger(debugMode: true))
93+
let myClient = Client(config: newConfig)
94+
95+
do {
96+
let (data, _) = try await myClient.operations().snapshot(path: "/tmp/typesense-data-snapshot")
97+
XCTAssertNotNil(data)
98+
guard let validData = data else {
99+
throw DataError.dataNotFound
100+
}
101+
print(validData)
102+
XCTAssertNotNil(validData.success)
103+
} catch HTTPError.serverError(let code, let desc) {
104+
print(desc)
105+
print("The response status code is \(code)")
106+
XCTAssertTrue(false)
107+
} catch (let error) {
108+
print(error.localizedDescription)
109+
XCTAssertTrue(false)
110+
}
111+
}
112+
113+
func testSlowRequestLog() async {
114+
let newConfig = Configuration(nodes: [Node(host: "localhost", port: "8108", nodeProtocol: "http")], apiKey: "xyz", logger: Logger(debugMode: true))
115+
let myClient = Client(config: newConfig)
116+
117+
do {
118+
let (data, _) = try await myClient.operations().toggleSlowRequestLog(seconds: 2)
119+
XCTAssertNotNil(data)
120+
guard let validData = data else {
121+
throw DataError.dataNotFound
122+
}
123+
print(validData)
124+
XCTAssertNotNil(validData.success)
125+
} catch HTTPError.serverError(let code, let desc) {
126+
print(desc)
127+
print("The response status code is \(code)")
128+
XCTAssertTrue(false)
129+
} catch (let error) {
130+
print(error.localizedDescription)
131+
XCTAssertTrue(false)
132+
}
133+
}
134+
}

0 commit comments

Comments
 (0)