@@ -22,6 +22,8 @@ public enum CouchDBClientError: Error {
22
22
case insertError( error: CouchDBError )
23
23
/// Update request wasn't successful.
24
24
case updateError( error: CouchDBError )
25
+ /// Find request wasn't successful.
26
+ case findError( error: CouchDBError )
25
27
/// Uknown response from CouchDB.
26
28
case unknownResponse
27
29
/// Wrong username or password.
@@ -41,6 +43,8 @@ extension CouchDBClientError: LocalizedError {
41
43
return " Insert request wasn't successful: \( error. localizedDescription) "
42
44
case . updateError( let error) :
43
45
return " Update request wasn't successful: \( error. localizedDescription) "
46
+ case . findError( let error) :
47
+ return " Find request wasn't successful: \( error. localizedDescription) "
44
48
case . unknownResponse:
45
49
return " Uknown response from CouchDB. "
46
50
case . unauthorized:
@@ -478,6 +482,96 @@ public class CouchDBClient {
478
482
throw parsingError
479
483
}
480
484
}
485
+
486
+ /// Find data in DB by selector.
487
+ ///
488
+ /// Example:
489
+ ///
490
+ /// ```swift
491
+ /// // find documents in DB by selector
492
+ /// let selector = ["selector": ["name": "Sam"]]
493
+ /// let docs: [ExpectedDoc] = try await couchDBClient.find(in: testsDB, selector: selector)
494
+ /// ```
495
+ ///
496
+ /// - Parameters:
497
+ /// - in dbName: DB name.
498
+ /// - selector: Codable representation of json selector query.
499
+ /// - eventLoopGroup: NIO's EventLoopGroup object. New will be created if nil value provided.
500
+ /// - Returns: Array of documents [T].
501
+ public func find< T: Codable & CouchDBRepresentable > ( in dbName: String , selector: Codable , dateDecodingStrategy: JSONDecoder . DateDecodingStrategy = . secondsSince1970, eventLoopGroup: EventLoopGroup ? = nil ) async throws -> [ T ] {
502
+ let encoder = JSONEncoder ( )
503
+ let selectorData = try encoder. encode ( selector)
504
+
505
+ let findResponse = try await find (
506
+ in: dbName,
507
+ body: . data( selectorData) ,
508
+ eventLoopGroup: eventLoopGroup
509
+ )
510
+
511
+ guard var body = findResponse. body, let bytes = body. readBytes ( length: body. readableBytes) else {
512
+ throw CouchDBClientError . unknownResponse
513
+ }
514
+
515
+ let data = Data ( bytes)
516
+ let decoder = JSONDecoder ( )
517
+ decoder. dateDecodingStrategy = dateDecodingStrategy
518
+
519
+ do {
520
+ let doc = try decoder. decode ( CouchDBFindResponse< T> . self , from: data)
521
+ return doc. docs
522
+ } catch let parsingError {
523
+ if let couchdbError = try ? decoder. decode ( CouchDBError . self, from: data) {
524
+ throw CouchDBClientError . findError ( error: couchdbError)
525
+ }
526
+ throw parsingError
527
+ }
528
+ }
529
+
530
+ /// Find data in DB by selector.
531
+ ///
532
+ /// Example:
533
+ /// ```swift
534
+ /// let selector = ["selector": ["name": "Greg"]]
535
+ /// let bodyData = try JSONEncoder().encode(selector)
536
+ /// var findResponse = try await couchDBClient.find(in: testsDB, body: .data(bodyData))
537
+ ///
538
+ /// let bytes = findResponse.body!.readBytes(length: findResponse.body!.readableBytes)!
539
+ /// let docs = try JSONDecoder().decode(CouchDBFindResponse<ExpectedDoc>.self, from: Data(bytes)).docs
540
+ /// ```
541
+ /// - Parameters:
542
+ /// - dbName: DB name.
543
+ /// - body: Request body data.
544
+ /// - eventLoopGroup: NIO's EventLoopGroup object. New will be created if nil value provided.
545
+ /// - Returns: Request response.
546
+ public func find( in dbName: String , body: HTTPClient . Body , eventLoopGroup: EventLoopGroup ? = nil ) async throws -> HTTPClient . Response {
547
+ try await authIfNeed ( eventLoopGroup: eventLoopGroup)
548
+
549
+ let httpClient : HTTPClient
550
+ if let eventLoopGroup = eventLoopGroup {
551
+ httpClient = HTTPClient ( eventLoopGroupProvider: . shared( eventLoopGroup) )
552
+ } else {
553
+ httpClient = HTTPClient ( eventLoopGroupProvider: . singleton)
554
+ }
555
+
556
+ defer {
557
+ DispatchQueue . main. async {
558
+ try ? httpClient. syncShutdown ( )
559
+ }
560
+ }
561
+
562
+ let url = buildUrl ( path: " / " + dbName + " /_find " , query: [ ] )
563
+ var request = try buildRequest ( fromUrl: url, withMethod: . POST)
564
+ request. body = body
565
+ let response = try await httpClient
566
+ . execute ( request: request, deadline: . now( ) + . seconds( requestsTimeout) )
567
+ . get ( )
568
+
569
+ if response. status == . unauthorized {
570
+ throw CouchDBClientError . unauthorized
571
+ }
572
+
573
+ return response
574
+ }
481
575
482
576
/// Update data in DB.
483
577
///
0 commit comments