Skip to content

Commit

Permalink
Add deadpool-arangodb
Browse files Browse the repository at this point in the history
  • Loading branch information
Weasy666 committed Oct 7, 2021
1 parent 1098538 commit d3ef3a5
Show file tree
Hide file tree
Showing 9 changed files with 464 additions and 3 deletions.
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ jobs:
fail-fast: false
matrix:
crate:
- arangodb
- diesel
- lapin
- postgres
Expand Down Expand Up @@ -136,6 +137,7 @@ jobs:
# `nom = 6.0.0`. Try re-enable it on next `lapin` major version
# upgrade.
#- { crate: deadpool-lapin, msrv: '1.54.0' }
- { crate: deadpool-arangodb, msrv: '1.54.0' }
- { crate: deadpool-postgres, msrv: '1.54.0' }
- { crate: deadpool-redis, msrv: '1.54.0' }
- { crate: deadpool-sqlite, msrv: '1.54.0' }
Expand Down Expand Up @@ -165,13 +167,21 @@ jobs:
matrix:
crate:
- deadpool
- deadpool-arangodb
- deadpool-diesel
- deadpool-lapin
- deadpool-postgres
- deadpool-redis
- deadpool-sqlite
runs-on: ubuntu-latest
services:
arangodb:
image: arangodb
ports:
- 8529:8529
env:
ARANGO_ROOT_PASSWORD: deadpool
ARANGODB_OVERRIDE_DETECTED_TOTAL_MEMORY: 500M
postgres:
image: postgres
ports:
Expand Down Expand Up @@ -207,6 +217,10 @@ jobs:

- run: cargo test -p ${{ matrix.crate }} --all-features
env:
ARANGODB__URL: http://127.0.0.1:8529
ARANGODB__USERNAME: root
ARANGODB__PASSWORD: deadpool
ARANGODB__USE_JWT: "true"
PG__HOST: 127.0.0.1
PG__PORT: 5432
PG__USER: deadpool
Expand All @@ -231,6 +245,7 @@ jobs:
matrix:
crate:
- deadpool
- deadpool-arangodb
- deadpool-diesel
- deadpool-lapin
- deadpool-postgres
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ harness = false

[workspace]
members = [
"arangodb",
"diesel",
"lapin",
"postgres",
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ struct Manager {}
impl managed::Manager for Manager {
type Type = Computer;
type Error = Error;

async fn create(&self) -> Result<Computer, Error> {
Ok(Computer {})
}

async fn recycle(&self, _: &mut Computer) -> managed::RecycleResult<Error> {
Ok(())
}
Expand Down Expand Up @@ -97,6 +97,7 @@ Backend | Crate | Latest Version |
[async-memcached](https://crates.io/crates/async-memcached) | [deadpool-memcached](https://crates.io/crates/deadpool-memcached) | [![Latest Version](https://img.shields.io/crates/v/deadpool-memcached.svg)](https://crates.io/crates/deadpool-memcached) |
[rusqlite](https://crates.io/crates/rusqlite) | [deadpool-sqlite](https://crates.io/crates/deadpool-sqlite) | [![Latest Version](https://img.shields.io/crates/v/deadpool-sqlite.svg)](https://crates.io/crates/deadpool-sqlite) |
[diesel](https://crates.io/crates/diesel) | [deadpool-diesel](https://crates.io/crates/deadpool-diesel) | [![Latest Version](https://img.shields.io/crates/v/deadpool-diesel.svg)](https://crates.io/crates/deadpool-diesel) |
[arangors](https://crates.io/crates/arangors) | [deadpool-arangodb](https://crates.io/crates/deadpool-arangodb) | [![Latest Version](https://img.shields.io/crates/v/deadpool-arangodb.svg)](https://crates.io/crates/deadpool-arangodb) |

### Reasons for yet another connection pool

Expand Down
32 changes: 32 additions & 0 deletions arangodb/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[package]
name = "deadpool-arangodb"
version = "0.1.0-pre"
edition = "2018"
resolver = "2"
authors = ["Daniel Wiesenberg <[email protected]>"]
description = "Dead simple async pool for ArangoDB"
keywords = ["async", "database", "pool", "arango", "arangodb"]
license = "MIT/Apache-2.0"
repository = "https://github.com/bikeshedder/deadpool/arangodb"
readme = "README.md"

[package.metadata.docs.rs]
all-features = true

[features]
default = ["rt_tokio_1"]
rt_tokio_1 = ["deadpool/rt_tokio_1", "arangors/reqwest_async"]
rt_async-std_1 = ["deadpool/rt_async-std_1", "arangors/surf_async"]
serde = ["deadpool/serde", "serde_1"]

[dependencies]
deadpool = { path = "../", version = "0.9.0-pre", default-features = false, features = ["managed"] }
arangors = { git = "https://github.com/fMeow/arangors", rev = "2c31587", default-features = false, features = ["rocksdb"] }
serde_1 = { package = "serde", version = "1.0", features = ["derive"], optional = true }
url = "2.2"

[dev-dependencies]
config = { version = "0.11", default-features = false }
dotenv = "0.15.0"
futures = "0.3"
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
48 changes: 48 additions & 0 deletions arangodb/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Deadpool for ArangoDB [![Latest Version](https://img.shields.io/crates/v/deadpool-arangodb.svg)](https://crates.io/crates/deadpool-arangodb) ![Unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg "Unsafe forbidden") [![Rust 1.54+](https://img.shields.io/badge/rustc-1.54+-lightgray.svg "Rust 1.54+")](https://blog.rust-lang.org/2021/07/29/Rust-1.54.0.html)

Deadpool is a dead simple async pool for connections and objects
of any type.

This crate implements a [`deadpool`](https://crates.io/crates/deadpool)
manager for [`ArangoDB`](https://www.arangodb.com/) using [`arangors`](https://crates.io/crates/arangors).

## Features

| Feature | Description | Extra dependencies | Default |
| ------- | ----------- | ------------------ | ------- |
| `rt_tokio_1` | Enable support for [tokio](https://crates.io/crates/tokio) crate,<br>through the usage of [reqwest](https://crates.io/crates/reqwest) as http client | `deadpool/rt_tokio_1`, `arangors/reqwest_async` | yes |
| `rt_async-std_1` | Enable support for [async-std](https://crates.io/crates/config) crate,<br>through the usage of [surf](https://crates.io/crates/surf) as http client | `deadpool/rt_async-std_1`, `arangors/surf_async` | no |
| `serde` | Enable support for [serde](https://crates.io/crates/serde) crate | `deadpool/serde`, `serde/derive` | no |

## Example

```rust
use deadpool_arangodb::{Config, Runtime};

#[tokio::main]
async fn main() {
let mut cfg = Config {
url: Some("http://localhost:8529".to_string()),
username: Some("root".to_string()),
password: Some("deadpool".to_string()),
use_jwt: true,
pool: None,
};
let pool = cfg.create_pool(Runtime::Tokio1).unwrap();
let mut conn = pool.get().await.unwrap();

let db = conn.create_database("deadpool_favorite_foods")
.await.expect("Failed to create database: {:?}");

// Do stuff with db...
}
```

## License

Licensed under either of

- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)

at your option.
135 changes: 135 additions & 0 deletions arangodb/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
use deadpool::{managed::BuildError, Runtime};
#[cfg(feature = "serde")]
use serde_1::Deserialize;
use url::Url;

use crate::{Pool, PoolConfig};

/// Configuration object.
///
/// # Example (from environment)
///
/// By enabling the `serde` feature you can read the configuration using the
/// [`config`](https://crates.io/crates/config) crate as following:
/// ```env
/// ARANGODB__URL=arangodb.example.com
/// ARANGODB__USERNAME=root
/// ARANGODB__PASSWORD=deadpool
/// ARANGODB__USE_JWT=true
/// ARANGODB__POOL__MAX_SIZE=16
/// ARANGODB__POOL__TIMEOUTS__WAIT__SECS=2
/// ARANGODB__POOL__TIMEOUTS__WAIT__NANOS=0
/// ```
/// ```rust
/// # use serde_1 as serde;
/// #
/// #[derive(serde::Deserialize)]
/// # #[serde(crate = "serde_1")]
/// struct Config {
/// arango: deadpool_arangodb::Config,
/// }
///
/// impl Config {
/// pub fn from_env() -> Result<Self, config::ConfigError> {
/// let mut cfg = config::Config::new();
/// cfg.merge(config::Environment::new().separator("__")).unwrap();
/// cfg.try_into()
/// }
/// }
/// ```
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde_1::Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "serde_1"))]
pub struct Config {
/// ArangoDB URL.
///
/// See [Arangors Connection](arangors/connection/struct.GenericConnection.html#method.establish_jwt).
pub url: Option<String>,
/// ArangoDB username.
/// If you have not manually created a new user on a ArangoDB instance, then this must be `root`.
///
/// See [Arangors Connection](arangors/connection/struct.GenericConnection.html#method.establish_jwt).
pub username: Option<String>,
/// ArangoDB password.
///
/// See [Arangors Connection](arangors/connection/struct.GenericConnection.html#method.establish_jwt).
pub password: Option<String>,
/// If jwt authentication should be used. JWT token expires after 1 month.
///
/// See [Arangors Connection](arangors/connection/struct.GenericConnection.html#method.establish_jwt).
pub use_jwt: bool,

/// [`Pool`] configuration.
pub pool: Option<PoolConfig>,
}

impl Config {
/// Creates a new [`Config`] from the given URL.
///
/// Url format is: `http://username:password@localhost:8529/?use_jwt=true`. If `use_jwt` is missing, then it defaults to `true`.
pub fn from_url<U: Into<String>>(url: U) -> Result<Self, BuildError<()>> {
let url = url.into();
let url = Url::parse(&url)
.map_err(|e| BuildError::Config(format!("Could not extract a valid config from url: `{}` - Error: {}", url, e)))?;

let use_jwt = url.query_pairs()
.filter(|(name, _)| name == "use_jwt")
.map(|(_, value)| value.to_string())
.next();
let use_jwt = match use_jwt {
Some(use_jwt) => use_jwt.parse()
.map_err(|e| BuildError::Config(format!("Could not parse `use_jwt` value: `{}` - Error: {}", use_jwt, e)))?,
None => true,
};

Ok(Config {
url: Some(format!("{}://{}:{}", url.scheme(), url.host_str().unwrap(), url.port_or_known_default().unwrap())),
username: Some(url.username().to_string()),
password: url.password().map(ToString::to_string),
use_jwt,
pool: None,
})
}


/// Creates a new [`Pool`] using this [`Config`].
///
/// # Errors
///
/// See [`BuildError`] and [`ClientError`] for details.
///
/// [`ClientError`]: arangors::ClientError
pub fn create_pool(&self, runtime: Runtime) -> Result<Pool, BuildError<arangors::ClientError>> {
let manager = match (&self.url, &self.username, &self.password) {
(Some(_), Some(_), Some(_)) => crate::Manager::from_config(self.clone())?,
_ => {
return Err(BuildError::Config("url, username and password must be specified.".into()))
}
};

let pool_config = self.get_pool_config();
Pool::builder(manager)
.config(pool_config)
.runtime(runtime)
.build()
}

/// Returns [`deadpool::managed::PoolConfig`] which can be used to construct
/// a [`deadpool::managed::Pool`] instance.
#[must_use]
pub fn get_pool_config(&self) -> PoolConfig {
self.pool.unwrap_or_default()
}
}

impl Default for Config {
fn default() -> Self {
Self {
url: None,
username: None,
password: None,
use_jwt: true,
pool: None,
}
}
}
Loading

0 comments on commit d3ef3a5

Please sign in to comment.