limit offset

main
Ziyang Hu 2 years ago
parent 8408d62539
commit fa1cda686b

@ -36,16 +36,17 @@
// }
use std::collections::BTreeMap;
use pest::iterators::Pair;
use crate::db::engine::Session;
use crate::db::table::TableInfo;
use crate::error::CozoError::LogicError;
use crate::parser::Rule;
use crate::error::{CozoError, Result};
use crate::parser::text_identifier::build_name_in_def;
use crate::parser::text_identifier::{build_name_in_def, parse_string};
use crate::relation::data::DataKind;
use crate::relation::value;
use crate::relation::value::Value;
use crate::relation::value::{build_expr_primary, METHOD_MERGE, Value};
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum FromEl {
@ -209,6 +210,117 @@ impl<'a> Session<'a> {
let conditions = pair.into_inner().map(Value::from_pair).collect::<Result<Vec<_>>>()?;
Ok(Value::Apply(value::OP_AND.into(), conditions).to_static())
}
pub fn parse_select_pattern<'i>(&self, pair: Pair<'i, Rule>) -> Result<Selection<'i>> {
let mut pairs = pair.into_inner();
let mut nxt = pairs.next().unwrap();
let scoped = match nxt.as_rule() {
Rule::scoped_dict => {
let mut pp = nxt.into_inner();
let name = pp.next().unwrap().as_str();
nxt = pp.next().unwrap();
Some(name.to_string())
}
_ => None
};
let mut keys = BTreeMap::new();
let mut merged = vec![];
let mut collected_vals = BTreeMap::new();
for p in nxt.into_inner() {
match p.as_rule() {
Rule::grouped_pair => {
let mut pp = p.into_inner();
let id = parse_string(pp.next().unwrap())?;
let val = Value::from_pair(pp.next().unwrap())?;
keys.insert(id, val);
}
Rule::dict_pair => {
let mut inner = p.into_inner();
let name = parse_string(inner.next().unwrap())?;
let val = build_expr_primary(inner.next().unwrap())?;
collected_vals.insert(name.into(), val);
}
Rule::spreading => {
let el = p.into_inner().next().unwrap();
let to_concat = build_expr_primary(el)?;
if !matches!(to_concat, Value::Dict(_) | Value::Variable(_) |
Value::IdxAccess(_, _) | Value:: FieldAccess(_, _) | Value::Apply(_, _)) {
return Err(CozoError::LogicError("Cannot spread".to_string()));
}
if !collected_vals.is_empty() {
merged.push(Value::Dict(collected_vals));
collected_vals = BTreeMap::new();
}
merged.push(to_concat);
}
Rule::scoped_accessor => {
let name = parse_string(p.into_inner().next().unwrap())?;
let val = Value::FieldAccess(name.clone().into(),
Value::Variable("_".into()).into());
collected_vals.insert(name.into(), val);
}
_ => unreachable!()
}
}
let vals = if merged.is_empty() {
Value::Dict(collected_vals)
} else {
if !collected_vals.is_empty() {
merged.push(Value::Dict(collected_vals));
}
Value::Apply(METHOD_MERGE.into(), merged)
};
let mut ordering = vec![];
let mut limit = None;
let mut offset = None;
for p in pairs {
match p.as_rule() {
Rule::order_pattern => {
for p in p.into_inner() {
ordering.push((p.as_rule() == Rule::order_asc, parse_string(p.into_inner().next().unwrap())?))
}
}
Rule::offset_pattern => {
for p in p.into_inner() {
match p.as_rule() {
Rule::limit_clause => {
limit = Some(p.into_inner().next().unwrap().as_str().replace('_', "").parse::<i64>()?);
}
Rule::offset_clause => {
offset = Some(p.into_inner().next().unwrap().as_str().replace('_', "").parse::<i64>()?);
}
_ => unreachable!()
}
}
}
_ => unreachable!()
}
}
Ok(Selection {
scoped,
keys,
vals,
ordering,
limit,
offset
})
}
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Selection<'a> {
pub scoped: Option<String>,
pub keys: BTreeMap<String, Value<'a>>,
pub vals: Value<'a>,
pub ordering: Vec<(bool, String)>,
pub limit: Option<i64>,
pub offset: Option<i64>
}
#[cfg(test)]
@ -272,6 +384,11 @@ mod tests {
let parsed = Parser::parse(Rule::where_pattern, s).unwrap().next().unwrap();
let where_result = sess.parse_where_pattern(parsed).unwrap();
println!("{:#?}", where_result);
let s = "select {*id: a.id, b: a.b, c: a.c} ordered [e, +c, -b] limit 1 offset 2";
let parsed = Parser::parse(Rule::select_pattern, s).unwrap().next().unwrap();
let select_result = sess.parse_select_pattern(parsed).unwrap();
println!("{:#?}", select_result);
}
drop(engine);
let _ = fs::remove_dir_all(db_path);

@ -126,7 +126,11 @@ dict_entry = _{ spreading | dict_pair | scoped_accessor }
scoped_accessor = { ident }
dict_pair = {(ident | string) ~ ":" ~ expr}
scoped_dict = { ident ~ dict }
select_dict = { "{" ~ (select_dict_entry ~ ",")* ~ select_dict_entry? ~ "}"}
select_dict_entry = _{ grouped_pair | spreading | dict_pair | scoped_accessor }
grouped_pair = { "*" ~ (ident | string) ~ ":" ~ expr}
scoped_dict = { ident ~ select_dict }
name_in_def = {(ident | string)}
col_entry = { col_name ~ ":" ~ typing ~ ("=" ~ expr)? }
@ -181,4 +185,15 @@ bwd_edge_pattern = { "<-" ~ edge_pattern_inner ~ "-" }
edge_pattern_inner = _{"[" ~ ident? ~ ":" ~ name_in_def ~ "]"}
outer_join_marker = { "?" }
where_pattern = { "where" ~ (expr ~ ",")* ~ expr }
where_pattern = { "where" ~ (expr ~ ",")* ~ expr }
select_pattern = { "select" ~ (select_dict | scoped_dict) ~ ( (order_pattern ~ offset_pattern?) | (offset_pattern ~ order_pattern?) )? }
order_pattern = { "ordered" ~ "[" ~ order_el ~ ("," ~ order_el)* ~ "]" }
order_el = _{order_asc | order_dsc}
order_asc = {"+"? ~ ident}
order_dsc = {"-" ~ ident}
offset_pattern = { limit_clause? ~ offset_clause? }
limit_clause = { "limit" ~ pos_int }
offset_clause = { "offset" ~ pos_int }
relational_query = { from_pattern ~ where_pattern? ~ select_pattern }

@ -387,7 +387,7 @@ fn build_expr_infix<'a>(lhs: Result<Value<'a>>, op: Pair<Rule>, rhs: Result<Valu
}
fn build_expr_primary(pair: Pair<Rule>) -> Result<Value> {
pub fn build_expr_primary(pair: Pair<Rule>) -> Result<Value> {
match pair.as_rule() {
Rule::expr => build_expr_primary(pair.into_inner().next().unwrap()),
Rule::term => {

Loading…
Cancel
Save