aragog 0.17.0

A simple lightweight object-document mapper for ArangoDB
Documentation
use crate::undefined_record::UndefinedRecord;
use crate::{DatabaseRecord, Error, Record};
use std::ops::{Deref, DerefMut};

/// Query result containing the queried documents
#[derive(Debug, Clone)]
pub struct QueryResult<T>(pub Vec<DatabaseRecord<T>>);

impl<T: Clone + Record> QueryResult<T> {
    /// Instantiates a new `QueryResult` from a document collection
    #[must_use]
    #[inline]
    pub fn new(documents: Vec<DatabaseRecord<T>>) -> Self {
        Self(documents)
    }

    /// Consumes and returns the only document of the current `QueryResult`.
    ///
    /// # Errors
    ///
    /// If there is no document or more than one, an [`Error`]::[`NotFound`] is returned.
    ///
    /// # Panics
    ///
    /// Should not panic
    ///
    /// [`Error`]: crate::Error
    /// [`NotFound`]: crate::Error::NotFound
    pub fn uniq(self) -> Result<DatabaseRecord<T>, Error> {
        if self.is_empty() || self.len() > 1 {
            log::error!(
                "Wrong number of {} returned: {}",
                T::COLLECTION_NAME,
                self.len()
            );
            return Err(Error::NotFound {
                item: T::COLLECTION_NAME.to_string(),
                id: "queried".to_string(),
                source: None,
            });
        }
        Ok(self.0.into_iter().next().unwrap())
    }

    /// Consumes and returns the first document of the current `QueryResult`
    #[must_use]
    pub fn first_record(self) -> Option<DatabaseRecord<T>> {
        self.0.into_iter().next()
    }
}

impl QueryResult<UndefinedRecord> {
    /// Retrieves deserialized documents from the json results. The documents not matching `T` will not be returned.
    ///
    /// # Example
    /// If you want to do a graph query that can return different models you can use this method to retrieve the serialized record:
    ///
    /// ```rust no_run
    /// # use aragog::{query::Query, Record, DatabaseConnection};
    /// # use serde::{Serialize, Deserialize};
    /// #
    /// # #[derive(Record, Clone, Serialize, Deserialize)]
    /// # struct User {}
    /// # #[derive(Record, Clone, Serialize, Deserialize)]
    /// # struct Topic {}
    /// # #[derive(Record, Clone, Serialize, Deserialize)]
    /// # struct Role {}
    /// # #[tokio::main]
    /// # async fn main() {
    /// # let db_accessor = DatabaseConnection::builder().build().await.unwrap();
    /// let json_results = Query::outbound(1, 5, "ChildOf", "User/123").call(&db_accessor).await.unwrap();
    ///
    /// let user_results = json_results.get_records::<User>();
    /// let topic_results = json_results.get_records::<Topic>();
    /// let role_results = json_results.get_records::<Role>();
    /// # }
    /// ```
    #[must_use]
    pub fn get_records<T: Record>(&self) -> QueryResult<T> {
        self.iter()
            .filter_map(|db_record| {
                serde_json::from_value(db_record.0.clone())
                    .ok()
                    .map(|record| DatabaseRecord {
                        key: db_record.key.clone(),
                        id: db_record.id.clone(),
                        rev: db_record.rev.clone(),
                        record,
                    })
            })
            .collect()
    }
}

impl<T: Record> FromIterator<DatabaseRecord<T>> for QueryResult<T> {
    fn from_iter<I: IntoIterator<Item = DatabaseRecord<T>>>(iter: I) -> Self {
        Self::new(iter.into_iter().collect())
    }
}

impl<T: Record> From<Vec<DatabaseRecord<T>>> for QueryResult<T> {
    fn from(documents: Vec<DatabaseRecord<T>>) -> Self {
        Self::new(documents)
    }
}

impl<T: Record> Deref for QueryResult<T> {
    type Target = Vec<DatabaseRecord<T>>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T: Record> DerefMut for QueryResult<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}