From 8fc870241353682e67f22e33dca72c6e870c3cab Mon Sep 17 00:00:00 2001 From: Sergey Date: Thu, 13 Feb 2025 13:57:50 +0700 Subject: [PATCH] 1.7.0 (#25) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * swift-docc-plugin 1.3.0 * async-http-client 1.19.0 * replaced deprecated .createNew with the new .singleton * Adding _find capability. (#13) * docs * tabs * renames * added test for find method with body * docs added * findError added * tests renamed * added test for find method with generic type * docs * README updated * updated dependencies * docs updated * try Swift 5.7.1 * Update build-ubuntu.yml * Swift 5.7.3 * Revert "Swift 5.7.3" This reverts commit ab8f67a89f5b83ed20fe30a9965a3f2f58f6d2c1. * updated dependencies * Docs updated * Delete .github/workflows/CodeQL.yml * dependencies updated * fixed when update method didn’t use passed dateEncodingStrategy * noData error added * migrating to new HTTPClientRequest from HTTPClient.Request wip * migrating to new HTTPClientRequest from HTTPClient.Request wip * migrating to new HTTPClientRequest from HTTPClient.Request wip * migrating to new HTTPClientRequest from HTTPClient.Request wip * migrating to new HTTPClientRequest from HTTPClient.Request wip * migrating to new HTTPClientRequest from HTTPClient.Request wip * … * migrating to new HTTPClientRequest from HTTPClient.Request wip * rename * tests updated * auth fixed * collect body bytes before returning response * param renamed to make keep backward compatibility with old methods * marking old find as deprecated * private * deprecated message * renames * moved deprecations * docs * docs * added Codable to CouchDBRepresentable protocol * added RowsResponse model * docs * Vapor tutorial updated * docs * docs and refactoring * docs and refactoring * Tutorials updated * docs * platforms list updated * minimum swift version 5.8 * workflow updated * Update build-ubuntu.yml * Update build-macos.yml * import NIOFoundationCompat to fix building on Ubuntu * using async-http-client from 1.21.0. Not calling http * Using HTTPClient.shared if eventLoopGroup not provided. No more calls httpClient.syncShutdown() if using shared singleton * docs updated * docs updated * Vapor tutorial updated * A SwiftUI tutorial * tutorial fixed * updated dependencies * Package.resolved * docs updated * userName param is now required for CouchDB init * cleanup * docs * docs * docs * docs * docs * docs * docs * docs * docs * docs * docs * docs * docs * docs * docs * docs * dependencices updated * updated swift-docc-plugin URL. Updated dependencies to latest versions. * Update build-ubuntu.yml * dependencies updated * deleted deprecated methods * Sendable conformance * swift-format added * formatting * formatting * revert sendable * updated dependencies --------- Co-authored-by: Gregório Gevartosky Torrezan --- .swift-format | 70 ++++++++ Package.resolved | 46 ++--- .../CouchDBClient/CouchDB+Deprecated.swift | 168 ------------------ Sources/CouchDBClient/CouchDBClient.swift | 71 ++++---- .../CouchDBClient/Models/CouchDBError.swift | 2 +- .../Models/CouchDBFindResponse.swift | 6 +- .../Models/CouchDBRepresentable.swift | 2 +- .../Models/CouchUpdateResponse.swift | 1 - .../Models/CreateSessionResponse.swift | 15 +- .../CouchDBClient/Models/RowsResponse.swift | 4 +- .../Models/UpdateDBResponse.swift | 6 +- .../CouchDBClientTests.swift | 78 ++++---- 12 files changed, 190 insertions(+), 279 deletions(-) create mode 100644 .swift-format delete mode 100644 Sources/CouchDBClient/CouchDB+Deprecated.swift diff --git a/.swift-format b/.swift-format new file mode 100644 index 0000000..3912518 --- /dev/null +++ b/.swift-format @@ -0,0 +1,70 @@ +{ + "fileScopedDeclarationPrivacy" : { + "accessLevel" : "private" + }, + "indentConditionalCompilationBlocks" : false, + "indentSwitchCaseLabels" : false, + "indentation" : { + "tabs" : 1 + }, + "lineBreakAroundMultilineExpressionChainComponents" : false, + "lineBreakBeforeControlFlowKeywords" : false, + "lineBreakBeforeEachArgument" : false, + "lineBreakBeforeEachGenericRequirement" : false, + "lineLength" : 500, + "maximumBlankLines" : 1, + "multiElementCollectionTrailingCommas" : false, + "noAssignmentInExpressions" : { + "allowedFunctions" : [ + "XCTAssertNoThrow" + ] + }, + "prioritizeKeepingFunctionOutputTogether" : false, + "respectsExistingLineBreaks" : true, + "rules" : { + "AllPublicDeclarationsHaveDocumentation" : false, + "AlwaysUseLiteralForEmptyCollectionInit" : false, + "AlwaysUseLowerCamelCase" : false, + "AmbiguousTrailingClosureOverload" : true, + "BeginDocumentationCommentWithOneLineSummary" : false, + "DoNotUseSemicolons" : true, + "DontRepeatTypeInStaticProperties" : true, + "FileScopedDeclarationPrivacy" : false, + "FullyIndirectEnum" : true, + "GroupNumericLiterals" : false, + "IdentifiersMustBeASCII" : true, + "NeverForceUnwrap" : false, + "NeverUseForceTry" : false, + "NeverUseImplicitlyUnwrappedOptionals" : false, + "NoAccessLevelOnExtensionDeclaration" : false, + "NoAssignmentInExpressions" : true, + "NoBlockComments" : false, + "NoCasesWithOnlyFallthrough" : true, + "NoEmptyTrailingClosureParentheses" : false, + "NoLabelsInCasePatterns" : true, + "NoLeadingUnderscores" : false, + "NoParensAroundConditions" : false, + "NoPlaygroundLiterals" : true, + "NoVoidReturnOnFunctionSignature" : true, + "OmitExplicitReturns" : false, + "OneCasePerLine" : false, + "OneVariableDeclarationPerLine" : false, + "OnlyOneTrailingClosureArgument" : true, + "OrderedImports" : false, + "ReplaceForEachWithForLoop" : false, + "ReturnVoidInsteadOfEmptyTuple" : true, + "TypeNamesShouldBeCapitalized" : false, + "UseEarlyExits" : false, + "UseExplicitNilCheckInConditions" : true, + "UseLetInEveryBoundCaseVariable" : false, + "UseShorthandTypeNames" : true, + "UseSingleLinePropertyGetter" : true, + "UseSynthesizedInitializer" : true, + "UseTripleSlashForDocumentationComments" : false, + "UseWhereClausesInForLoops" : false, + "ValidateDocumentationComments" : false + }, + "spacesAroundRangeFormationOperators" : false, + "tabWidth" : 8, + "version" : 1 +} diff --git a/Package.resolved b/Package.resolved index a5db573..d3914ba 100644 --- a/Package.resolved +++ b/Package.resolved @@ -5,17 +5,17 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swift-server/async-http-client.git", "state" : { - "revision" : "6df8e1c17e68f0f93de2443b8c8cafca9ddcc89a", - "version" : "1.22.2" + "revision" : "b645ad40822b5c59ac92b758c5c17af054b5b01f", + "version" : "1.25.1" } }, { "identity" : "swift-algorithms", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-algorithms", + "location" : "https://github.com/apple/swift-algorithms.git", "state" : { - "revision" : "f6919dfc309e7f1b56224378b11e28bab5bccc42", - "version" : "1.2.0" + "revision" : "87e50f483c54e6efd60e885f7f5aa946cee68023", + "version" : "1.2.1" } }, { @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections.git", "state" : { - "revision" : "9bf03ff58ce34478e66aaee630e491823326fd06", - "version" : "1.1.3" + "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7", + "version" : "1.1.4" } }, { @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-http-types", "state" : { - "revision" : "ae67c8178eb46944fd85e4dc6dd970e1f3ed6ccd", - "version" : "1.3.0" + "revision" : "ef18d829e8b92d731ad27bb81583edd2094d1ce3", + "version" : "1.3.1" } }, { @@ -68,8 +68,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-log.git", "state" : { - "revision" : "9cb486020ebf03bfa5b5df985387a14a98744537", - "version" : "1.6.1" + "revision" : "96a2f8a0fa41e9e09af4585e2724c4e825410b91", + "version" : "1.6.2" } }, { @@ -77,8 +77,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio.git", "state" : { - "revision" : "9746cf80e29edfef2a39924a66731249223f42a3", - "version" : "2.72.0" + "revision" : "c51907a839e63ebf0ba2076bba73dd96436bd1b9", + "version" : "2.81.0" } }, { @@ -86,8 +86,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-extras.git", "state" : { - "revision" : "d1ead62745cc3269e482f1c51f27608057174379", - "version" : "1.24.0" + "revision" : "2e9746cfc57554f70b650b021b6ae4738abef3e6", + "version" : "1.24.1" } }, { @@ -95,8 +95,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-http2.git", "state" : { - "revision" : "b5f7062b60e4add1e8c343ba4eb8da2e324b3a94", - "version" : "1.34.0" + "revision" : "170f4ca06b6a9c57b811293cebcb96e81b661310", + "version" : "1.35.0" } }, { @@ -104,8 +104,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-ssl.git", "state" : { - "revision" : "7b84abbdcef69cc3be6573ac12440220789dcd69", - "version" : "2.27.2" + "revision" : "0cc3528ff48129d64ab9cab0b1cd621634edfc6b", + "version" : "2.29.3" } }, { @@ -113,8 +113,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-transport-services.git", "state" : { - "revision" : "38ac8221dd20674682148d6451367f89c2652980", - "version" : "1.21.0" + "revision" : "3c394067c08d1225ba8442e9cffb520ded417b64", + "version" : "1.23.1" } }, { @@ -131,8 +131,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-system.git", "state" : { - "revision" : "d2ba781702a1d8285419c15ee62fd734a9437ff5", - "version" : "1.3.2" + "revision" : "c8a44d836fe7913603e246acab7c528c2e780168", + "version" : "1.4.0" } } ], diff --git a/Sources/CouchDBClient/CouchDB+Deprecated.swift b/Sources/CouchDBClient/CouchDB+Deprecated.swift deleted file mode 100644 index fb253f3..0000000 --- a/Sources/CouchDBClient/CouchDB+Deprecated.swift +++ /dev/null @@ -1,168 +0,0 @@ -// -// CouchDB+Deprecated.swift -// -// -// Created by Sergei Armodin on 02.04.2024. -// - -import Foundation -import AsyncHTTPClient -import NIO -import NIOHTTP1 - -extension CouchDBClient { - /// Get data from DB. - /// - /// Examples: - /// - /// Define your document model: - /// ```swift - /// // Example struct - /// struct ExpectedDoc: CouchDBRepresentable, Codable { - /// var name: String - /// var _id: String? - /// var _rev: String? - /// } - /// ``` - /// - /// Get document by ID: - /// ```swift - /// // get data from DB by document ID - /// var response = try await couchDBClient.get(dbName: "databaseName", uri: "documentId") - /// - /// // parse JSON - /// let bytes = response.body!.readBytes(length: response.body!.readableBytes)! - /// let doc = try JSONDecoder().decode(ExpectedDoc.self, from: Data(bytes)) - /// ``` - /// - /// You can also provide CouchDB view document as uri and key in query. - /// - /// Get data and parse `RowsResponse`: - /// ```swift - /// let response = try await couchDBClient.get( - /// dbName: "databaseName", - /// uri: "_design/all/_view/by_url", - /// query: ["key": "\"\(url)\""] - /// ) - /// let bytes = response.body!.readBytes(length: response.body!.readableBytes)! - /// let decodedResponse = try JSONDecoder().decode(RowsResponse.self, from: data) - /// print(decodedResponse.rows) - /// print(decodedResponse.rows.first?.value) - /// ``` - /// - /// - Parameters: - /// - dbName: DB name. - /// - uri: URI (view or document id). - /// - query: Request query items. - /// - eventLoopGroup: NIO's EventLoopGroup object. New will be created if nil value provided. - /// - Returns: Request response. - @available(*, deprecated, message: "Use the new `get(fromDB:uri:queryItems:eventLoopGroup)` method.") - public func get(dbName: String, uri: String, queryItems: [URLQueryItem]? = nil, eventLoopGroup: EventLoopGroup? = nil) async throws -> HTTPClient.Response { - try await authIfNeed(eventLoopGroup: eventLoopGroup) - - let httpClient: HTTPClient - if let eventLoopGroup = eventLoopGroup { - httpClient = HTTPClient(eventLoopGroupProvider: .shared(eventLoopGroup)) - } else { - httpClient = HTTPClient.shared - } - - defer { - if eventLoopGroup != nil { - DispatchQueue.main.async { - try? httpClient.syncShutdown() - } - } - } - - let url = buildUrl(path: "/" + dbName + "/" + uri, query: queryItems ?? []) - let request = try buildRequestOld(fromUrl: url, withMethod: .GET) - let response = try await httpClient - .execute(request: request, deadline: .now() + .seconds(requestsTimeout)) - .get() - - if response.status == .unauthorized { - throw CouchDBClientError.unauthorized - } - - return response - } - - /// Find data in DB by selector. - /// - /// Example: - /// ```swift - /// let selector = ["selector": ["name": "Greg"]] - /// let bodyData = try JSONEncoder().encode(selector) - /// var findResponse = try await couchDBClient.find(in: testsDB, body: .data(bodyData)) - /// - /// let bytes = findResponse.body!.readBytes(length: findResponse.body!.readableBytes)! - /// let docs = try JSONDecoder().decode(CouchDBFindResponse.self, from: Data(bytes)).docs - /// ``` - /// - Parameters: - /// - dbName: DB name. - /// - body: Request body data. - /// - eventLoopGroup: NIO's EventLoopGroup object. New will be created if nil value provided. - /// - Returns: Request response. - @available(*, deprecated, message: "Use the new 'find(inDB:body:eventLoopGroup)' method.") - public func find(in dbName: String, body: HTTPClient.Body, eventLoopGroup: EventLoopGroup? = nil) async throws -> HTTPClient.Response { - try await authIfNeed(eventLoopGroup: eventLoopGroup) - - let httpClient: HTTPClient - if let eventLoopGroup = eventLoopGroup { - httpClient = HTTPClient(eventLoopGroupProvider: .shared(eventLoopGroup)) - } else { - httpClient = HTTPClient.shared - } - - defer { - if eventLoopGroup != nil { - DispatchQueue.main.async { - try? httpClient.syncShutdown() - } - } - } - - let url = buildUrl(path: "/" + dbName + "/_find", query: []) - var request = try buildRequestOld(fromUrl: url, withMethod: .POST) - request.body = body - let response = try await httpClient - .execute(request: request, deadline: .now() + .seconds(requestsTimeout)) - .get() - - if response.status == .unauthorized { - throw CouchDBClientError.unauthorized - } - - return response - } - - /// Build HTTP request from url string. - /// - Parameters: - /// - url: URL string. - /// - method: HTTP method. - /// - Returns: HTTP Request. - private func buildRequestOld(fromUrl url: String, withMethod method: HTTPMethod) throws -> HTTPClient.Request { - var headers = HTTPHeaders() - headers.add(name: "Content-Type", value: "application/json") - if let cookie = sessionCookie { - headers.add(name: "Cookie", value: cookie) - } - return try HTTPClient.Request( - url: url, - method: method, - headers: headers, - body: nil - ) - } - - @available(*, deprecated, renamed: "get", message: "Renamed to: get(fromDB:uri:queryItems:dateDecodingStrategy:eventLoopGroup)") - public func get (dbName: String, uri: String, queryItems: [URLQueryItem]? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .secondsSince1970, eventLoopGroup: EventLoopGroup? = nil) async throws -> T { - return try await get(fromDB: dbName, uri: uri, queryItems: queryItems, dateDecodingStrategy: dateDecodingStrategy, eventLoopGroup: eventLoopGroup) - } - - @available(*, deprecated, renamed: "find", message: "Renamed to: find(inDB:selector:dateDecodingStrategy:eventLoopGroup)") - public func find(in dbName: String, selector: Codable, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .secondsSince1970, eventLoopGroup: EventLoopGroup? = nil) async throws -> [T] { - return try await find(inDB: dbName, selector: selector, dateDecodingStrategy: dateDecodingStrategy, eventLoopGroup: eventLoopGroup) - } -} diff --git a/Sources/CouchDBClient/CouchDBClient.swift b/Sources/CouchDBClient/CouchDBClient.swift index b57658d..7567fc2 100644 --- a/Sources/CouchDBClient/CouchDBClient.swift +++ b/Sources/CouchDBClient/CouchDBClient.swift @@ -71,15 +71,15 @@ public class CouchDBClient { case http case https } - + // MARK: - Public properties - + /// Flag if authorized in CouchDB. public var isAuthorized: Bool { authData?.ok ?? false } /// You can set a timeout for requests in seconds. Default value is 30. public var requestsTimeout: Int64 = 30 - + // MARK: - Private properties /// Requests protocol. private var couchProtocol: CouchDBProtocol = .http @@ -100,7 +100,6 @@ public class CouchDBClient { /// Authorization response from CouchDB. private var authData: CreateSessionResponse? - // MARK: - Initializer /// Initializes a new instance of a CouchDB client. @@ -150,12 +149,12 @@ public class CouchDBClient { self.couchPort = couchPort self.userName = userName - self.userPassword = userPassword.isEmpty - ? ProcessInfo.processInfo.environment["COUCHDB_PASS"] ?? userPassword - : userPassword + self.userPassword = + userPassword.isEmpty + ? ProcessInfo.processInfo.environment["COUCHDB_PASS"] ?? userPassword + : userPassword } - - + // MARK: - Public methods /// Retrieves a list of all database names from the CouchDB server. @@ -197,7 +196,8 @@ public class CouchDBClient { let url = buildUrl(path: "/_all_dbs") let request = try buildRequest(fromUrl: url, withMethod: .GET) - let response = try await httpClient + let response = + try await httpClient .execute(request, timeout: .seconds(requestsTimeout)) if response.status == .unauthorized { @@ -252,7 +252,8 @@ public class CouchDBClient { let url = buildUrl(path: "/" + dbName) let request = try buildRequest(fromUrl: url, withMethod: .HEAD) - let response = try await httpClient + let response = + try await httpClient .execute(request, timeout: .seconds(requestsTimeout)) if response.status == .unauthorized { @@ -284,7 +285,7 @@ public class CouchDBClient { /// ``` /// /// - Note: Ensure that the CouchDB server is running and accessible. Handle any thrown errors appropriately, especially when dealing with authentication issues and potential conflicts if the database already exists. - @discardableResult public func createDB(_ dbName: String, eventLoopGroup: EventLoopGroup? = nil) async throws -> UpdateDBResponse { + @discardableResult public func createDB(_ dbName: String, eventLoopGroup: EventLoopGroup? = nil) async throws -> UpdateDBResponse { try await authIfNeed(eventLoopGroup: eventLoopGroup) let httpClient: HTTPClient @@ -306,7 +307,8 @@ public class CouchDBClient { let request = try self.buildRequest(fromUrl: url, withMethod: .PUT) - let response = try await httpClient + let response = + try await httpClient .execute(request, timeout: .seconds(requestsTimeout)) if response.status == .unauthorized { @@ -378,7 +380,8 @@ public class CouchDBClient { let request = try self.buildRequest(fromUrl: url, withMethod: .DELETE) - let response = try await httpClient + let response = + try await httpClient .execute(request, timeout: .seconds(requestsTimeout)) if response.status == .unauthorized { @@ -500,7 +503,8 @@ public class CouchDBClient { let url = buildUrl(path: "/" + dbName + "/" + uri, query: queryItems ?? []) let request = try buildRequest(fromUrl: url, withMethod: .GET) - var response = try await httpClient + var response = + try await httpClient .execute(request, timeout: .seconds(requestsTimeout)) if response.status == .unauthorized { @@ -558,7 +562,7 @@ public class CouchDBClient { /// ``` /// /// - Note: Ensure that the CouchDB server is running and accessible. Handle any thrown errors appropriately, especially when dealing with authentication issues and data decoding. - public func get (fromDB dbName: String, uri: String, queryItems: [URLQueryItem]? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .secondsSince1970, eventLoopGroup: EventLoopGroup? = nil) async throws -> T { + public func get(fromDB dbName: String, uri: String, queryItems: [URLQueryItem]? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .secondsSince1970, eventLoopGroup: EventLoopGroup? = nil) async throws -> T { let response: HTTPClientResponse = try await get(fromDB: dbName, uri: uri, queryItems: queryItems, eventLoopGroup: eventLoopGroup) if response.status == .unauthorized { @@ -667,7 +671,7 @@ public class CouchDBClient { /// let selector = ["selector": ["name": "Greg"]] /// let bodyData = try JSONEncoder().encode(selector) /// var findResponse = try await couchDBClient.find( - /// inDB: testsDB, + /// inDB: testsDB, /// body: .data(bodyData) /// ) /// @@ -700,7 +704,8 @@ public class CouchDBClient { let url = buildUrl(path: "/" + dbName + "/_find", query: []) var request = try buildRequest(fromUrl: url, withMethod: .POST) request.body = body - var response = try await httpClient + var response = + try await httpClient .execute(request, timeout: .seconds(requestsTimeout)) if response.status == .unauthorized { @@ -784,7 +789,7 @@ public class CouchDBClient { } else { httpClient = HTTPClient.shared } - + defer { if eventLoopGroup != nil { DispatchQueue.main.async { @@ -797,7 +802,8 @@ public class CouchDBClient { var request = try buildRequest(fromUrl: url, withMethod: .PUT) request.body = body - let response = try await httpClient + let response = + try await httpClient .execute(request, timeout: .seconds(requestsTimeout)) if response.status == .unauthorized { @@ -871,7 +877,7 @@ public class CouchDBClient { /// ``` /// /// - Note: Ensure that the CouchDB server is running and accessible. Handle any thrown errors appropriately, especially when dealing with document updates and server responses. - public func update (dbName: String, doc: inout T, dateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .secondsSince1970, eventLoopGroup: EventLoopGroup? = nil ) async throws { + public func update(dbName: String, doc: inout T, dateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .secondsSince1970, eventLoopGroup: EventLoopGroup? = nil) async throws { guard let id = doc._id else { throw CouchDBClientError.idMissing } guard doc._rev?.isEmpty == false else { throw CouchDBClientError.revMissing } @@ -964,7 +970,8 @@ public class CouchDBClient { var request = try self.buildRequest(fromUrl: url, withMethod: .POST) request.body = body - let response = try await httpClient + let response = + try await httpClient .execute(request, timeout: .seconds(requestsTimeout)) if response.status == .unauthorized { @@ -1031,7 +1038,7 @@ public class CouchDBClient { /// ``` /// /// - Note: Ensure that the CouchDB server is running and accessible. Handle any thrown errors appropriately, especially when dealing with document insertion and server responses. - public func insert (dbName: String, doc: inout T, dateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .secondsSince1970, eventLoopGroup: EventLoopGroup? = nil ) async throws { + public func insert(dbName: String, doc: inout T, dateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .secondsSince1970, eventLoopGroup: EventLoopGroup? = nil) async throws { let encoder = JSONEncoder() encoder.dateEncodingStrategy = dateEncodingStrategy let insertEncodeData = try encoder.encode(doc) @@ -1096,12 +1103,16 @@ public class CouchDBClient { } } - let url = buildUrl(path: "/" + dbName + "/" + uri, query: [ - URLQueryItem(name: "rev", value: rev) - ]) + let url = buildUrl( + path: "/" + dbName + "/" + uri, + query: [ + URLQueryItem(name: "rev", value: rev) + ] + ) let request = try self.buildRequest(fromUrl: url, withMethod: .DELETE) - let response = try await httpClient + let response = + try await httpClient .execute(request, timeout: .seconds(requestsTimeout)) if response.status == .unauthorized { @@ -1149,7 +1160,6 @@ public class CouchDBClient { } } - // MARK: - Private methods internal extension CouchDBClient { /// Build URL string. @@ -1206,7 +1216,8 @@ internal extension CouchDBClient { let dataString = "name=\(userName)&password=\(userPassword)" request.body = .bytes(ByteBuffer(string: dataString)) - let response = try await httpClient + let response = + try await httpClient .execute(request, timeout: .seconds(requestsTimeout)) if response.status == .unauthorized { @@ -1253,7 +1264,7 @@ internal extension CouchDBClient { return authData } - func buildRequest(fromUrl url: String, withMethod method: HTTPMethod) throws -> HTTPClientRequest { + func buildRequest(fromUrl url: String, withMethod method: HTTPMethod) throws -> HTTPClientRequest { var headers = HTTPHeaders() headers.add(name: "Content-Type", value: "application/json") if let cookie = sessionCookie { diff --git a/Sources/CouchDBClient/Models/CouchDBError.swift b/Sources/CouchDBClient/Models/CouchDBError.swift index a232438..657e2fe 100644 --- a/Sources/CouchDBClient/Models/CouchDBError.swift +++ b/Sources/CouchDBClient/Models/CouchDBError.swift @@ -1,6 +1,6 @@ // // CouchDBError.swift -// +// // // Created by Sergey Armodin on 01.09.2022. // diff --git a/Sources/CouchDBClient/Models/CouchDBFindResponse.swift b/Sources/CouchDBClient/Models/CouchDBFindResponse.swift index dc5b045..f84ff75 100644 --- a/Sources/CouchDBClient/Models/CouchDBFindResponse.swift +++ b/Sources/CouchDBClient/Models/CouchDBFindResponse.swift @@ -1,6 +1,6 @@ // // CouchDBFindResponse.swift -// +// // // Created by Gregorio Gevartosky Torrezan on 2023-11-15. // @@ -8,6 +8,6 @@ import Foundation public struct CouchDBFindResponse: Codable { - var docs: [T] - var bookmark: String? + var docs: [T] + var bookmark: String? } diff --git a/Sources/CouchDBClient/Models/CouchDBRepresentable.swift b/Sources/CouchDBClient/Models/CouchDBRepresentable.swift index 74409ee..9ba47cc 100644 --- a/Sources/CouchDBClient/Models/CouchDBRepresentable.swift +++ b/Sources/CouchDBClient/Models/CouchDBRepresentable.swift @@ -1,6 +1,6 @@ // // CouchDBRepresentable.swift -// +// // // Created by Sergey Armodin on 30.08.2022. // diff --git a/Sources/CouchDBClient/Models/CouchUpdateResponse.swift b/Sources/CouchDBClient/Models/CouchUpdateResponse.swift index 8d6d7c8..e1471ce 100644 --- a/Sources/CouchDBClient/Models/CouchUpdateResponse.swift +++ b/Sources/CouchDBClient/Models/CouchUpdateResponse.swift @@ -7,7 +7,6 @@ import Foundation - /// Model for insert/update/delete request response. public struct CouchUpdateResponse: Codable { /// Operation status. diff --git a/Sources/CouchDBClient/Models/CreateSessionResponse.swift b/Sources/CouchDBClient/Models/CreateSessionResponse.swift index 19134e4..7e81ba7 100644 --- a/Sources/CouchDBClient/Models/CreateSessionResponse.swift +++ b/Sources/CouchDBClient/Models/CreateSessionResponse.swift @@ -1,6 +1,6 @@ // // CreateSessionResponse.swift -// +// // // Created by Sergey Armodin on 15.05.2020. // @@ -9,10 +9,10 @@ import Foundation /// Resonse model for create session request struct CreateSessionResponse: Codable { - var ok: Bool - var name: String? - var roles: [String]? - + let ok: Bool + let name: String? + let roles: [String]? + enum CodingKeys: String, CodingKey { case ok case name @@ -23,12 +23,11 @@ struct CreateSessionResponse: Codable { extension CreateSessionResponse { init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - + let ok = try container.decodeIfPresent(Bool.self, forKey: .ok) ?? false let name = try container.decodeIfPresent(String.self, forKey: .name) let roles = try container.decodeIfPresent([String].self, forKey: .roles) - + self.init(ok: ok, name: name, roles: roles) } } - diff --git a/Sources/CouchDBClient/Models/RowsResponse.swift b/Sources/CouchDBClient/Models/RowsResponse.swift index 328609b..ee301d8 100644 --- a/Sources/CouchDBClient/Models/RowsResponse.swift +++ b/Sources/CouchDBClient/Models/RowsResponse.swift @@ -1,6 +1,6 @@ // // RowsResponse.swift -// +// // // Created by Sergei Armodin on 07.04.2024. // @@ -13,7 +13,7 @@ public struct RowsResponse: Codable { /// A CouchDB document. public let value: T } - + /// Total documents in a response. public let total_rows: Int /// Results offset. diff --git a/Sources/CouchDBClient/Models/UpdateDBResponse.swift b/Sources/CouchDBClient/Models/UpdateDBResponse.swift index 955e140..8d7e8e0 100644 --- a/Sources/CouchDBClient/Models/UpdateDBResponse.swift +++ b/Sources/CouchDBClient/Models/UpdateDBResponse.swift @@ -1,6 +1,6 @@ // // UpdateDBResponse.swift -// +// // // Created by Sergei Armodin on 26.12.2022. // @@ -9,6 +9,6 @@ import Foundation /// DB creation response. public struct UpdateDBResponse: Codable { - /// Operation status. - public let ok: Bool + /// Operation status. + public let ok: Bool } diff --git a/Tests/CouchDBClientTests/CouchDBClientTests.swift b/Tests/CouchDBClientTests/CouchDBClientTests.swift index e718967..821fd32 100644 --- a/Tests/CouchDBClientTests/CouchDBClientTests.swift +++ b/Tests/CouchDBClientTests/CouchDBClientTests.swift @@ -3,7 +3,6 @@ import NIO import AsyncHTTPClient @testable import CouchDBClient - final class CouchDBClientTests: XCTestCase { struct ExpectedDoc: CouchDBRepresentable { @@ -11,7 +10,7 @@ final class CouchDBClientTests: XCTestCase { var _id: String? var _rev: String? } - + let testsDB = "fortests" let couchDBClient = CouchDBClient( @@ -21,33 +20,33 @@ final class CouchDBClientTests: XCTestCase { userName: "admin", userPassword: ProcessInfo.processInfo.environment["COUCHDB_PASS"] ?? "" ) - + override func setUp() async throws { - try await super.setUp() + try await super.setUp() + } + + func test00_CreateDB() async throws { + do { + let exists = try await couchDBClient.dbExists(testsDB) + if exists { + try await couchDBClient.deleteDB(testsDB) + } + + try await couchDBClient.createDB(testsDB) + } catch { + XCTFail(error.localizedDescription) + } + } + + func test01_DBExists() async throws { + do { + let exists = try await couchDBClient.dbExists(testsDB) + XCTAssertTrue(exists) + } catch { + XCTFail(error.localizedDescription) + } } - func test00_CreateDB() async throws { - do { - let exists = try await couchDBClient.dbExists(testsDB) - if exists { - try await couchDBClient.deleteDB(testsDB) - } - - try await couchDBClient.createDB(testsDB) - } catch { - XCTFail(error.localizedDescription) - } - } - - func test01_DBExists() async throws { - do { - let exists = try await couchDBClient.dbExists(testsDB) - XCTAssertTrue(exists) - } catch { - XCTFail(error.localizedDescription) - } - } - func test03_GetAllDbs() async throws { do { let dbs = try await couchDBClient.getAllDBs() @@ -145,7 +144,7 @@ final class CouchDBClientTests: XCTestCase { XCTFail(error.localizedDescription) } } - + func test05_InsertGetUpdateDelete() async throws { var testDoc = ExpectedDoc(name: "test name") var expectedInsertId: String = "" @@ -246,12 +245,14 @@ final class CouchDBClientTests: XCTestCase { XCTFail(error.localizedDescription) } } - + func test06_BuildUrl() { let expectedUrl = "http://127.0.0.1:5984?key=testKey" - let url = couchDBClient.buildUrl(path: "", query: [ - URLQueryItem(name: "key", value: "testKey") - ]) + let url = couchDBClient.buildUrl( + path: "", + query: [ + URLQueryItem(name: "key", value: "testKey") + ]) XCTAssertEqual(url, expectedUrl) } @@ -271,7 +272,6 @@ final class CouchDBClientTests: XCTestCase { body: .bytes(ByteBuffer(data: insertEncodedData)) ) - let selector = ["selector": ["name": "Greg"]] let bodyData = try JSONEncoder().encode(selector) let requestBody: HTTPClientRequest.Body = .bytes(ByteBuffer(data: bodyData)) @@ -329,11 +329,11 @@ final class CouchDBClientTests: XCTestCase { } } - func test99_deleteDB() async throws { - do { - try await couchDBClient.deleteDB(testsDB) - } catch { - XCTFail(error.localizedDescription) - } - } + func test99_deleteDB() async throws { + do { + try await couchDBClient.deleteDB(testsDB) + } catch { + XCTFail(error.localizedDescription) + } + } }