Skip to content

Commit

Permalink
feat: index management (#33)
Browse files Browse the repository at this point in the history
* Initial index implementation

* Finish index implementation, add tests & docs

* Ignore example during testing

* Remove 'get_' from index retrieval function names

* Change to enum implementation for indexes

* Remove obsolete fields

* Switch implementation to struct with flattened enum

* Update documentation

* Add default to fields

Co-authored-by: Rafael Aggeler <rafael.aggeler@sfts-engineering.com>
Co-authored-by: Gitea <gitea@fake.local>
  • Loading branch information
3 people committed Aug 20, 2020
1 parent 8875b5a commit b2c4234
Show file tree
Hide file tree
Showing 4 changed files with 482 additions and 0 deletions.
69 changes: 69 additions & 0 deletions src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use serde::{de::DeserializeOwned, Deserialize};
use serde_json::value::Value;
use url::Url;

use crate::index::{DeleteIndexResponse, Index, IndexCollection};
use crate::{
aql::{AqlQuery, Cursor},
client::ClientExt,
Expand Down Expand Up @@ -297,6 +298,74 @@ impl<'a, C: ClientExt> Database<C> {
.build();
self.aql_query(aql).await
}

/// Create a new index on a collection.
///
/// # Note
/// this function would make a request to arango server.
#[maybe_async]
pub async fn create_index(
&self,
collection: &str,
index: &Index,
) -> Result<Index, ClientError> {
let mut url = self.base_url.join("_api/index").unwrap();
url.set_query(Some(&format!("collection={}", collection)));

let resp = self
.session
.post(url, &serde_json::to_string(&index)?)
.await?;

let result: Index = deserialize_response::<Index>(resp.body())?;

Ok(result)
}

/// Retrieve an index by id
///
/// # Note
/// this function would make a request to arango server.
#[maybe_async]
pub async fn index(&self, id: &str) -> Result<Index, ClientError> {
let url = self.base_url.join(&format!("_api/index/{}", id)).unwrap();

let resp = self.session.get(url, "").await?;

let result: Index = deserialize_response::<Index>(resp.body())?;

Ok(result)
}

/// Retrieve a list of indexes for a collection.
///
/// # Note
/// this function would make a request to arango server.
#[maybe_async]
pub async fn indexes(&self, collection: &str) -> Result<IndexCollection, ClientError> {
let mut url = self.base_url.join("_api/index").unwrap();
url.set_query(Some(&format!("collection={}", collection)));

let resp = self.session.get(url, "").await?;

let result: IndexCollection = deserialize_response::<IndexCollection>(resp.body())?;

Ok(result)
}

/// Delete an index by id.
///
/// # Note
/// this function would make a request to arango server.
#[maybe_async]
pub async fn delete_index(&self, id: &str) -> Result<DeleteIndexResponse, ClientError> {
let url = self.base_url.join(&format!("_api/index/{}", id)).unwrap();
let resp = self.session.delete(url, "").await?;

let result: DeleteIndexResponse = deserialize_response::<DeleteIndexResponse>(resp.body())?;

Ok(result)
}
}

#[derive(Debug, Deserialize)]
Expand Down
133 changes: 133 additions & 0 deletions src/index.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//! This module facilitates the building of new indexes as well as the retrieval
//! of existing indexes in ArangoDB.
//! The following types are supported:
//!
//! * Fulltext
//! * Geo
//! * Hash
//! * Persistent
//! * Skiplist
//! * Ttl (Time to live)
//!
//! An index of type [`Primary`] cannot be created and is only available for
//! the retrieval of existing indexes, as ArangoDB creates a primary index on every
//! collection.
//! For detailed information about ArangoDB indexes, please check out the official
//! ArangoDB [documentation](https://www.arangodb.com/docs/stable/http/indexes.html).
use serde::{Deserialize, Serialize};
use typed_builder::TypedBuilder;

/// Represents an [`Index`] in ArangoDB. The following types are
/// supported:
/// * Fulltext
/// * Geo
/// * Hash
/// * Persistent
/// * Skiplist
/// * Ttl (Time to live)
///
/// As different settings may be applied to different index types, use the [`settings`] field
/// on the index to specify the exact `type` of the index including the required settings.
///
/// # Example
/// ```ignore
/// let database = conn.db("test_db").await.unwrap();
///
/// let index = Index::builder()
/// .name(index_name)
/// .fields(vec!["password".to_string()])
/// .settings(IndexSettings::Persistent {
/// unique: true,
/// sparse: false,
/// deduplicate: false,
/// })
/// .build();
///
/// let index = database
/// .create_index(collection_name, &index)
/// .await?;
/// ```
#[derive(Debug, Serialize, Deserialize, Default, TypedBuilder)]
#[serde(rename_all = "camelCase")]
pub struct Index {
#[builder(default)]
pub fields: Vec<String>,
#[builder(default, setter(into))]
pub name: String,
#[builder(default)]
pub id: String,
#[builder(default)]
pub is_newly_created: Option<bool>,
#[builder(default)]
pub selectivity_estimate: Option<u8>,
#[builder(default)]
pub in_background: Option<bool>,
#[serde(flatten)]
#[builder(default)]
pub settings: IndexSettings,
}

/// Settings for the different index types. This `enum` also sets the index type.
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", tag = "type")]
pub enum IndexSettings {
Primary {
unique: bool,
sparse: bool,
},
Persistent {
unique: bool,
sparse: bool,
deduplicate: bool,
},
Hash {
unique: bool,
sparse: bool,
deduplicate: bool,
},
Skiplist {
unique: bool,
sparse: bool,
deduplicate: bool,
},
#[serde(rename_all = "camelCase")]
Ttl {
expire_after: u32,
},
#[serde(rename_all = "camelCase")]
Geo {
geo_json: bool,
},
#[serde(rename_all = "camelCase")]
Fulltext {
min_length: u32,
},
}

impl Default for IndexSettings {
fn default() -> Self {
IndexSettings::Persistent {
unique: false,
sparse: false,
deduplicate: false,
}
}
}

/// Represents a collection of indexes on a collection in ArangoDB.
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct IndexCollection {
pub error: bool,
pub code: u16,
pub indexes: Vec<Index>,
}

/// Response from ArangoDB when deleting an index
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DeleteIndexResponse {
pub id: String,
pub error: bool,
pub code: u16,
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,5 +403,6 @@ pub mod connection;
pub mod database;
pub mod document;
pub mod error;
pub mod index;
mod query;
pub mod response;
Loading

0 comments on commit b2c4234

Please sign in to comment.