diff --git a/crates/query-engine/execution/src/query.rs b/crates/query-engine/execution/src/query.rs index 696ed12e..a1dee2b1 100644 --- a/crates/query-engine/execution/src/query.rs +++ b/crates/query-engine/execution/src/query.rs @@ -6,7 +6,7 @@ use bytes::{BufMut, Bytes, BytesMut}; use gcp_bigquery_client::model::query_request::QueryRequest; use gcp_bigquery_client::model::{query_parameter, query_parameter_type, query_parameter_value}; use query_engine_sql::sql::string::Param; -use serde_json; +use serde_json::{self, to_string, Value}; use sqlformat; use sqlx; use sqlx::Row; @@ -88,10 +88,28 @@ pub async fn execute( .unwrap(); while rs.next_row() { + dbg!("result set of row: ", &rs); let this_row = rs.get_string(0).unwrap().unwrap(); // we should only have one row called 'universe' + dbg!("this row: ", &this_row); + let foo: Value = serde_json::from_str(&this_row).unwrap(); + dbg!("foo: ", &foo); + let bar = Value::Array(vec![foo]); + dbg!("bar: ", &bar); + let baz = to_string(&bar).unwrap(); + dbg!("baz: ", &baz); + // let bar: u8 = this_row.as_bytes()[0]; + // dbg!("bar: ", &bar); + // let foo = vec![this_row]; // let json_value = serde_json::from_str(&this_row).unwrap(); - let b: Bytes = Bytes::from(this_row); + let b: Bytes = Bytes::from(baz); + // let b: Bytes = Bytes::from(to_string(&foo).unwrap()); + dbg!("b: ", &b); buffer.put(b); + // let this_row = rs.get_json_value(0).unwrap(); // we should only have one row called 'universe' + // // let json_value = serde_json::from_str(&this_row).unwrap(); + // let json_string = serde_json::to_string(&this_row).unwrap(); + // let b: Bytes = Bytes::from(json_string); + // buffer.put(b); // inner_rows.push(json_value); } // let b: Bytes = Bytes::from(serde_json::to_string(&inner_rows).unwrap()); diff --git a/crates/query-engine/sql/src/sql/ast.rs b/crates/query-engine/sql/src/sql/ast.rs index dd5ff0ab..784158dc 100644 --- a/crates/query-engine/sql/src/sql/ast.rs +++ b/crates/query-engine/sql/src/sql/ast.rs @@ -300,8 +300,17 @@ pub enum Expression { expression: Box, nested_field: NestedField, }, + // JsonQuery(Box, JsonPath), // JSON_QUERY([album].[json], '$.title') for multiple + // // values + // JsonValue(Box, JsonPath), // JSON_VALUE([album].[json], '$.title') for single values } +// // JSON selector path for expressing '$.user.name' +// #[derive(Debug, Clone, PartialEq, Eq)] +// pub struct JsonPath { +// pub elements: Vec, +// } + /// Represents the name of a field in a nested object. #[derive(Debug, Clone, PartialEq, Eq)] pub struct NestedField(pub String); diff --git a/crates/query-engine/sql/src/sql/convert.rs b/crates/query-engine/sql/src/sql/convert.rs index 60a9a440..ec3fe77e 100644 --- a/crates/query-engine/sql/src/sql/convert.rs +++ b/crates/query-engine/sql/src/sql/convert.rs @@ -531,10 +531,40 @@ impl Expression { sql.append_syntax("."); nested_field.to_sql(sql); } + // Expression::JsonQuery(target, path) => { + // sql.append_syntax("JSON_QUERY"); + // sql.append_syntax("("); + // target.to_sql(sql); + // sql.append_syntax(", "); + // path.to_sql(sql); + // sql.append_syntax(")") + // } + // Expression::JsonValue(target, path) => { + // sql.append_syntax("JSON_VALUE"); + // sql.append_syntax("("); + // target.to_sql(sql); + // sql.append_syntax(", "); + // path.to_sql(sql); + // sql.append_syntax(")") + // } } } } +// impl JsonPath { +// pub fn to_sql(&self, sql: &mut SQL) { +// sql.append_syntax("'$"); +// for ColumnAlias { +// name: path_item, .. +// } in self.elements.iter() +// { +// sql.append_syntax("."); +// sql.append_syntax(path_item); +// } +// sql.append_syntax("'"); +// } +// } + impl UnaryOperator { pub fn to_sql(&self, sql: &mut SQL) { match self { diff --git a/crates/query-engine/sql/src/sql/helpers.rs b/crates/query-engine/sql/src/sql/helpers.rs index 4baed19b..d1b02d1d 100644 --- a/crates/query-engine/sql/src/sql/helpers.rs +++ b/crates/query-engine/sql/src/sql/helpers.rs @@ -257,20 +257,57 @@ pub fn select_rowset( // with: With, select_set: SelectSet, ) -> Select { + dbg!(output_table_alias.clone()); + dbg!(output_column_alias.clone()); + dbg!(row_table_alias.clone()); match select_set { SelectSet::Rows(row_select) => { let mut json_items = BTreeMap::new(); json_items.insert( "rows".to_string(), - (Expression::FunctionCall { - function: Function::ArrayAgg, - args: vec![Expression::TableReference(TableReference::AliasedTable( - row_table_alias.clone(), - ))], - }), + Expression::FunctionCall { + function: Function::Coalesce, + args: vec![ + Expression::FunctionCall { + function: Function::ArrayAgg, + args: vec![Expression::TableReference(TableReference::AliasedTable( + row_table_alias.clone(), + ))], + }, + Expression::ArrayConstructor(vec![]) + ], + }, + // (Expression::FunctionCall { + // function: Function::ArrayAgg, + // args: vec![Expression::TableReference(TableReference::AliasedTable( + // row_table_alias.clone(), + // ))], + // }), ); + // json_items.insert( + // "rows".to_string(), + // Expression::FunctionCall { + // function: Function::Coalesce, + // args: vec![ + // Expression::FunctionCall { + // function: Function::JsonAgg, + // args: vec![Expression::RowToJson(TableReference::AliasedTable( + // row_table_alias.clone(), + // ))], + // }, + // Expression::ArrayConstructor(vec![]) + // ], + // } + // // Expression::FunctionCall { + // // function: Function::ArrayAgg, + // // args: vec![Expression::TableReference(TableReference::AliasedTable( + // // row_table_alias.clone(), + // // ))], + // // }, + // ); + let row = vec![( output_column_alias, (Expression::JsonBuildObject(json_items)), @@ -313,7 +350,58 @@ pub fn select_rowset( }); final_select } - _ => todo!("no select rowset for rows + aggregates"), + // _ => todo!("no select rowset for rows + aggregates"), + SelectSet::RowsAndAggregates(row_select, aggregate_select) => { + let mut json_items = BTreeMap::new(); + + json_items.insert( + "rows".to_string(), + Expression::FunctionCall { + function: Function::ArrayAgg, + args: vec![Expression::TableReference(TableReference::AliasedTable( + row_table_alias.clone(), + ))], + }, + ); + + json_items.insert( + "aggregates".to_string(), + (Expression::TableReference(TableReference::AliasedTable( + aggregate_table_alias.clone(), + ))), + ); + + let row = vec![( + output_column_alias, + (Expression::JsonBuildObject(json_items)), + )]; + + let mut final_select = simple_select(row); + + let select_star = star_select(From::Select { + alias: row_inner_table_alias_.clone(), + select: Box::new(row_select), + }); + + let select_star2 = star_select(From::Select { + alias: aggregate_table_alias.clone(), + select: Box::new(aggregate_select), + }); + + final_select.from = Some(From::Select { + alias: row_table_alias, + select: Box::new(select_star), + }); + + final_select.joins = vec![Join::CrossJoin(CrossJoin { + select: Box::new(select_star2), + alias: aggregate_table_alias, + })]; + + dbg!(final_select.clone()); + + final_select + } } } // pub fn select_rowset( diff --git a/crates/query-engine/translation/src/translation/query/mod.rs b/crates/query-engine/translation/src/translation/query/mod.rs index 2561521d..d80f5baa 100644 --- a/crates/query-engine/translation/src/translation/query/mod.rs +++ b/crates/query-engine/translation/src/translation/query/mod.rs @@ -72,6 +72,8 @@ pub fn translate( select_set, ); + dbg!(json_select.clone()); + // normalize ast let json_select = sql::rewrites::constant_folding::normalize_select(json_select);