diff --git a/src/lib.rs b/src/lib.rs index a537e7e8d..a5c9b2180 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,13 @@ +mod pretty; + +use crate::pretty::PrettyPrint; + use partiql_eval as eval; use partiql_eval::env::basic::MapBindings; use partiql_logical as logical; use partiql_logical_planner::lower; use partiql_parser::{Parsed, Parser, ParserResult}; -use partiql_value::ion::parse_ion; +use partiql_value::Value; use wasm_bindgen::prelude::wasm_bindgen; @@ -36,11 +40,20 @@ pub fn eval_as_string(statement: &str, env: &str) -> String { let parsed = parse(statement); match parsed { Ok(p) => { - format!("{:?}", eval(&p, env)) - } - Err(e) => { - format!("{:?}", e) + let value = eval(&p, env); + match value { + Ok(v) => { + let mut pretty = String::new(); + let res = v.pretty(&mut pretty); + match res { + Ok(..) => pretty, + Err(e) => format!("{:?}", e) + } + } + Err(e) => format!("{:?}", e) + } } + Err(e) => format!("{:?}", e) } } @@ -48,11 +61,29 @@ pub(crate) fn parse(statement: &str) -> ParserResult { Parser::default().parse(statement) } -fn eval(p: &Parsed, env: &str) -> partiql_value::Value { +fn eval(p: &Parsed, env: &str) -> Result { let lowered = lower(p); - let env_as_value = parse_ion(env); - let bindings: MapBindings = MapBindings::from(env_as_value); - evaluate(lowered, bindings) + let env_as_value = get_bindings(env); + match env_as_value { + Ok(bindings) => Ok(evaluate(lowered, bindings)), + Err(e) => Err(format!("{:?}", e)) + } +} + + +fn get_bindings(env: &str) -> Result, String> { + let parsed = parse(env); + match parsed { + Ok(p) => { + let lowered = lower(&p); + let res = evaluate(lowered, MapBindings::default()); + match res { + Value::Tuple(t) => Ok(MapBindings::from(*t)), + _ => Err("Error in Env; Expected a struct containing the input environment".to_string()) + } + } + Err(e) => Err(format!("{:?}", e)) + } } /// Creates a logical plan for the given query and returns the json serialized string. @@ -73,8 +104,8 @@ pub fn explain_as_string(statement: &str) -> String { fn evaluate( logical: logical::LogicalPlan, - bindings: MapBindings, -) -> partiql_value::Value { + bindings: MapBindings, +) -> Value { let planner = eval::plan::EvaluatorPlanner; let mut plan = planner.compile(&logical); @@ -82,6 +113,6 @@ fn evaluate( if let Ok(out) = plan.execute_mut(bindings) { out.result } else { - partiql_value::Value::Missing + Value::Missing } } diff --git a/src/pretty.rs b/src/pretty.rs new file mode 100644 index 000000000..8c15779d2 --- /dev/null +++ b/src/pretty.rs @@ -0,0 +1,68 @@ +use partiql_value::Value; + +use std::fmt::Result; +use std::fmt::Write; + +pub trait PrettyPrint { + fn pretty(&self, f: &mut String) -> Result; +} + +impl PrettyPrint for Value { + fn pretty(&self, s: &mut String) -> Result { + pretty(self, s, 0) + } +} + +fn pretty(value: &Value, s: &mut String, cur_indent_size: usize) -> Result { + // For now, defining an indent to be two spaces. We could allow users to pass in an indent string + // for more control. + let indent = " ".repeat(cur_indent_size); + match value { + Value::List(l) => { + writeln!(s, "[")?; + let mut iter = l.iter().peekable(); + while let Some(v) = iter.next() { + if iter.peek().is_some() { + write!(s, "{indent} ")?; + pretty(v, s, cur_indent_size + 1)?; + writeln!(s, ",")?; + } else { + write!(s, "{indent} ")?; + pretty(v, s, cur_indent_size + 1)?; + } + } + write!(s, "\n{indent}]") + } + Value::Bag(b) => { + writeln!(s, "<<")?; + let mut iter = b.iter().peekable(); + while let Some(v) = iter.next() { + if iter.peek().is_some() { + write!(s, "{indent} ")?; + pretty(v, s, cur_indent_size + 1)?; + writeln!(s, ",")?; + } else { + write!(s, "{indent} ")?; + pretty(v, s, cur_indent_size + 1)?; + } + } + write!(s, "\n{indent}>>") + } + Value::Tuple(t) => { + writeln!(s, "{{")?; + let mut iter = t.pairs().peekable(); + while let Some((k, v)) = iter.next() { + if iter.peek().is_some() { + write!(s, "{indent} {k}: ")?; + pretty(v, s, cur_indent_size + 1)?; + writeln!(s, ",")?; + } else { + write!(s, "{indent} {k}: ")?; + pretty(v, s, cur_indent_size + 1)?; + } + } + write!(s, "\n{indent}}}") + } + _ => write!(s, "{value:?}"), + } +} \ No newline at end of file