mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
walletdb: WIP abstraction
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::{any::Any, path::PathBuf};
|
||||
|
||||
use async_std::sync::{Arc, Mutex};
|
||||
use log::{debug, info};
|
||||
@@ -55,6 +55,25 @@ impl From<u8> for QueryType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SqlType {
|
||||
Integer(i64),
|
||||
Text(String),
|
||||
Blob(Vec<u8>),
|
||||
Null,
|
||||
}
|
||||
|
||||
impl SqlType {
|
||||
pub fn inner<T: 'static>(&self) -> Option<&T> {
|
||||
match self {
|
||||
SqlType::Integer(v) => (v as &dyn Any).downcast_ref::<T>(),
|
||||
SqlType::Text(v) => (v as &dyn Any).downcast_ref::<T>(),
|
||||
SqlType::Blob(v) => (v as &dyn Any).downcast_ref::<T>(),
|
||||
SqlType::Null => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Structure representing base wallet operations.
|
||||
/// Additional operations can be implemented by trait extensions.
|
||||
pub struct WalletDb {
|
||||
@@ -86,6 +105,57 @@ impl WalletDb {
|
||||
let _ = self.conn.lock().await.execute(query, ())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn query_single(
|
||||
&self,
|
||||
table: &str,
|
||||
col_names: Vec<&str>,
|
||||
where_queries: Option<Vec<(&str, SqlType)>>,
|
||||
) -> Result<Vec<SqlType>> {
|
||||
let mut query = format!("SELECT {} FROM {}", col_names.join(", "), table);
|
||||
|
||||
if let Some(wq) = where_queries.as_ref() {
|
||||
let where_str: Vec<String> = wq.iter().map(|(k, _)| format!("{} = ?", k)).collect();
|
||||
query.push_str(&format!(" WHERE {}", where_str.join(" AND ")));
|
||||
}
|
||||
|
||||
let params: Vec<rusqlite::types::ToSqlOutput> = where_queries.map_or(Vec::new(), |wq| {
|
||||
wq.into_iter()
|
||||
.map(|(_, v)| match v {
|
||||
SqlType::Integer(i) => rusqlite::types::ToSqlOutput::from(i),
|
||||
SqlType::Text(t) => rusqlite::types::ToSqlOutput::from(t),
|
||||
SqlType::Blob(b) => rusqlite::types::ToSqlOutput::from(b),
|
||||
SqlType::Null => rusqlite::types::ToSqlOutput::from(rusqlite::types::Null),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
let wallet_conn = self.conn.lock().await;
|
||||
let mut stmt = wallet_conn.prepare(&query)?;
|
||||
let params_as_slice: Vec<&dyn rusqlite::ToSql> =
|
||||
params.iter().map(|x| x as &dyn rusqlite::ToSql).collect();
|
||||
let mut rows = stmt.query(params_as_slice.as_slice())?;
|
||||
|
||||
let row = match rows.next()? {
|
||||
Some(row_result) => row_result,
|
||||
None => return Ok(vec![]),
|
||||
};
|
||||
|
||||
let mut result = vec![];
|
||||
for (idx, _) in col_names.iter().enumerate() {
|
||||
let value: SqlType = match row.get_ref(idx)?.data_type() {
|
||||
rusqlite::types::Type::Integer => SqlType::Integer(row.get(idx)?),
|
||||
rusqlite::types::Type::Text => SqlType::Text(row.get(idx)?),
|
||||
rusqlite::types::Type::Blob => SqlType::Blob(row.get(idx)?),
|
||||
rusqlite::types::Type::Null => SqlType::Null,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
result.push(value);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -104,4 +174,36 @@ mod tests {
|
||||
stmt.finalize().unwrap();
|
||||
assert!(numba == 42);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_query_single() {
|
||||
let wallet = WalletDb::new(None, None).unwrap();
|
||||
wallet
|
||||
.exec_sql("CREATE TABLE mista ( why INTEGER, are TEXT, you INTEGER, gae BLOB );")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let why = 42;
|
||||
let are = "are".to_string();
|
||||
let you = 69;
|
||||
let gae = vec![42u8; 32];
|
||||
|
||||
let query_str =
|
||||
format!("INSERT INTO mista ( why, are, you, gae ) VALUES (?1, ?2, ?3, ?4);");
|
||||
|
||||
let wallet_conn = wallet.conn.lock().await;
|
||||
let mut stmt = wallet_conn.prepare(&query_str).unwrap();
|
||||
stmt.execute(rusqlite::params![why, are, you, gae]).unwrap();
|
||||
stmt.finalize().unwrap();
|
||||
drop(wallet_conn);
|
||||
|
||||
let ret =
|
||||
wallet.query_single("mista", vec!["why", "are", "you", "gae"], None).await.unwrap();
|
||||
assert!(ret.len() == 4);
|
||||
|
||||
assert!(ret[0].inner::<i64>().unwrap() == &why);
|
||||
assert!(ret[1].inner::<String>().unwrap() == &are);
|
||||
assert!(ret[2].inner::<i64>().unwrap() == &you);
|
||||
assert!(ret[3].inner::<Vec<u8>>().unwrap() == &gae);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user