sql.rs
1 use std::ops::Deref; 2 use std::str::FromStr; 3 4 use sqlite as sql; 5 use sqlite::Value; 6 7 use crate::identity::Id; 8 use crate::node; 9 use crate::node::Address; 10 11 /// Run an SQL query inside a transaction. 12 /// Commits the transaction on success, and rolls back on error. 13 pub fn transaction<T>( 14 db: &sql::Connection, 15 query: impl FnOnce(&sql::Connection) -> Result<T, sql::Error>, 16 ) -> Result<T, sql::Error> { 17 db.execute("BEGIN")?; 18 19 match query(db) { 20 Ok(result) => { 21 db.execute("COMMIT")?; 22 Ok(result) 23 } 24 Err(err) => { 25 db.execute("ROLLBACK")?; 26 Err(err) 27 } 28 } 29 } 30 31 impl TryFrom<&Value> for Id { 32 type Error = sql::Error; 33 34 fn try_from(value: &Value) -> Result<Self, Self::Error> { 35 match value { 36 Value::String(id) => Id::from_urn(id).map_err(|e| sql::Error { 37 code: None, 38 message: Some(e.to_string()), 39 }), 40 _ => Err(sql::Error { 41 code: None, 42 message: Some("sql: invalid type for id".to_owned()), 43 }), 44 } 45 } 46 } 47 48 impl sqlite::BindableWithIndex for &Id { 49 fn bind<I: sql::ParameterIndex>(self, stmt: &mut sql::Statement<'_>, i: I) -> sql::Result<()> { 50 self.urn().as_str().bind(stmt, i) 51 } 52 } 53 54 impl sql::BindableWithIndex for node::Features { 55 fn bind<I: sql::ParameterIndex>(self, stmt: &mut sql::Statement<'_>, i: I) -> sql::Result<()> { 56 (*self.deref() as i64).bind(stmt, i) 57 } 58 } 59 60 impl TryFrom<&Value> for node::Features { 61 type Error = sql::Error; 62 63 fn try_from(value: &Value) -> Result<Self, Self::Error> { 64 match value { 65 Value::Integer(bits) => Ok(node::Features::from(*bits as u64)), 66 _ => Err(sql::Error { 67 code: None, 68 message: Some("sql: invalid type for node features".to_owned()), 69 }), 70 } 71 } 72 } 73 74 impl TryFrom<&sql::Value> for Address { 75 type Error = sql::Error; 76 77 fn try_from(value: &sql::Value) -> Result<Self, Self::Error> { 78 match value { 79 sql::Value::String(s) => Address::from_str(s.as_str()).map_err(|e| sql::Error { 80 code: None, 81 message: Some(e.to_string()), 82 }), 83 _ => Err(sql::Error { 84 code: None, 85 message: Some("sql: invalid type for address".to_owned()), 86 }), 87 } 88 } 89 } 90 91 impl sql::BindableWithIndex for &Address { 92 fn bind<I: sql::ParameterIndex>(self, stmt: &mut sql::Statement<'_>, i: I) -> sql::Result<()> { 93 self.to_string().bind(stmt, i) 94 } 95 }