neo4rs 0.8.0

Rust driver for Neo4j
Documentation
mod begin;
mod bye;
mod commit;
mod discard;
mod failure;
mod hello;
mod pull;
mod record;
mod reset;
mod rollback;
mod run;
mod success;

use crate::{
    errors::{Error, Result},
    types::{BoltMap, BoltWireFormat},
    version::Version,
    BoltString, BoltType,
};
use begin::Begin;
use bytes::Bytes;
use commit::Commit;
use discard::Discard;
use failure::Failure;
use hello::Hello;
use pull::Pull;
use record::Record;
use reset::Reset;
use rollback::Rollback;
use run::Run;
pub(crate) use success::Success;

#[derive(Debug, PartialEq, Clone)]
pub enum BoltResponse {
    Success(Success),
    Failure(Failure),
    Record(Record),
}

#[derive(Debug, PartialEq, Clone)]
pub enum BoltRequest {
    Hello(Hello),
    Run(Run),
    Pull(Pull),
    Discard(Discard),
    Begin(Begin),
    Commit(Commit),
    Rollback(Rollback),
    Reset(Reset),
}

pub struct HelloBuilder {
    agent: BoltString,
    principal: BoltString,
    credentials: BoltString,
    routing: Option<BoltMap>,
    version: Version,
}

impl HelloBuilder {
    pub fn new(principal: impl Into<BoltString>, credentials: impl Into<BoltString>) -> Self {
        Self {
            agent: "neo4rs".into(),
            principal: principal.into(),
            credentials: credentials.into(),
            routing: None,
            version: Version::V4,
        }
    }

    pub fn with_routing(self, routing: impl Into<Option<BoltMap>>) -> Self {
        Self {
            routing: routing.into(),
            ..self
        }
    }

    pub fn with_version(self, version: Version) -> Self {
        Self { version, ..self }
    }

    pub fn build(self) -> BoltRequest {
        let HelloBuilder {
            agent,
            principal,
            credentials,
            routing,
            version,
        } = self;
        BoltRequest::hello(agent, principal, credentials, routing, version)
    }
}

impl BoltRequest {
    pub fn hello(
        agent: BoltString,
        principal: BoltString,
        credentials: BoltString,
        routing: Option<BoltMap>,
        version: Version,
    ) -> BoltRequest {
        let mut data = BoltMap::default();
        data.put("user_agent".into(), BoltType::String(agent));
        data.put("scheme".into(), "basic".into());
        data.put("principal".into(), BoltType::String(principal));
        data.put("credentials".into(), BoltType::String(credentials));
        if version >= Version::V4_1 {
            if let Some(context) = routing {
                data.put("routing".into(), BoltType::Map(context));
            }
        }
        BoltRequest::Hello(Hello::new(data))
    }

    pub fn run(db: &str, query: &str, params: BoltMap) -> BoltRequest {
        BoltRequest::Run(Run::new(db.into(), query.into(), params))
    }

    pub fn pull(n: usize, qid: i64) -> BoltRequest {
        BoltRequest::Pull(Pull::new(n as i64, qid))
    }

    pub fn discard() -> BoltRequest {
        BoltRequest::Discard(Discard::default())
    }

    pub fn begin(db: &str) -> BoltRequest {
        let begin = Begin::new([("db".into(), db.into())].into_iter().collect());
        BoltRequest::Begin(begin)
    }

    pub fn commit() -> BoltRequest {
        BoltRequest::Commit(Commit::new())
    }

    pub fn rollback() -> BoltRequest {
        BoltRequest::Rollback(Rollback::new())
    }

    pub fn reset() -> BoltRequest {
        BoltRequest::Reset(Reset::new())
    }
}

impl BoltRequest {
    pub fn into_bytes(self, version: Version) -> Result<Bytes> {
        let bytes: Bytes = match self {
            BoltRequest::Hello(hello) => hello.into_bytes(version)?,
            BoltRequest::Run(run) => run.into_bytes(version)?,
            BoltRequest::Pull(pull) => pull.into_bytes(version)?,
            BoltRequest::Discard(discard) => discard.into_bytes(version)?,
            BoltRequest::Begin(begin) => begin.into_bytes(version)?,
            BoltRequest::Commit(commit) => commit.into_bytes(version)?,
            BoltRequest::Rollback(rollback) => rollback.into_bytes(version)?,
            BoltRequest::Reset(reset) => reset.into_bytes(version)?,
        };
        Ok(bytes)
    }
}

impl BoltResponse {
    pub fn parse(version: Version, mut response: Bytes) -> Result<BoltResponse> {
        if Success::can_parse(version, &response) {
            let success = Success::parse(version, &mut response)?;
            return Ok(BoltResponse::Success(success));
        }
        if Failure::can_parse(version, &response) {
            let failure = Failure::parse(version, &mut response)?;
            return Ok(BoltResponse::Failure(failure));
        }
        if Record::can_parse(version, &response) {
            let record = Record::parse(version, &mut response)?;
            return Ok(BoltResponse::Record(record));
        }
        Err(Error::UnknownMessage(format!(
            "unknown message {:?}",
            response
        )))
    }
}