diff --git a/samples/q1.json b/samples/q1.json index 99f3591..b65f900 100644 --- a/samples/q1.json +++ b/samples/q1.json @@ -2,9 +2,9 @@ "hr": { "employees": [ { + "name": "Bob Smith", "id": 3, - "title": null, - "name": "Bob Smith" + "title": null }, { "title": "Dev Mgr", @@ -12,9 +12,9 @@ "name": "Susan Smith" }, { - "id": 6, + "title": "Software Eng 2", "name": "Jane Smith", - "title": "Software Eng 2" + "id": 6 } ] } diff --git a/samples/q2.json b/samples/q2.json new file mode 100644 index 0000000..3a8b14c --- /dev/null +++ b/samples/q2.json @@ -0,0 +1,38 @@ +{ + "hr": { + "employeesNest": [ + { + "title": null, + "id": 3, + "projects": [ + { + "name": "AWS Redshift Spectrum querying" + }, + { + "name": "AWS Redshift security" + }, + { + "name": "AWS Aurora security" + } + ], + "name": "Bob Smith" + }, + { + "title": "Dev Mgr", + "name": "Susan Smith", + "id": 4, + "projects": [] + }, + { + "id": 6, + "title": "Software Eng 2", + "projects": [ + { + "name": "AWS Redshift security" + } + ], + "name": "Jane Smith" + } + ] + } +} diff --git a/src/bin/main.rs b/src/bin/main.rs index 98b5692..bf24c8f 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -4,10 +4,10 @@ use std::path::{Path, PathBuf}; use regex::Regex; use structopt::StructOpt; +use partiql::dsql_parser as sql_parser; use partiql::models::JsonValue; use partiql::pqlir_parser as parser; -use partiql::sql::Sql; -use partiql::sql_parser; +use partiql::sql::run; fn read_from_stdin() -> anyhow::Result { let mut buf = String::new(); @@ -80,38 +80,20 @@ fn main() -> anyhow::Result<()> { let sql = sql_parser::sql(&query)?; - if let Some(output) = run(sql, data) { - let s = match to.as_str() { - "json" => { - let s = serde_json::to_string(&output).unwrap(); - s - } - _ => { - let s = serde_partiql::to_string(&output).unwrap(); - s - } - }; - println!("{}", s); - } else { - eprintln!("failed"); - } + let output = run(sql, data); + let s = match to.as_str() { + "json" => { + let s = serde_json::to_string(&output).unwrap(); + s + } + _ => { + let s = serde_partiql::to_string(&output).unwrap(); + s + } + }; + println!("{}", s); } }; Ok(()) } - -fn run(sql: Sql, data: JsonValue) -> Option { - let from_clause = sql.from_clause.first().unwrap(); - let full_path = format!("{}.{}", from_clause.source, from_clause.path); - let from_path = full_path.split(".").collect::>(); - - let rows = data.get_path(&from_path).unwrap(); - - let field_list = sql.select_clause; - let data = rows.select_map(&field_list).unwrap(); - - let cond = sql.where_clause.unwrap(); - let data = data.filter_map(cond).unwrap(); - Some(data) -} diff --git a/src/lib/sql/eval.rs b/src/lib/sql/eval.rs new file mode 100644 index 0000000..c07e9b7 --- /dev/null +++ b/src/lib/sql/eval.rs @@ -0,0 +1,46 @@ +use std::collections::HashMap; + +use itertools::Itertools; + +use crate::dsql_parser; +use crate::models::JsonValue; +use crate::pqlir_parser; +use crate::sql::to_list; +use crate::sql::Bingings; +use crate::sql::DField; +use crate::sql::DSql as Sql; +use crate::sql::DWhereCond; +use crate::sql::Dpath; +use crate::sql_parser; + +pub fn run(sql: Sql, data: JsonValue) -> JsonValue { + let fields = sql + .select_clause + .iter() + .chain(sql.from_clause.iter()) + .map(|e| e.to_owned()) + .collect::>(); + let bindings = Bingings::from(fields.as_slice()); + + let select_fields = sql + .select_clause + .iter() + .map(|field| field.to_owned().full(&bindings)) + .collect::>(); + let bindings_for_select = Bingings::from(select_fields.as_slice()); + + let value = data.select_by_fields(&select_fields).unwrap(); + let list = to_list(value); + + let filtered_list = list + .iter() + .filter_map(|value| match &sql.where_clause { + Some(cond) if cond.eval(&value.to_owned(), &bindings, &bindings_for_select) => { + Some(value.to_owned()) + } + _ => None, + }) + .collect::>(); + + JsonValue::Array(filtered_list) +} diff --git a/src/lib/sql/mod.rs b/src/lib/sql/mod.rs index e4bf6e2..4e444c8 100644 --- a/src/lib/sql/mod.rs +++ b/src/lib/sql/mod.rs @@ -3,8 +3,10 @@ use std::collections::HashMap; use crate::models::JsonValue; mod bingings; +mod eval; mod utils; pub use bingings::Bingings; +pub use eval::run; pub use utils::to_list; #[derive(Debug, Clone, PartialEq)] diff --git a/tests/sql.rs b/tests/sql.rs index a72b529..092823f 100644 --- a/tests/sql.rs +++ b/tests/sql.rs @@ -5,6 +5,7 @@ use itertools::Itertools; use partiql::dsql_parser; use partiql::models::JsonValue; use partiql::pqlir_parser; +use partiql::sql::run; use partiql::sql::to_list; use partiql::sql::Bingings; use partiql::sql::DField; @@ -13,40 +14,6 @@ use partiql::sql::DWhereCond; use partiql::sql::Dpath; use partiql::sql_parser; -fn run(sql: Sql, data: JsonValue) -> JsonValue { - let fields = sql - .select_clause - .iter() - .chain(sql.from_clause.iter()) - .map(|e| e.to_owned()) - .collect::>(); - let bindings = Bingings::from(fields.as_slice()); - - let select_fields = sql - .select_clause - .iter() - .map(|field| field.to_owned().full(&bindings)) - .collect::>(); - let bindings_for_select = Bingings::from(select_fields.as_slice()); - - let value = data.select_by_fields(&select_fields).unwrap(); - let list = to_list(value); - dbg!(&list); - dbg!(&sql); - - let filtered_list = list - .iter() - .filter_map(|value| match &sql.where_clause { - Some(cond) if cond.eval(&value.to_owned(), &bindings, &bindings_for_select) => { - Some(value.to_owned()) - } - _ => None, - }) - .collect::>(); - - JsonValue::Array(filtered_list) -} - #[test] fn q1() -> anyhow::Result<()> { let sql = {