-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
42 changed files
with
5,721 additions
and
18 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
use std::str::FromStr; | ||
|
||
use crate::parsers::lang::{Lang, LangType}; | ||
use crate::parsers::planner; | ||
use crate::parsers::sql::Sql; | ||
use crate::parsers::value::PqlValue; | ||
|
||
pub fn evaluate(sql: &str, input: &str, from: &str, to: &str) -> anyhow::Result<String> { | ||
let from_lang_type = LangType::from_str(&from)?; | ||
let to_lang_type = LangType::from_str(&to)?; | ||
let mut lang = Lang::from_as(&input, from_lang_type)?; | ||
|
||
let sql = Sql::from_str(&sql)?; | ||
|
||
let result = planner::evaluate(sql, lang.data); | ||
lang.to = to_lang_type; | ||
lang.data = result; | ||
let output = lang.to_string(true)?; | ||
|
||
Ok(output) | ||
} | ||
|
||
pub fn loads(input: &str, from: &str) -> anyhow::Result<PqlValue> { | ||
let from_lang_type = LangType::from_str(&from)?; | ||
let lang = Lang::from_as(&input, from_lang_type)?; | ||
let value = lang.data; | ||
Ok(value) | ||
} | ||
|
||
pub fn dumps(data: PqlValue, to: &str) -> anyhow::Result<String> { | ||
let to_lang_type = LangType::from_str(&to)?; | ||
let mut lang = Lang::default(); | ||
lang.data = data; | ||
lang.to = to_lang_type; | ||
let output = lang.to_string(true)?; | ||
Ok(output) | ||
} | ||
|
||
pub fn query_evaluate(data: PqlValue, sql: &str) -> anyhow::Result<PqlValue> { | ||
let sql = Sql::from_str(&sql)?; | ||
let data = PqlValue::from(data); | ||
let value = planner::evaluate(sql, data); | ||
Ok(value) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
use std::str::FromStr; | ||
|
||
use parse_display::{Display, FromStr}; | ||
|
||
#[cfg(feature = "table")] | ||
use polars::prelude::CsvReader; | ||
#[cfg(feature = "table")] | ||
use polars::prelude::*; | ||
|
||
use crate::parsers::value::{BPqlValue, PqlValue, TomlValue}; | ||
|
||
#[derive(Display, FromStr, PartialEq, Clone, Debug)] | ||
#[display(style = "snake_case")] | ||
pub enum LangType { | ||
Json, | ||
Yaml, | ||
Toml, | ||
Xml, | ||
#[cfg(feature = "table")] | ||
Csv, | ||
} | ||
|
||
impl Default for LangType { | ||
fn default() -> Self { | ||
Self::Json | ||
} | ||
} | ||
|
||
#[derive(Debug, Default, Clone, PartialEq)] | ||
pub struct Lang { | ||
pub data: PqlValue, | ||
pub text: String, | ||
pub from: LangType, | ||
pub to: LangType, | ||
pub colnames: Vec<String>, | ||
} | ||
|
||
impl FromStr for Lang { | ||
type Err = anyhow::Error; | ||
|
||
fn from_str(input: &str) -> anyhow::Result<Self> { | ||
if let Ok(this) = Self::from_as_json(input) { | ||
Ok(this) | ||
} else if let Ok(this) = Self::from_as_toml(input) { | ||
Ok(this) | ||
} else if let Ok(this) = Self::from_as_xml(input) { | ||
Ok(this) | ||
} else if let Ok(this) = Self::from_as_xml(input) { | ||
Ok(this) | ||
} else { | ||
anyhow::bail!("not supported") | ||
} | ||
} | ||
} | ||
|
||
impl Lang { | ||
pub fn from_as(input: &str, lnag_type: LangType) -> anyhow::Result<Self> { | ||
match lnag_type { | ||
#[cfg(feature = "table")] | ||
LangType::Csv => Self::from_as_csv(input), | ||
LangType::Json => Self::from_as_json(input), | ||
LangType::Toml => Self::from_as_toml(input), | ||
LangType::Yaml => Self::from_as_yaml(input), | ||
LangType::Xml => Self::from_as_xml(input), | ||
} | ||
} | ||
|
||
#[cfg(feature = "table")] | ||
pub fn from_as_csv(input: &str) -> anyhow::Result<Self> { | ||
if let Ok(data) = csvstr_to_pqlv(input) { | ||
Ok(Self { | ||
data, | ||
text: input.to_string(), | ||
from: LangType::Csv, | ||
to: LangType::Csv, | ||
colnames: Vec::default(), | ||
}) | ||
} else { | ||
anyhow::bail!("fail to parse input as csv"); | ||
} | ||
} | ||
|
||
pub fn from_as_json(input: &str) -> anyhow::Result<Self> { | ||
if let Ok(data) = serde_json::from_str::<serde_json::value::Value>(input) { | ||
// Json does not distinguish between Float and Int. For this reason, it it parsed once with serde_json::value::Value, not crate::value::PqlValue. | ||
Ok(Self { | ||
data: crate::parsers::value::json_value::to_pqlvalue(data), | ||
text: input.to_string(), | ||
from: LangType::Json, | ||
to: LangType::Json, | ||
colnames: Vec::default(), | ||
}) | ||
} else { | ||
anyhow::bail!("fail to parse input as json"); | ||
} | ||
} | ||
|
||
pub fn from_as_toml(input: &str) -> anyhow::Result<Self> { | ||
if let Ok(data) = toml::from_str::<PqlValue>(input) { | ||
Ok(Self { | ||
data, | ||
text: input.to_string(), | ||
from: LangType::Toml, | ||
to: LangType::Toml, | ||
colnames: Vec::default(), | ||
}) | ||
} else { | ||
anyhow::bail!("fail to parse input as toml"); | ||
} | ||
} | ||
|
||
pub fn from_as_xml(input: &str) -> anyhow::Result<Self> { | ||
if let Ok(data) = quick_xml::de::from_str::<PqlValue>(input) { | ||
Ok(Self { | ||
data, | ||
text: input.to_string(), | ||
from: LangType::Xml, | ||
to: LangType::Xml, | ||
colnames: Vec::default(), | ||
}) | ||
} else { | ||
anyhow::bail!("fail to parse input as xml"); | ||
} | ||
} | ||
|
||
pub fn from_as_yaml(input: &str) -> anyhow::Result<Self> { | ||
if let Ok(data) = serde_yaml::from_str::<PqlValue>(input) { | ||
Ok(Self { | ||
data, | ||
text: input.to_string(), | ||
from: LangType::Yaml, | ||
to: LangType::Yaml, | ||
colnames: Vec::default(), | ||
}) | ||
} else { | ||
anyhow::bail!("fail to parse input as yaml"); | ||
} | ||
} | ||
|
||
pub fn sort_keys(&mut self) { | ||
let json = serde_json::to_string(&self.data).unwrap(); | ||
let bdata = serde_json::from_str::<BPqlValue>(&json).unwrap(); | ||
let bjson = serde_json::to_string(&bdata).unwrap(); | ||
let data = serde_json::from_str::<PqlValue>(&bjson).unwrap(); | ||
self.data = data; | ||
} | ||
|
||
pub fn to_string(&self, compact: bool) -> anyhow::Result<String> { | ||
let output = match (&self.to, &self.from == &self.to) { | ||
#[cfg(feature = "table")] | ||
(LangType::Csv, _) => { | ||
// To pad missing values with null, serialize them to json, deserialize them with polars, and write them to csv from there. | ||
let sss = match &self.data { | ||
PqlValue::Array(array) => array | ||
.iter() | ||
.map(|v| serde_json::to_string(&v).unwrap()) | ||
.collect::<Vec<String>>() | ||
.join("\n"), | ||
_ => anyhow::bail!("must array"), | ||
}; | ||
let c = std::io::Cursor::new(&sss); | ||
let mut df = JsonReader::new(c).infer_schema(Some(100)).finish()?; | ||
|
||
let mut v = Vec::new(); | ||
CsvWriter::new(&mut v) | ||
.has_headers(true) | ||
.with_delimiter(b',') | ||
.finish(&mut df)?; | ||
let s = String::from_utf8(v)?; | ||
s | ||
} | ||
(LangType::Json, _) if compact => serde_json::to_string(&self.data).unwrap(), | ||
(LangType::Json, _) => serde_json::to_string_pretty(&self.data).unwrap(), | ||
(_, true) => self.text.to_owned(), | ||
(LangType::Toml, _) => { | ||
let v = TomlValue::from(self.data.to_owned()); | ||
toml::to_string_pretty(&v).unwrap() | ||
} | ||
(LangType::Yaml, _) => serde_yaml::to_string(&self.data) | ||
.unwrap() | ||
.trim_start_matches("---\n") | ||
.to_string(), | ||
(LangType::Xml, _) => quick_xml::se::to_string(&self.data).unwrap(), | ||
}; | ||
|
||
Ok(output) | ||
} | ||
|
||
#[cfg(feature = "cli")] | ||
pub fn print(&self, compact: bool) -> anyhow::Result<()> { | ||
let output = self.to_string(compact)?; | ||
|
||
if atty::is(atty::Stream::Stdout) { | ||
let bytes = output.as_bytes().to_vec(); | ||
let lang_type = self.to.to_string(); | ||
|
||
bat::PrettyPrinter::new() | ||
.language(&lang_type) | ||
.input(bat::Input::from_bytes(&bytes)) | ||
.print() | ||
.unwrap(); | ||
} else { | ||
println!("{}", &output); | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
#[cfg(feature = "table")] | ||
fn csvstr_to_pqlv(input: &str) -> anyhow::Result<PqlValue> { | ||
let c = std::io::Cursor::new(input.to_owned()); | ||
let df = CsvReader::new(c).infer_schema(Some(100)).finish()?; | ||
Ok(PqlValue::from(df)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#![feature(box_patterns)] | ||
pub mod engine; | ||
pub mod lang; | ||
pub mod models; | ||
pub mod parser; | ||
pub mod planner; | ||
pub mod pqlir_parser; | ||
pub mod sql; | ||
pub mod utils; | ||
pub mod value; |
Oops, something went wrong.