Some rusqlite code. I'll hopefully go over this at some point. Or not.
use std::fs;
use std::collections::HashMap;
use std::time::SystemTime;
use rusqlite::Connection;
#[derive(Debug)]
enum FType {
File, Directory
}
#[derive(Debug)]
struct Entry {
ino: u64,
parent: u64,
id_col: String,
table: String,
name: String,
ftype: FType,
}
#[derive(Debug)]
struct FS {
db: String,
modified: SystemTime,
counter: u64,
directories: HashMap<u64, Entry>,
files: HashMap<u64, Entry>,
}
impl FS {
fn new(db: String) -> FS {
let metadata = fs::metadata(&db).unwrap();
let modified = metadata.modified().unwrap();
FS {
db,
modified,
counter: 0,
directories: HashMap::new(),
files: HashMap::new(),
}
}
fn get_directories(&mut self) {
let conn = Connection::open(self.db.clone()).unwrap();
let mut stmt = conn.prepare(
"select name from sqlite_master
where type = 'table'
and name not like 'sqlite_%' order by name;"
).unwrap();
self.counter = 1;
let rows = stmt.query_map([], |row| {
self.counter = self.counter + 1;
Ok(Entry {
ino: self.counter,
parent: 1,
id_col: "".to_string(),
table: "".to_string(),
name: row.get(0)?,
ftype: FType::Directory,
})
}).unwrap();
for row in rows {
if let Ok(r) = row {
self.directories.insert(r.ino, r);
}
}
}
fn get_all_files(&mut self) {
for (ino, entry) in &self.directories {
let table = &entry.name;
let conn = Connection::open(self.db.clone()).unwrap();
let query = format!("select * from \"{}\";",table);
let mut stmt = conn.prepare(&query).unwrap();
let mut id_col = "".to_string();
let rows = stmt.query_map([], |row| {
self.counter = self.counter + 1;
if id_col == "" {
id_col = row.as_ref().column_name(0).unwrap().to_string();
}
Ok(Entry {
ino: self.counter,
parent: ino.clone(),
name: row.get(0)?,
id_col: id_col.clone(),
table: table.clone(),
ftype: FType::File,
})
}).unwrap();
for row in rows {
match row {
Ok(r) => {
self.files.insert(r.ino, r);
},
Err(err) => {
println!("rusqlite error: {}", err);
}
}
}
}
}
fn fetch(&mut self) {
self.directories = HashMap::new();
self.files = HashMap::new();
self.get_directories();
self.get_all_files();
}
fn read(&self, table: &str, id_col: &str, id: &str) {
let query = format!("select * from {} where {} = \"{}\";", table, id_col, id);
let conn = Connection::open(self.db.clone()).unwrap();
let mut stmt = conn.prepare(&query).unwrap();
let column_count = stmt.column_count();
let mut rows = stmt.query(()).unwrap();
let row = rows.next().unwrap().unwrap();
let mut row_map = serde_json::map::Map::new();
for column_index in 0..column_count {
let key = row.as_ref().column_name(column_index).unwrap().to_string();
let str_val: String = row.get(column_index).unwrap();
let val = serde_json::Value::from(str_val);
row_map.insert(key, val);
}
row_map.remove(id_col);
println!("{}", serde_json::to_string(&row_map).unwrap());
}
fn write(&mut self, table: &str, id_col: &str, id: &str, text :&str) {
let mut columns = vec!();
let mut values = vec!();
let json: serde_json::Value = match serde_json::from_str(text) {
Ok(json) => json,
Err(err) => {
println!("Failed to write - {} on {}: {}", id, table,err);
return;
}
};
for (key, val) in json.as_object().unwrap() {
columns.push(key.to_string());
values.push(val.to_string());
}
let columns = columns.join(",");
let values = values.join(",");
let query = format!("REPLACE INTO {} ({},{}) VALUES (\"{}\",{});", table, id_col, columns, id, values);
let conn = Connection::open(self.db.clone()).unwrap();
let res = conn.execute(&query, ());
match res {
Ok(r) => {
self.fetch();
println!("Successfully written: {} on {}.", id, table);
},
Err(err) => {
println!("Failed to write - {} on {}: {}", id, table,err);
}
}
}
fn print_directories(&self) {
for (ino, entry) in &self.directories {
println!("{:?}: {:?}", ino, entry);
}
}
fn print_files(&self) {
for (ino, entry) in &self.files {
println!("{:?}: {:?}", ino, entry);
}
}
fn info(&self) {
let dirs = self.directories.keys().len();
let files = self.files.keys().len();
println!("Last modified {:?}", self.modified);
println!("{} directoriess found", dirs);
println!("{} files found", files);
println!("{} is the last inode", self.counter);
}
}
fn main() {
let db = "example.db".to_string();
let mut fs = FS::new(db);
fs.fetch();
fs.read("mytable", "title", "Post 1");
let text = r#"{"body":"Content for Post 1"}"#;
fs.write("mytable", "title", "Post 1", text);
let text = r#"{"body":"Content for Post 4. This is the end"}"#;
fs.write("mytable", "title", "Post 4", text);
println!("{}", text);
}