Skip to content

Commit

Permalink
1.4.0 (#17)
Browse files Browse the repository at this point in the history
* 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 ab8f67a.

* 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

---------

Co-authored-by: Gregório Gevartosky Torrezan <[email protected]>
  • Loading branch information
makoni and gevartosky authored Apr 7, 2024
1 parent d618612 commit 68fd468
Show file tree
Hide file tree
Showing 25 changed files with 559 additions and 345 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
jobs:
macOS:
name: Build on macOS
runs-on: macOS-latest
runs-on: macOS-14
steps:
- name: Print Swift version
run: swift --version
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
name: Build on Ubuntu with Swift ${{matrix.swift}}
strategy:
matrix:
swift: [5.9, 5.8.1, 5.7.3]
swift: ["5.10", "5.9", "5.8"]
runs-on: ubuntu-latest
container:
image: swift:${{matrix.swift}}
Expand Down
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// swift-tools-version:5.7.1
// swift-tools-version:5.8
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "couchdb-vapor",
platforms: [.macOS(.v10_15), .iOS(.v13)],
platforms: [.macOS(.v10_15), .iOS(.v13), .tvOS(.v13), .watchOS(.v6)],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(name: "CouchDBClient", targets: ["CouchDBClient"]),
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@


This is a simple lib to work with CouchDB in Swift.
- Latest version is based on async/await and requires Swift 5.6 and newer. Works with Vapor 4.50 and newer.
- Latest version is based on async/await and requires Swift 5.8 or newer. Works with Vapor 4.50 and newer.
- Version 1.0.0 can be used with Vapor 4 without async/await. Swift 5.3 is required
- You can use the old version for Vapor 3 from vapor3 branch or using version < 1.0.0.

Expand Down Expand Up @@ -55,7 +55,7 @@ let couchDBClient = CouchDBClient(
)
```

If you don’t want to have your password in the code you can pass COUCHDB_PASS param in your command line. For example you can run your Server Side Swift project:
If you don’t want to have your password in the code you can pass `COUCHDB_PASS` param in your command line. For example you can run your Server Side Swift project:
```bash
COUCHDB_PASS=myPassword /path/.build/x86_64-unknown-linux-gnu/release/Run
```
Expand All @@ -76,7 +76,7 @@ Define your document model:

```swift
// Example struct
struct ExpectedDoc: CouchDBRepresentable, Codable {
struct ExpectedDoc: CouchDBRepresentable {
var name: String
var _id: String?
var _rev: String?
Expand All @@ -98,7 +98,7 @@ print(testDoc) // testDoc has _id and _rev values now
### Update data

```swift
// get data from DB by document ID
// get data from a database by document ID
var doc: ExpectedDoc = try await couchDBClient.get(dbName: "databaseName", uri: "documentId")
print(doc)

Expand All @@ -121,15 +121,15 @@ let response = try await couchDBClient.delete(fromDb: "databaseName", doc: doc)
let response = try await couchDBClient.delete(fromDb: "databaseName", uri: doc._id,rev: doc._rev)
```

Get all DBs example:
Get all databases example:

```swift
let dbs = try await couchDBClient.getAllDBs()
print(dbs)
// prints: ["_global_changes", "_replicator", "_users", "yourDBname"]
```

Find documents in DB by selector:
Find documents in a database by selector:
```swift
let selector = ["selector": ["name": "Sam"]]
let docs: [ExpectedDoc] = try await couchDBClient.find(in: "databaseName", selector: selector)
Expand Down
164 changes: 164 additions & 0 deletions Sources/CouchDBClient/CouchDB+Deprecated.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
//
// 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<ExpectedDoc>.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(eventLoopGroupProvider: .singleton)
}

defer {
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<ExpectedDoc>.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(eventLoopGroupProvider: .singleton)
}

defer {
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 <T: Codable & CouchDBRepresentable>(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<T: Codable & CouchDBRepresentable>(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)
}
}
4 changes: 2 additions & 2 deletions Sources/CouchDBClient/CouchDBClient.docc/CouchDBClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ A simple CouchDB client written in Swift.

Source code is available on [GitHub](https://github.com/makoni/couchdb-vapor).

CouchDBClient allows you to make simple requests to CouchDB. It's using Swift Concurrency (async/await) and supports Linux, iOS 13+ and macOS 10.15+.
CouchDBClient allows you to make simple requests to CouchDB. It's using Swift Concurrency (async/await) and supports Linux, iOS 13+, iPadOS 13+, tvOS 13+, watchOS 6+, visionOS 1.0+ and macOS 10.15+.

It's using [AsyncHTTPClient](https://github.com/swift-server/async-http-client) which makes it easy to use CouchDBClient for server-side development with Vapor 4. But it's easy to use it with any iOS or macOS app. Check the Essentials section for examples.

Expand All @@ -15,7 +15,7 @@ Currently CouchDBClient supports:
- Create DB.
- Delete DB.
- Get databases list.
- Get document by id or documents using view.
- Get a document by id or documents using a view.
- Insert/update documents.
- Find documents by selector.
- Delete documents.
Expand Down
14 changes: 10 additions & 4 deletions Sources/CouchDBClient/CouchDBClient.docc/Extensions/Client.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,19 @@ A CouchDB client class with methods using Swift Concurrency.
- ``createDB(_:eventLoopGroup:)``
- ``deleteDB(_:eventLoopGroup:)``
- ``dbExists(_:eventLoopGroup:)``
- ``get(dbName:uri:queryItems:eventLoopGroup:)``
- ``get(dbName:uri:queryItems:dateDecodingStrategy:eventLoopGroup:)``
- ``get(fromDB:uri:queryItems:eventLoopGroup:)``
- ``get(fromDB:uri:queryItems:dateDecodingStrategy:eventLoopGroup:)``
- ``insert(dbName:body:eventLoopGroup:)``
- ``insert(dbName:doc:dateEncodingStrategy:eventLoopGroup:)``
- ``update(dbName:doc:dateEncodingStrategy:eventLoopGroup:)``
- ``update(dbName:uri:body:eventLoopGroup:)``
- ``find(in:body:eventLoopGroup:)``
- ``find(in:selector:dateDecodingStrategy:eventLoopGroup:)``
- ``find(inDB:body:eventLoopGroup:)``
- ``find(inDB:selector:dateDecodingStrategy:eventLoopGroup:)``
- ``delete(fromDb:doc:eventLoopGroup:)``
- ``delete(fromDb:uri:rev:eventLoopGroup:)``

### Deprecated methods
- ``get(dbName:uri:queryItems:eventLoopGroup:)``
- ``get(dbName:uri:queryItems:dateDecodingStrategy:eventLoopGroup:)``
- ``find(in:body:eventLoopGroup:)``
- ``find(in:selector:dateDecodingStrategy:eventLoopGroup:)``
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
@Tutorial(time: 3) {
@Intro(title: "Handling CouchDB errors") {
Use CouchDBClient in macOS app
Use CouchDBClient in a macOS app

@Image(source: chapter1.png, alt: "Application icon")
}

@Section(title: "Use CouchDBClient in macOS app") {
@Section(title: "macOS app example") {
@ContentAndMedia {
Use CouchDBClient in macOS app
Use CouchDBClient in a macOS app

@Image(source: chapter1.png, alt: "Application icon")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let couchDBClient = CouchDBClient(

let dbName = "fortests"

struct MyDoc: CouchDBRepresentable, Codable {
struct MyDoc: CouchDBRepresentable {
var _id: String?
var _rev: String?
var title: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let couchDBClient = CouchDBClient(

let dbName = "fortests"

struct MyDoc: CouchDBRepresentable, Codable {
struct MyDoc: CouchDBRepresentable {
var _id: String?
var _rev: String?
var title: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let couchDBClient = CouchDBClient(

let dbName = "fortests"

struct MyDoc: CouchDBRepresentable, Codable {
struct MyDoc: CouchDBRepresentable {
var _id: String?
var _rev: String?
var title: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let couchDBClient = CouchDBClient(

let dbName = "fortests"

struct MyDoc: CouchDBRepresentable, Codable {
struct MyDoc: CouchDBRepresentable {
var _id: String?
var _rev: String?
var title: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let couchDBClient = CouchDBClient(

let dbName = "fortests"

struct MyDoc: CouchDBRepresentable, Codable {
struct MyDoc: CouchDBRepresentable {
var _id: String?
var _rev: String?
var title: String
Expand Down
Loading

0 comments on commit 68fd468

Please sign in to comment.