use crate::ast::{
BinaryOp, Consumer, CountCmp, Expr, Follow, FollowDestination, LogicalOp, OpNode, OrderSpec,
Query, SelectItem, Span, Subquery, UnaryOp, Where,
};
use crate::value::Value;
pub fn lit(value: impl Into<Value>) -> Expr {
Expr::Lit {
value: value.into(),
span: Span::EMPTY,
}
}
pub fn ident(name: &str) -> Expr {
Expr::Ident {
name: name.to_owned(),
span: Span::EMPTY,
}
}
pub fn outer(levels: usize, name: &str) -> Expr {
Expr::Outer {
levels,
name: name.to_owned(),
span: Span::EMPTY,
}
}
pub fn binding(index: usize) -> Expr {
Expr::Binding {
index,
span: Span::EMPTY,
}
}
pub fn member(recv: Expr, name: &str) -> Expr {
Expr::Member {
recv: Box::new(recv),
name: name.to_owned(),
span: Span::EMPTY,
}
}
pub fn path(segments: &[&str]) -> Expr {
let (first, rest) = segments
.split_first()
.expect("a path has at least one segment");
rest.iter().fold(ident(first), |e, n| member(e, n))
}
pub fn call(recv: Option<Expr>, name: &str, args: Vec<Expr>) -> Expr {
Expr::Call {
recv: recv.map(Box::new),
name: name.to_owned(),
args,
span: Span::EMPTY,
}
}
pub fn required(expr: Expr) -> Expr {
Expr::Required {
expr: Box::new(expr),
span: Span::EMPTY,
}
}
pub fn unary(op: UnaryOp, expr: Expr) -> Expr {
Expr::Unary {
op,
expr: Box::new(expr),
span: Span::EMPTY,
}
}
pub fn binary(op: BinaryOp, left: Expr, right: Expr) -> Expr {
Expr::Binary {
op,
left: Box::new(left),
right: Box::new(right),
span: Span::EMPTY,
}
}
pub fn logical(op: LogicalOp, left: Expr, right: Expr) -> Expr {
Expr::Logical {
op,
left: Box::new(left),
right: Box::new(right),
span: Span::EMPTY,
}
}
pub fn in_op(left: Expr, right: Expr) -> Expr {
Expr::In {
left: Box::new(left),
right: Box::new(right),
span: Span::EMPTY,
}
}
pub fn range(lo: Option<Expr>, hi: Option<Expr>, exclusive_end: bool) -> Expr {
Expr::Range {
lo: lo.map(Box::new),
hi: hi.map(Box::new),
exclusive_end,
span: Span::EMPTY,
}
}
pub fn tuple(items: Vec<Expr>) -> Expr {
Expr::Tuple {
items,
span: Span::EMPTY,
}
}
pub fn scalar(expr: Expr) -> Where {
Where::Scalar {
expr,
span: Span::EMPTY,
}
}
pub fn and(parts: Vec<Where>) -> Where {
Where::And {
parts,
span: Span::EMPTY,
}
}
pub fn or(parts: Vec<Where>) -> Where {
Where::Or {
parts,
span: Span::EMPTY,
}
}
pub fn not(expr: Where) -> Where {
Where::Not {
expr: Box::new(expr),
span: Span::EMPTY,
}
}
pub fn where_op(op: OpNode) -> Where {
Where::Op(Box::new(op))
}
pub fn field(name: &str, expr: Expr) -> SelectItem {
SelectItem::Field {
name: name.to_owned(),
expr,
lift: 0,
span: Span::EMPTY,
}
}
pub fn lifted(lift: usize, name: &str, expr: Expr) -> SelectItem {
SelectItem::Field {
name: name.to_owned(),
expr,
lift,
span: Span::EMPTY,
}
}
pub fn collect(name: &str, op: OpNode) -> SelectItem {
SelectItem::Collect {
name: name.to_owned(),
op: Box::new(op),
span: Span::EMPTY,
}
}
pub fn order(expr: Expr, desc: bool) -> OrderSpec {
OrderSpec {
expr,
desc,
span: Span::EMPTY,
}
}
pub fn subquery() -> Subquery {
Subquery {
from: Vec::new(),
r#where: None,
select: Vec::new(),
order_by: None,
follow: None,
frontier: None,
depth: None,
values: false,
limit: None,
offset: None,
span: Span::EMPTY,
}
}
pub fn op(receiver: Expr, consumer: Consumer, sub: Subquery) -> OpNode {
OpNode {
receiver,
op: consumer,
sub,
count_cmp: None,
distinct: false,
span: Span::EMPTY,
}
}
pub fn count_cmp(receiver: Expr, sub: Subquery, cmp: CountCmp) -> OpNode {
OpNode {
receiver,
op: Consumer::Count,
sub,
count_cmp: Some(cmp),
distinct: false,
span: Span::EMPTY,
}
}
pub fn follow(destinations: Vec<FollowDestination>) -> Follow {
Follow {
destinations,
distinct: false,
span: Span::EMPTY,
}
}
pub fn query(source: Expr) -> Query {
Query {
source,
from: Vec::new(),
r#where: None,
frontier: None,
select: Vec::new(),
order_by: None,
consumer: Consumer::Collect,
follow: None,
distinct: false,
values: false,
limit: None,
offset: None,
span: Span::EMPTY,
}
}