kv.rs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. use crate::kv::schema::{kv_table, kv_table::dsl, KV_SQL};
  2. use crate::sqlite::{DBConnection, Database, PoolConfig};
  3. use ::diesel::{query_dsl::*, ExpressionMethods};
  4. use diesel::{Connection, SqliteConnection};
  5. use lazy_static::lazy_static;
  6. use std::{path::Path, sync::RwLock};
  7. macro_rules! impl_get_func {
  8. (
  9. $func_name:ident,
  10. $get_method:ident=>$target:ident
  11. ) => {
  12. #[allow(dead_code)]
  13. pub fn $func_name(k: &str) -> Option<$target> {
  14. match KV::get(k) {
  15. Ok(item) => item.$get_method,
  16. Err(_) => None,
  17. }
  18. }
  19. };
  20. }
  21. macro_rules! impl_set_func {
  22. ($func_name:ident,$set_method:ident,$key_type:ident) => {
  23. #[allow(dead_code)]
  24. pub fn $func_name(key: &str, value: $key_type) {
  25. let mut item = KeyValue::new(key);
  26. item.$set_method = Some(value);
  27. match KV::set(item) {
  28. Ok(_) => {},
  29. Err(e) => {
  30. tracing::error!("{:?}", e)
  31. },
  32. };
  33. }
  34. };
  35. }
  36. const DB_NAME: &str = "kv.db";
  37. lazy_static! {
  38. static ref KV_HOLDER: RwLock<KV> = RwLock::new(KV::new());
  39. }
  40. pub struct KV {
  41. database: Option<Database>,
  42. }
  43. impl KV {
  44. fn new() -> Self {
  45. KV { database: None }
  46. }
  47. fn set(value: KeyValue) -> Result<(), String> {
  48. // tracing::trace!("[KV]: set value: {:?}", value);
  49. let _ = diesel::replace_into(kv_table::table)
  50. .values(&value)
  51. .execute(&*(get_connection()?))
  52. .map_err(|e| format!("KV set error: {:?}", e))?;
  53. Ok(())
  54. }
  55. fn get(key: &str) -> Result<KeyValue, String> {
  56. let conn = get_connection()?;
  57. let value = dsl::kv_table
  58. .filter(kv_table::key.eq(key))
  59. .first::<KeyValue>(&*conn)
  60. .map_err(|e| format!("KV get error: {:?}", e))?;
  61. Ok(value)
  62. }
  63. #[allow(dead_code)]
  64. pub fn remove(key: &str) -> Result<(), String> {
  65. // tracing::debug!("remove key: {}", key);
  66. let conn = get_connection()?;
  67. let sql = dsl::kv_table.filter(kv_table::key.eq(key));
  68. let _ = diesel::delete(sql)
  69. .execute(&*conn)
  70. .map_err(|e| format!("KV remove error: {:?}", e))?;
  71. Ok(())
  72. }
  73. #[tracing::instrument(level = "trace", err)]
  74. pub fn init(root: &str) -> Result<(), String> {
  75. if !Path::new(root).exists() {
  76. return Err(format!("Init KVStore failed. {} not exists", root));
  77. }
  78. let pool_config = PoolConfig::default();
  79. let database = Database::new(root, DB_NAME, pool_config).unwrap();
  80. let conn = database.get_connection().unwrap();
  81. SqliteConnection::execute(&*conn, KV_SQL).unwrap();
  82. let mut store = KV_HOLDER
  83. .write()
  84. .map_err(|e| format!("KVStore write failed: {:?}", e))?;
  85. tracing::trace!("Init kv with path: {}", root);
  86. store.database = Some(database);
  87. Ok(())
  88. }
  89. pub fn get_bool(key: &str) -> bool {
  90. match KV::get(key) {
  91. Ok(item) => item.bool_value.unwrap_or(false),
  92. Err(_) => false,
  93. }
  94. }
  95. impl_set_func!(set_str, str_value, String);
  96. impl_set_func!(set_bool, bool_value, bool);
  97. impl_set_func!(set_int, int_value, i64);
  98. impl_set_func!(set_float, float_value, f64);
  99. impl_get_func!(get_str,str_value=>String);
  100. impl_get_func!(get_int,int_value=>i64);
  101. impl_get_func!(get_float,float_value=>f64);
  102. }
  103. fn get_connection() -> Result<DBConnection, String> {
  104. match KV_HOLDER.read() {
  105. Ok(store) => {
  106. let conn = store
  107. .database
  108. .as_ref()
  109. .expect("KVStore is not init")
  110. .get_connection()
  111. .map_err(|e| format!("KVStore error: {:?}", e))?;
  112. Ok(conn)
  113. },
  114. Err(e) => {
  115. let msg = format!("KVStore get connection failed: {:?}", e);
  116. tracing::error!("{:?}", msg);
  117. Err(msg)
  118. },
  119. }
  120. }
  121. #[derive(Clone, Debug, Default, Queryable, Identifiable, Insertable, AsChangeset)]
  122. #[table_name = "kv_table"]
  123. #[primary_key(key)]
  124. pub struct KeyValue {
  125. pub key: String,
  126. pub str_value: Option<String>,
  127. pub int_value: Option<i64>,
  128. pub float_value: Option<f64>,
  129. pub bool_value: Option<bool>,
  130. }
  131. impl KeyValue {
  132. pub fn new(key: &str) -> Self {
  133. KeyValue {
  134. key: key.to_string(),
  135. ..Default::default()
  136. }
  137. }
  138. }
  139. #[cfg(test)]
  140. mod tests {
  141. use crate::kv::KV;
  142. #[test]
  143. fn kv_store_test() {
  144. let dir = "./temp/";
  145. if !std::path::Path::new(dir).exists() {
  146. std::fs::create_dir_all(dir).unwrap();
  147. }
  148. KV::init(dir).unwrap();
  149. KV::set_str("1", "hello".to_string());
  150. assert_eq!(KV::get_str("1").unwrap(), "hello");
  151. assert_eq!(KV::get_str("2"), None);
  152. KV::set_bool("1", true);
  153. assert!(KV::get_bool("1"));
  154. assert!(!KV::get_bool("2"));
  155. }
  156. }