use mongodb::bson::Document;
use crate::error::{ParseError, Result};
use crate::parser::command::{AggregateOptions, FindAndModifyOptions, UpdateOptions};
use crate::parser::mongo_ast::*;
use crate::parser::mongo_converter::ExpressionConverter;
pub struct ArgParser;
impl ArgParser {
pub fn extract_db_call_target(callee: &Expr) -> Result<(String, String)> {
if let Expr::Member(member) = callee {
let operation = match &member.property {
MemberProperty::Ident(name) => name.clone(),
MemberProperty::Computed(expr) => {
if let Expr::String(s) = expr {
s.clone()
} else {
return Err(ParseError::InvalidCommand(
"Computed member expression must use string literal".to_string(),
)
.into());
}
}
};
if let Expr::Member(inner_member) = member.object.as_ref() {
let collection = match &inner_member.property {
MemberProperty::Ident(name) => name.clone(),
MemberProperty::Computed(expr) => {
if let Expr::String(s) = expr {
s.clone()
} else {
return Err(ParseError::InvalidCommand(
"Collection name must be a string".to_string(),
)
.into());
}
}
};
if let Expr::Ident(id) = inner_member.object.as_ref() {
if id == "db" {
return Ok((collection, operation));
}
}
}
}
Err(
ParseError::InvalidCommand("Expected db.collection.operation() syntax".to_string())
.into(),
)
}
pub fn get_doc_arg(args: &[Expr], index: usize) -> Result<Document> {
if let Some(expr) = args.get(index) {
let bson = ExpressionConverter::expr_to_bson(expr)?;
if let mongodb::bson::Bson::Document(doc) = bson {
Ok(doc)
} else {
Err(
ParseError::InvalidQuery(format!("Argument {} must be an object", index))
.into(),
)
}
} else {
Ok(Document::new())
}
}
pub fn get_doc_array_arg(args: &[Expr], index: usize) -> Result<Vec<Document>> {
if let Some(expr) = args.get(index) {
let bson = ExpressionConverter::expr_to_bson(expr)?;
if let mongodb::bson::Bson::Array(arr) = bson {
let mut docs = Vec::new();
for item in arr {
if let mongodb::bson::Bson::Document(doc) = item {
docs.push(doc);
} else {
return Err(ParseError::InvalidQuery(
"Array must contain only documents".to_string(),
)
.into());
}
}
Ok(docs)
} else {
Err(ParseError::InvalidQuery(format!("Argument {} must be an array", index)).into())
}
} else {
Ok(Vec::new())
}
}
pub fn get_string_arg(args: &[Expr], index: usize) -> Result<String> {
if let Some(expr) = args.get(index) {
if let Expr::String(s) = expr {
Ok(s.clone())
} else {
Err(ParseError::InvalidQuery(format!("Argument {} must be a string", index)).into())
}
} else {
Err(ParseError::InvalidQuery(format!("Missing argument at index {}", index)).into())
}
}
pub fn get_number_arg(args: &[Expr], index: usize) -> Result<i64> {
if let Some(expr) = args.get(index) {
if let Expr::Number(n) = expr {
Ok(*n as i64)
} else {
Err(ParseError::InvalidQuery(format!("Argument {} must be a number", index)).into())
}
} else {
Err(ParseError::InvalidQuery(format!("Missing argument at index {}", index)).into())
}
}
pub fn get_update_options(args: &[Expr], index: usize) -> Result<UpdateOptions> {
if let Some(expr) = args.get(index) {
super::options::OptionsParser::parse_update_options(expr)
} else {
Ok(UpdateOptions::default())
}
}
pub fn get_find_and_modify_options(args: &[Expr], index: usize) -> Result<FindAndModifyOptions> {
if let Some(expr) = args.get(index) {
super::options::OptionsParser::parse_find_and_modify_options(expr)
} else {
Ok(FindAndModifyOptions::default())
}
}
pub fn get_aggregate_options(args: &[Expr], index: usize) -> Result<AggregateOptions> {
if let Some(expr) = args.get(index) {
super::options::OptionsParser::parse_aggregate_options(expr)
} else {
Ok(AggregateOptions::default())
}
}
pub fn get_projection(args: &[Expr], index: usize) -> Result<Option<Document>> {
if let Some(_expr) = args.get(index) {
Ok(Some(Self::get_doc_arg(args, index)?))
} else {
Ok(None)
}
}
}