Skip to content

Commit

Permalink
feat: Support for transactions, analyzers and views (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
bakjos committed Dec 20, 2020
1 parent a669281 commit 1be43eb
Show file tree
Hide file tree
Showing 25 changed files with 1,941 additions and 66 deletions.
38 changes: 19 additions & 19 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,22 @@ thiserror = "1"
typed-builder = "0.7"
url = "2"

[dependencies.serde]
version = "1"
features = [ "derive" ]
[dependencies.serde]
version = "1"
features = [ "derive" ]

[dependencies.reqwest]
version = "0.10.4"
features = [ "gzip", "json" ]
optional = true
[dependencies.reqwest]
version = "0.10.4"
features = [ "gzip", "json" ]
optional = true

[dependencies.surf]
version = "2.0.0-alpha.5"
optional = true
[dependencies.surf]
version = "2.1.0"
optional = true

[dependencies.http-types]
version = "2.0.0"
optional = true
[dependencies.http-types]
version = "2.0.0"
optional = true

[dev-dependencies]
env_logger = "0.8"
Expand All @@ -66,10 +66,10 @@ dotenv = "0.15.0"
regex = "1.3.7"
anyhow = "1"

[dev-dependencies.tokio]
version = "0.2"
features = [ "macros", "rt-core" ]
[dev-dependencies.tokio]
version = "0.2"
features = [ "macros", "rt-core" ]

[dev-dependencies.async-std]
version = "1"
features = [ "attributes" ]
[dev-dependencies.async-std]
version = "1"
features = [ "attributes" ]
43 changes: 43 additions & 0 deletions examples/analyzer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#![allow(unused_imports)]
#![allow(unused_parens)]

use anyhow::Error;

use arangors::analyzer::{AnalyzerCase, AnalyzerFeature, AnalyzerInfo, NormAnalyzerProperties};
use arangors::Connection;
use std::collections::HashMap;

const URL: &str = "http://localhost:8529";

#[cfg_attr(feature = "reqwest_async", tokio::main)]
#[cfg_attr(feature = "surf_async", async_std::main)]
#[cfg_attr(feature = "reqwest_blocking", maybe_async::must_be_sync)]
async fn main() -> Result<(), Error> {
let analyzer_name = "test_analyzer".to_string();

let conn = Connection::establish_jwt(URL, "username", "password").await?;
let database = conn.db("test_db").await?;

let info = AnalyzerInfo::Norm {
name: analyzer_name.clone(),
features: Some(vec![AnalyzerFeature::Frequency, AnalyzerFeature::Norm]),
properties: Some(
NormAnalyzerProperties::builder()
.locale("en.utf-8".to_string())
.case(AnalyzerCase::Lower)
.build(),
),
};

database.create_analyzer(info).await?;

database.drop_analyzer(&analyzer_name).await?;

Ok(())
}
#[cfg(not(any(
feature = "reqwest_blocking",
feature = "reqwest_async",
feature = "surf_async"
)))]
fn main() {}
11 changes: 11 additions & 0 deletions examples/custom_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ impl ClientExt for ReqwestClient {
.map_err(|e| ClientError::HttpClient(format!("{:?}", e)))
}

fn copy_with_transaction(&self, transaction_id: String) -> Result<Self, ClientError> {
let request = self.0.get("/").build().unwrap();
let original_headers = request.headers();
let mut headers = HeaderMap::new();
for (name, value) in original_headers.iter() {
headers.insert(name, value.clone());
}
headers.insert("x-arango-trx-id", transaction_id.parse().unwrap());
ReqwestClient::new(headers)
}

async fn request(
&self,
request: http::Request<String>,
Expand Down
55 changes: 55 additions & 0 deletions examples/transaction.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#![allow(unused_imports)]
#![allow(unused_parens)]

use anyhow::Error;
use arangors::Document;
use arangors::{
transaction::{TransactionCollections, TransactionSettings},
Connection,
};
use log::info;
use serde_json::{json, Value};

const URL: &str = "http://localhost:8529";

#[cfg_attr(feature = "reqwest_async", tokio::main)]
#[cfg_attr(feature = "surf_async", async_std::main)]
#[cfg_attr(feature = "reqwest_blocking", maybe_async::must_be_sync)]
async fn main() -> Result<(), Error> {
let conn = Connection::establish_jwt(URL, "username", "password").await?;
let database = conn.db("test_db").await?;

let tx = database
.begin_transaction(
TransactionSettings::builder()
.lock_timeout(60000)
.wait_for_sync(true)
.collections(
TransactionCollections::builder()
.write(vec!["test_collection".to_owned()])
.build(),
)
.build(),
)
.await?;

let transactions = database.list_transactions().await?;
info!("Transactions: {:?}", transactions);

let test_doc: Document<Value> = Document::new(json!({
"user_name":"test21",
"user_name":"test21_pwd",
}));

let collection = tx.collection("test_collection").await?;
let document = collection
.create_document(test_doc, Default::default())
.await?;
let header = document.header().unwrap();
let _key = &header._key;

info!("Key: {}", _key);
tx.abort().await?;

Ok(())
}
56 changes: 56 additions & 0 deletions examples/view.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#![allow(unused_imports)]
#![allow(unused_parens)]

use anyhow::Error;

use arangors::view::{ArangoSearchViewLink, ArangoSearchViewPropertiesOptions, ViewOptions};
use arangors::Connection;
use std::collections::HashMap;

const URL: &str = "http://localhost:8529";

#[cfg_attr(feature = "reqwest_async", tokio::main)]
#[cfg_attr(feature = "surf_async", async_std::main)]
#[cfg_attr(feature = "reqwest_blocking", maybe_async::must_be_sync)]
async fn main() -> Result<(), Error> {
let collection_name = "test_collection".to_string();

let conn = Connection::establish_jwt(URL, "username", "password").await?;
let database = conn.db("test_db").await?;

let mut links: HashMap<String, ArangoSearchViewLink> = HashMap::new();

links.insert(
collection_name.clone(),
ArangoSearchViewLink::builder()
.include_all_fields(true)
.build(),
);

let view = database
.create_view(
ViewOptions::builder()
.name(format!("{}_view", collection_name))
.properties(
ArangoSearchViewPropertiesOptions::builder()
.links(links)
.build(),
)
.build(),
)
.await?;

println!("{:?}", view);

database
.drop_view(&format!("{}_view", collection_name))
.await?;

Ok(())
}
#[cfg(not(any(
feature = "reqwest_blocking",
feature = "reqwest_async",
feature = "surf_async"
)))]
fn main() {}
169 changes: 169 additions & 0 deletions src/analyzer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
use serde::{Deserialize, Serialize};
use typed_builder::TypedBuilder;

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum AnalyzerFeature {
Frequency,
Norm,
Position,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum AnalyzerCase {
Lower,
None,
Upper,
}

#[derive(Debug, Serialize, Deserialize, TypedBuilder, PartialEq)]
#[builder(doc)]
pub struct DelimiterAnalyzerProperties {
/// The value will be used as delimiter to split text into tokens as specified
/// in RFC 4180, without starting new records on newlines.
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub delimiter: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, TypedBuilder, PartialEq)]
#[builder(doc)]
pub struct StemAnalyzerProperties {
/// Format: `language[_COUNTRY][.encoding][@variant]`
pub locale: String,
}

#[derive(Debug, Serialize, Deserialize, TypedBuilder, PartialEq)]
#[builder(doc)]
pub struct NormAnalyzerProperties {
/// Format: `language[_COUNTRY][.encoding][@variant]`
pub locale: String,

/// Case conversion. Default: `"lower"`
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub case: Option<AnalyzerCase>,

/// Preserve accents in returned words. Default: `false`
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub accent: Option<bool>,
}

#[derive(Debug, Serialize, Deserialize, TypedBuilder, PartialEq)]
#[builder(doc)]
#[serde(rename_all = "camelCase")]
pub struct NgramAnalyzerProperties {
/// Minimum n-gram length.
pub min: u16,

/// Maximum n-gram length.
pub max: u16,

/// Output the original value as well.
pub preserve_riginal: bool,
}

#[derive(Debug, Serialize, Deserialize, TypedBuilder, PartialEq)]
#[builder(doc)]
#[serde(rename_all = "camelCase")]
pub struct TextAnalyzerProperties {
/// Format: `language[_COUNTRY][.encoding][@variant]`
pub locale: String,

#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub case: Option<AnalyzerCase>,

#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub accent: Option<bool>,

/// Words to omit from result.
/// Defaults to the words loaded from the file at `stopwordsPath`.
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub stopwords: Option<Vec<String>>,

/// Path with a `language` sub-directory containing files with words to omit.
///
/// Defaults to the path specified in the server-side environment variable
/// IRESEARCH_TEXT_STOPWORD_PATH` or the current working directory of the
/// ArangoDB process.
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub stopwords_path: Option<Vec<String>>,

/// Apply stemming on returned words.
/// Default: `true`
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub stemming: Option<bool>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase", tag = "type")]
pub enum AnalyzerInfo {
/// The `identity` Analyzer does not take additional properties.
Identity {
name: String,

#[serde(skip_serializing_if = "Option::is_none")]
features: Option<Vec<AnalyzerFeature>>,
},
Delimiter {
name: String,

#[serde(skip_serializing_if = "Option::is_none")]
features: Option<Vec<AnalyzerFeature>>,

#[serde(skip_serializing_if = "Option::is_none")]
properties: Option<DelimiterAnalyzerProperties>,
},

Stem {
name: String,

#[serde(skip_serializing_if = "Option::is_none")]
features: Option<Vec<AnalyzerFeature>>,

#[serde(skip_serializing_if = "Option::is_none")]
properties: Option<StemAnalyzerProperties>,
},

Norm {
name: String,

#[serde(skip_serializing_if = "Option::is_none")]
features: Option<Vec<AnalyzerFeature>>,

#[serde(skip_serializing_if = "Option::is_none")]
properties: Option<NormAnalyzerProperties>,
},

Ngram {
name: String,

#[serde(skip_serializing_if = "Option::is_none")]
features: Option<Vec<AnalyzerFeature>>,

#[serde(skip_serializing_if = "Option::is_none")]
properties: Option<NgramAnalyzerProperties>,
},

Text {
name: String,

#[serde(skip_serializing_if = "Option::is_none")]
features: Option<Vec<AnalyzerFeature>>,

#[serde(skip_serializing_if = "Option::is_none")]
properties: Option<TextAnalyzerProperties>,
},
}

#[derive(Debug, Serialize, Deserialize)]
pub struct AnalyzerDescription {
pub name: String,
}
Loading

0 comments on commit 1be43eb

Please sign in to comment.