1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
extern crate csv;
extern crate rustc_serialize;
extern crate walkdir;

use std::path::PathBuf;
use std::fs;
use std::fs::OpenOptions;
use std::io::Write;

pub struct CSVStore {
    datadir: PathBuf,
}

impl CSVStore {
    pub fn new(datadir: PathBuf) -> CSVStore {
        CSVStore { datadir: datadir }
    }

    pub fn write<V: rustc_serialize::Encodable>(&self, key: Vec<&str>, value: V) {
        let key_path = self.get_path_from_key(key);

        fs::create_dir_all(key_path.parent()
                .expect("can not get parent for key path while trying to write data"))
            .expect("can not create folder for writing data");


        let mut file = match OpenOptions::new().append(true).open(&key_path) {
            Ok(file) => file,
            Err(_) => {
                OpenOptions::new()
                    .append(true)
                    .create(true)
                    .open(&key_path)
                    .expect("can not open key file for writing")
            }
        };

        let mut wtr = csv::Writer::from_memory();
        wtr.encode(value).expect("can not serialize value into csv");
        file.write_all(wtr.as_bytes()).expect("can not write csv data to file");
    }

    pub fn get<V: rustc_serialize::Decodable>(&self, key: Vec<&str>) -> Vec<V> {
        let key_path = self.get_path_from_key(key);
        let mut rdr =
            csv::Reader::from_file(key_path).expect("read csv data from file").has_headers(false);

        let mut out = Vec::new();
        for record in rdr.decode() {
            let entry: V = record.unwrap();
            out.push(entry);
        }

        out
    }

    pub fn destroy(&self) {
        fs::remove_dir_all(&self.datadir).expect("can not remove data store folder")
    }

    pub fn get_path_from_key(&self, key: Vec<&str>) -> PathBuf {
        let mut key_path = self.datadir.clone();
        key_path.push(format!("{}.csv", key.join("/")));

        key_path
    }
}

#[test]
fn test_write_read() {
    let store = CSVStore::new(PathBuf::from("/tmp/csvstore_test"));
    let key = vec!["test"];
    let data = "test";

    store.write(key.clone(), data);

    let read_data: Vec<String> = store.get(key);

    assert_eq!(data, read_data[0]);

    store.destroy();
}