Add sled migration utility.
This commit is contained in:
parent
6b6be06c89
commit
5630b4ed20
|
@ -0,0 +1,37 @@
|
|||
use tenebrous_dicebot::db::sqlite::{Database as SqliteDatabase, Variables};
|
||||
use tenebrous_dicebot::db::Database;
|
||||
use tenebrous_dicebot::error::BotError;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), BotError> {
|
||||
let sled_path = std::env::args()
|
||||
.skip(1)
|
||||
.next()
|
||||
.expect("Need a path to a Sled database as an arument.");
|
||||
|
||||
let sqlite_path = std::env::args()
|
||||
.skip(2)
|
||||
.next()
|
||||
.expect("Need a path to an sqlite database as an arument.");
|
||||
|
||||
let db = Database::new(&sled_path)?;
|
||||
|
||||
let all_variables = db.variables.get_all_variables()?;
|
||||
|
||||
let sql_db = SqliteDatabase::new(&sqlite_path).await?;
|
||||
|
||||
for var in all_variables {
|
||||
if let ((username, room_id, variable_name), value) = var {
|
||||
println!(
|
||||
"Migrating {}::{}::{} = {} to sql",
|
||||
username, room_id, variable_name, value
|
||||
);
|
||||
|
||||
sql_db
|
||||
.set_user_variable(&username, &room_id, &variable_name, value)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -19,7 +19,7 @@ pub mod variables;
|
|||
#[derive(Clone)]
|
||||
pub struct Database {
|
||||
db: Db,
|
||||
pub(crate) variables: Variables,
|
||||
pub variables: Variables,
|
||||
pub(crate) migrations: Migrations,
|
||||
pub(crate) rooms: Rooms,
|
||||
pub(crate) state: DbState,
|
||||
|
|
|
@ -26,6 +26,9 @@ pub enum DataError {
|
|||
#[error("expected i32, but i32 schema was violated")]
|
||||
I32SchemaViolation,
|
||||
|
||||
#[error("parse error")]
|
||||
ParseError(#[from] std::num::ParseIntError),
|
||||
|
||||
#[error("unexpected or corruptd data bytes")]
|
||||
InvalidValue,
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ pub(crate) trait Rooms {
|
|||
// TODO move this up to the top once we delete sled. Traits will be the
|
||||
// main API, then we can have different impls for different DBs.
|
||||
#[async_trait]
|
||||
pub(crate) trait Variables {
|
||||
pub trait Variables {
|
||||
async fn get_user_variables(
|
||||
&self,
|
||||
user: &str,
|
||||
|
|
|
@ -10,6 +10,8 @@ use std::str;
|
|||
use zerocopy::byteorder::I32;
|
||||
use zerocopy::AsBytes;
|
||||
|
||||
use super::errors;
|
||||
|
||||
pub(super) mod migrations;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -67,6 +69,9 @@ fn alter_room_variable_count(
|
|||
Ok(new_count)
|
||||
}
|
||||
|
||||
/// Room ID, Username, Variable Name
|
||||
pub type AllVariablesKey = (String, String, String);
|
||||
|
||||
impl Variables {
|
||||
pub(in crate::db) fn new(db: &sled::Db) -> Result<Variables, sled::Error> {
|
||||
Ok(Variables {
|
||||
|
@ -75,6 +80,40 @@ impl Variables {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn get_all_variables(&self) -> Result<HashMap<AllVariablesKey, i32>, DataError> {
|
||||
use std::convert::TryFrom;
|
||||
let variables: Result<Vec<(AllVariablesKey, i32)>, DataError> = self
|
||||
.room_user_variables
|
||||
.scan_prefix("")
|
||||
.map(|entry| match entry {
|
||||
Ok((key, raw_value)) => {
|
||||
let keys: Vec<_> = key
|
||||
.split(|&b| b == 0xfe || b == 0xff)
|
||||
.map(|b| str::from_utf8(b))
|
||||
.collect();
|
||||
|
||||
if let &[Ok(room_id), Ok(username), Ok(variable_name), ..] = keys.as_slice() {
|
||||
Ok((
|
||||
(
|
||||
room_id.to_owned(),
|
||||
username.to_owned(),
|
||||
variable_name.to_owned(),
|
||||
),
|
||||
convert_i32(&raw_value)?,
|
||||
))
|
||||
} else {
|
||||
Err(errors::DataError::InvalidValue)
|
||||
}
|
||||
}
|
||||
Err(e) => Err(e.into()),
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Convert tuples to hash map with collect(), inferred via
|
||||
// return type.
|
||||
variables.map(|entries| entries.into_iter().collect())
|
||||
}
|
||||
|
||||
pub fn get_user_variables(
|
||||
&self,
|
||||
key: &UserAndRoom<'_>,
|
||||
|
|
Loading…
Reference in New Issue