v-storage 0.2.1

Storage layer for the veda platform
Documentation
use super::tt_wrapper::{Client, ClientConfig, IteratorType};
use v_individual_model::onto::individual::Individual;
use v_individual_model::onto::parser::parse_raw;
use crate::common::{Storage, StorageId, StorageResult};
use crate::RuntimeWrapper;
use std::str;

pub struct TTStorage {
    rt: RuntimeWrapper,
    client: Client,
}

const INDIVIDUALS_SPACE_ID: i32 = 512;
const TICKETS_SPACE_ID: i32 = 513;
const AZ_SPACE_ID: i32 = 514;

impl TTStorage {
    pub fn new(tt_uri: String, login: &str, pass: &str) -> TTStorage {
        TTStorage {
            rt: RuntimeWrapper::new(),
            client: ClientConfig::new(tt_uri, login, pass).set_timeout_time_ms(1000).set_reconnect_time_ms(10000).build(),
        }
    }
}

impl Storage for TTStorage {
    fn get_individual(&mut self, storage: StorageId, uri: &str, iraw: &mut Individual) -> StorageResult<()> {
        let space = if storage == StorageId::Tickets {
            TICKETS_SPACE_ID
        } else if storage == StorageId::Az {
            AZ_SPACE_ID
        } else {
            INDIVIDUALS_SPACE_ID
        };

        let key = (uri,);

        match self.rt.block_on(self.client.select(space, 0, &key, 0, 100, IteratorType::EQ)) {
            Ok(v) => {
                if !v.data.is_empty() {
                    iraw.set_raw(&v.data[5..]);
                    if parse_raw(iraw).is_ok() {
                        return StorageResult::Ok(());
                    } else {
                        return StorageResult::UnprocessableEntity;
                    }
                }
                StorageResult::NotFound
            },
            Err(_) => StorageResult::UnprocessableEntity,
        }
    }

    fn get_value(&mut self, storage: StorageId, key: &str) -> StorageResult<String> {
        let space = if storage == StorageId::Tickets {
            TICKETS_SPACE_ID
        } else if storage == StorageId::Az {
            AZ_SPACE_ID
        } else {
            INDIVIDUALS_SPACE_ID
        };

        let key_tuple = (key,);

        match self.rt.block_on(self.client.select(space, 0, &key_tuple, 0, 100, IteratorType::EQ)) {
            Ok(v) => {
                match std::str::from_utf8(&v.data[5..]) {
                    Ok(s) => StorageResult::Ok(s.to_string()),
                    Err(_) => StorageResult::Error("Invalid UTF-8 data".to_string()),
                }
            },
            Err(e) => {
                error!("TTStorage: fail get [{}] from tarantool, err={:?}", key, e);
                StorageResult::NotFound
            },
        }
    }

    fn get_raw_value(&mut self, storage: StorageId, key: &str) -> StorageResult<Vec<u8>> {
        let space = if storage == StorageId::Tickets {
            TICKETS_SPACE_ID
        } else if storage == StorageId::Az {
            AZ_SPACE_ID
        } else {
            INDIVIDUALS_SPACE_ID
        };

        let key_tuple = (key,);

        match self.rt.block_on(self.client.select(space, 0, &key_tuple, 0, 100, IteratorType::EQ)) {
            Ok(v) => StorageResult::Ok(v.data[5..].to_vec()),
            Err(e) => {
                error!("TTStorage: fail get raw [{}] from tarantool, err={:?}", key, e);
                StorageResult::NotFound
            },
        }
    }

    fn put_value(&mut self, storage: StorageId, key: &str, val: &str) -> StorageResult<()> {
        let space = if storage == StorageId::Tickets {
            TICKETS_SPACE_ID
        } else if storage == StorageId::Az {
            AZ_SPACE_ID
        } else {
            INDIVIDUALS_SPACE_ID
        };

        let tuple = (key, val);

        match self.rt.block_on(self.client.replace(space, &tuple)) {
            Ok(_) => StorageResult::Ok(()),
            Err(e) => {
                error!("tarantool: fail replace, db [{:?}], err = {:?}", storage, e);
                StorageResult::Error(format!("Failed to put value: {:?}", e))
            },
        }
    }

    fn put_raw_value(&mut self, storage: StorageId, _key: &str, val: Vec<u8>) -> StorageResult<()> {
        let space = if storage == StorageId::Tickets {
            TICKETS_SPACE_ID
        } else if storage == StorageId::Az {
            AZ_SPACE_ID
        } else {
            INDIVIDUALS_SPACE_ID
        };

        match self.rt.block_on(self.client.replace_raw(space, val)) {
            Ok(_) => StorageResult::Ok(()),
            Err(e) => {
                error!("tarantool: fail replace raw, db [{:?}], err = {:?}", storage, e);
                StorageResult::Error(format!("Failed to put raw value: {:?}", e))
            },
        }
    }

    fn remove_value(&mut self, storage: StorageId, key: &str) -> StorageResult<()> {
        let space = if storage == StorageId::Tickets {
            TICKETS_SPACE_ID
        } else if storage == StorageId::Az {
            AZ_SPACE_ID
        } else {
            INDIVIDUALS_SPACE_ID
        };

        let tuple = (key,);

        match self.rt.block_on(self.client.delete(space, &tuple)) {
            Ok(_) => StorageResult::Ok(()),
            Err(e) => {
                error!("tarantool: fail remove, db [{:?}], err = {:?}", storage, e);
                StorageResult::NotFound
            },
        }
    }

    fn count(&mut self, storage: StorageId) -> StorageResult<usize> {
        let space_name = if storage == StorageId::Tickets {
            "TICKETS"
        } else if storage == StorageId::Az {
            "AZ"
        } else {
            "INDIVIDUALS"
        };

        match self.rt.block_on(self.client.eval(format!("return box.space.{}:len()", space_name), &(0,))) {
            Ok(response) => {
                match response.decode::<(u64,)>() {
                    Ok(res) => StorageResult::Ok(res.0 as usize),
                    Err(e) => {
                        error!("failed to decode count response: db [{}], err = {:?}", space_name, e);
                        StorageResult::Error("Failed to decode count response".to_string())
                    },
                }
            },
            Err(e) => {
                error!("failed to count the number of records: db [{}], err = {:?}", space_name, e);
                StorageResult::Error(format!("Failed to count records: {:?}", e))
            },
        }
    }
}