use rustledger_core::Directive;
use rustledger_query::{Executor, parse as parse_query};
use crate::convert::{directive_to_json, value_datatype, value_to_json};
use crate::helpers::load_source;
use crate::types::{BatchOutput, ColumnInfo, DirectiveJson, Error, LoadOutput, QueryOutput};
use crate::{API_VERSION, output_json};
pub fn execute_query(directives: &[Directive], query_str: &str) -> QueryOutput {
let query = match parse_query(query_str) {
Ok(q) => q,
Err(e) => {
return QueryOutput {
api_version: API_VERSION,
columns: vec![],
rows: vec![],
errors: vec![Error::new(e.to_string())],
};
}
};
let mut executor = Executor::new(directives);
match executor.execute(&query) {
Ok(result) => {
let columns: Vec<ColumnInfo> = if result.rows.is_empty() {
result
.columns
.iter()
.map(|name| ColumnInfo {
name: name.clone(),
datatype: "str".to_string(), })
.collect()
} else {
result
.columns
.iter()
.zip(result.rows[0].iter())
.map(|(name, value)| ColumnInfo {
name: name.clone(),
datatype: value_datatype(value).to_string(),
})
.collect()
};
let rows: Vec<Vec<_>> = result
.rows
.iter()
.map(|row| row.iter().map(value_to_json).collect())
.collect();
QueryOutput {
api_version: API_VERSION,
columns,
rows,
errors: vec![],
}
}
Err(e) => QueryOutput {
api_version: API_VERSION,
columns: vec![],
rows: vec![],
errors: vec![Error::new(format!("Query error: {e}"))],
},
}
}
pub fn cmd_query(source: &str, query_str: &str) -> i32 {
let load = load_source(source);
if !load.errors.is_empty() {
let output = QueryOutput {
api_version: API_VERSION,
columns: vec![],
rows: vec![],
errors: load.errors,
};
return output_json(&output);
}
let output = execute_query(&load.directives, query_str);
output_json(&output)
}
pub fn cmd_batch(source: &str, filename: &str, queries: &[String]) -> i32 {
let load = load_source(source);
let entries: Vec<DirectiveJson> = load
.directives
.iter()
.zip(load.directive_lines.iter())
.map(|(d, &line)| directive_to_json(d, line, filename))
.collect();
let load_output = LoadOutput {
api_version: API_VERSION,
entries,
errors: load.errors.clone(),
options: load.options,
plugins: load.plugins,
includes: load.includes,
};
let query_outputs: Vec<QueryOutput> = if load.errors.is_empty() {
queries
.iter()
.map(|q| execute_query(&load.directives, q))
.collect()
} else {
queries
.iter()
.map(|_| QueryOutput {
api_version: API_VERSION,
columns: vec![],
rows: vec![],
errors: vec![Error::new("Cannot execute query: parse errors exist")],
})
.collect()
};
let output = BatchOutput {
api_version: API_VERSION,
load: load_output,
queries: query_outputs,
};
output_json(&output)
}