Skip to content

Commit

Permalink
adds debounce
Browse files Browse the repository at this point in the history
  • Loading branch information
micheleriva committed Jul 17, 2024
1 parent 90aff13 commit f625983
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import Foundation

@available(macOS 12.0, *)
@available(macOS 13.0, *)
final class OramaClient {
private let id: String
private let apiKey: String
private let endpoint: String
private let debouncer = Debouncer()

private var searchDebounceTimer: Timer?
private var searchRequestCounter: Int = 0

init(params: OramaClientParams) {
Expand All @@ -15,15 +15,34 @@ final class OramaClient {
self.endpoint = params.endpoint
}

public func search<T: Encodable & Decodable>(query: ClientSearchParams) async throws -> SearchResults<T> {
// let concurrentRequestNumber = (self.searchRequestCounter += 1)
public func search<T: Encodable & Decodable>(query: ClientSearchParams, config: SearchRequestConfig? = SearchRequestConfig(debounce: nil)) async throws -> SearchResults<T> {
let shouldDebounce = config?.debounce != nil && (config?.debounce ?? 0) > 0

if shouldDebounce {
return try await withCheckedThrowingContinuation { continuation in
debouncer.debounce(interval: .milliseconds(Int64(config?.debounce ?? 0))) {
Task {
do {
let result = try await self.performSearch(query: query) as SearchResults<T>
continuation.resume(returning: result)
} catch {
continuation.resume(throwing: error)
}
}
}
}
} else {
return try await performSearch(query: query)
}
}

private func performSearch<T: Encodable & Decodable>(query: ClientSearchParams) async throws -> SearchResults<T> {
guard let oramaEndpointURL = URL(string: "\(self.endpoint)/search?api-key=\(self.apiKey)") else {
throw URLError(.badURL)
throw URLError(.badURL)
}

var request = URLRequest(url: oramaEndpointURL)
let httpBody = try self.encodeSearchQuery(query: query, version: "1.0.9", id: self.id) // @todo: use actual version
let httpBody = try self.encodeSearchQuery(query: query, version: "1.0.9", id: self.id)

request.httpBody = httpBody
request.httpMethod = "POST"
Expand All @@ -32,10 +51,10 @@ final class OramaClient {
let (responseData, response) = try await URLSession.shared.data(for: request)

if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode != 200 {
let responseDataString = String(data: responseData, encoding: .utf8) ?? "No response data"
print("HTTP Status Code: \(httpResponse.statusCode)")
print("Response Data: \(responseDataString)")
throw URLError(.badServerResponse)
let responseDataString = String(data: responseData, encoding: .utf8) ?? "No response data"
print("HTTP Status Code: \(httpResponse.statusCode)")
print("Response Data: \(responseDataString)")
throw URLError(.badServerResponse)
}

let decoder = JSONDecoder()
Expand Down
6 changes: 5 additions & 1 deletion Sources/oramacloud-client/types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ extension Encodable {
func toDictionary() throws -> [String: Any] {
let data = try JSONEncoder().encode(self)
let jsonObject = try JSONSerialization.jsonObject(with: data, options: .fragmentsAllowed)

guard let dictionary = jsonObject as? [String: Any] else {
throw NSError()
}
Expand Down Expand Up @@ -59,6 +59,10 @@ struct SearchResults<T> : Encodable, Decodable where T : Encodable & Decodable {
// @todo: add support for facets
}

struct SearchRequestConfig {
let debounce: Int?
}

struct SearchRequestPayload: Encodable {
let q: Data
let version: String
Expand Down
18 changes: 18 additions & 0 deletions Sources/oramacloud-client/utils.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
class Debouncer {
private var task: Task<(), Never>?

func debounce(interval: Duration = .nanoseconds(10000), operation: @escaping () -> Void) {
task?.cancel()

task = Task {
do {
try await Task.sleep(for: interval)
operation()
} catch {
// @todo: handle error
print("Error: \(error)")
}
}
}
}
9 changes: 6 additions & 3 deletions Tests/oramacloud-clientTests/oramacloud_clientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ struct E2ETest1Document: Encodable & Decodable {
let breed: String
}

let e2eEndpoint = "https://cloud.orama.run/v1/indexes/e2e-index-client-rv4bdd"
let e2eApiKey = "eaXWAKLxn05lefXAfB3wAhuTq3VaXGqx"

@available(macOS 12.0, *)
final class oramacloud_clientTests: XCTestCase {
func testEncodeSearchQuery() throws {
let clientParams = OramaClientParams(endpoint: "https://cloud.orama.run/v1/indexes/e2e-index-client-rv4bdd", apiKey: "eaXWAKLxn05lefXAfB3wAhuTq3VaXGqx")
let clientParams = OramaClientParams(endpoint: e2eEndpoint, apiKey: e2eApiKey)
let orama = OramaClient(params: clientParams)

let searchParams = ClientSearchParams(
Expand All @@ -26,7 +29,7 @@ final class oramacloud_clientTests: XCTestCase {
}

func testE2ESearch() async throws {
let clientParams = OramaClientParams(endpoint: "https://cloud.orama.run/v1/indexes/e2e-index-client-rv4bdd", apiKey: "eaXWAKLxn05lefXAfB3wAhuTq3VaXGqx")
let clientParams = OramaClientParams(endpoint: e2eEndpoint, apiKey: e2eApiKey)
let orama = OramaClient(params: clientParams)

let searchParams = ClientSearchParams(
Expand All @@ -41,7 +44,7 @@ final class oramacloud_clientTests: XCTestCase {
let expectation = XCTestExpectation(description: "Async search completes")

Task {
do {
do {
let searchResults: SearchResults<E2ETest1Document> = try await orama.search(query: searchParams)

XCTAssertGreaterThan(searchResults.count, 0)
Expand Down

0 comments on commit f625983

Please sign in to comment.