use std::io::{self, Write};
use crate::error::{MongoshError, Result};
use crate::parser::{AdminCommand, QueryCommand};
pub fn is_dangerous_query(cmd: &QueryCommand) -> bool {
matches!(
cmd,
QueryCommand::DeleteOne { .. }
| QueryCommand::DeleteMany { .. }
| QueryCommand::UpdateOne { .. }
| QueryCommand::UpdateMany { .. }
| QueryCommand::ReplaceOne { .. }
| QueryCommand::FindOneAndDelete { .. }
| QueryCommand::FindOneAndUpdate { .. }
| QueryCommand::FindOneAndReplace { .. }
| QueryCommand::FindAndModify { .. }
)
}
pub fn is_dangerous_admin(cmd: &AdminCommand) -> bool {
matches!(
cmd,
AdminCommand::CreateIndex { .. }
| AdminCommand::CreateIndexes { .. }
| AdminCommand::DropIndex { .. }
| AdminCommand::DropIndexes { .. }
| AdminCommand::DropCollection(..)
| AdminCommand::RenameCollection { .. }
)
}
pub fn prompt_confirmation() -> Result<bool> {
println!("⚠️ Dangerous operation! Continue? (yes/no): ");
io::stdout()
.flush()
.map_err(|e| MongoshError::Generic(format!("Failed to flush stdout: {}", e)))?;
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.map_err(|e| MongoshError::Generic(format!("Failed to read input: {}", e)))?;
let input = input.trim().to_lowercase();
Ok(matches!(input.as_str(), "yes" | "y"))
}
pub fn confirm_query_operation(cmd: &QueryCommand) -> Result<bool> {
if !is_dangerous_query(cmd) {
return Ok(true);
}
prompt_confirmation()
}
pub fn confirm_admin_operation(cmd: &AdminCommand) -> Result<bool> {
if !is_dangerous_admin(cmd) {
return Ok(true);
}
prompt_confirmation()
}
#[cfg(test)]
mod tests {
use super::*;
use mongodb::bson::doc;
#[test]
fn test_is_dangerous_query() {
let delete_one = QueryCommand::DeleteOne {
collection: "test".to_string(),
filter: doc! {},
};
assert!(is_dangerous_query(&delete_one));
let find = QueryCommand::Find {
collection: "test".to_string(),
filter: doc! {},
options: Default::default(),
};
assert!(!is_dangerous_query(&find));
}
#[test]
fn test_is_dangerous_admin() {
let create_index = AdminCommand::CreateIndex {
collection: "users".to_string(),
keys: doc! { "email": 1 },
options: None,
};
assert!(is_dangerous_admin(&create_index));
let show_dbs = AdminCommand::ShowDatabases;
assert!(!is_dangerous_admin(&show_dbs));
}
}