use std::fmt::{Display, Error, Formatter};
use proc_macro2::{Span, TokenStream};
use quote::{Tokens, ToTokens};
use syn::{Expr, Ident};
pub type Expression = Expr;
pub type Groups = Vec<Ident>;
#[derive(Clone, Debug, Default)]
pub struct Aggregate {
pub field: Option<Ident>,
pub function: String,
pub has_name_in_query: bool,
pub result_name: Option<Ident>,
pub sql_function: String,
}
#[derive(Debug)]
pub struct AggregateFilter {
pub operand1: Aggregate,
pub operator: RelationalOperator,
pub operand2: Expression,
}
#[derive(Debug)]
pub enum AggregateFilterExpression {
Filter(AggregateFilter),
Filters(AggregateFilters),
NegFilter(Box<AggregateFilterExpression>),
NoFilters,
ParenFilter(Box<AggregateFilterExpression>),
FilterValue(WithSpan<Aggregate>),
}
impl Default for AggregateFilterExpression {
fn default() -> Self {
AggregateFilterExpression::NoFilters
}
}
#[derive(Debug)]
pub struct AggregateFilters {
pub operand1: Box<AggregateFilterExpression>,
pub operator: LogicalOperator,
pub operand2: Box<AggregateFilterExpression>,
}
#[derive(Debug)]
pub struct Assignment {
pub identifier: Option<Ident>,
pub operator: WithSpan<AssignmentOperator>,
pub value: Expression,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum AssignmentOperator {
Add,
Divide,
Equal,
Modulo,
Mul,
Sub,
}
impl Display for AssignmentOperator {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
let op =
match *self {
AssignmentOperator::Add => "+=",
AssignmentOperator::Divide => "/=",
AssignmentOperator::Equal => "=",
AssignmentOperator::Modulo => "%=",
AssignmentOperator::Mul => "*=",
AssignmentOperator::Sub => "-=",
};
write!(formatter, "{}", op).unwrap();
Ok(())
}
}
#[derive(Debug)]
pub struct Filter {
pub operand1: FilterValue,
pub operator: RelationalOperator,
pub operand2: Expression,
}
#[derive(Debug)]
pub enum FilterExpression {
Filter(Filter),
Filters(Filters),
NegFilter(Box<FilterExpression>),
NoFilters,
ParenFilter(Box<FilterExpression>),
FilterValue(WithSpan<FilterValue>),
}
impl Default for FilterExpression {
fn default() -> Self {
FilterExpression::NoFilters
}
}
#[derive(Debug)]
pub struct Filters {
pub operand1: Box<FilterExpression>,
pub operator: LogicalOperator,
pub operand2: Box<FilterExpression>,
}
#[derive(Debug)]
pub enum FilterValue {
None,
Identifier(String, Ident),
MethodCall(MethodCall),
PrimaryKey(String),
}
#[derive(Clone, Debug)]
pub struct Join {
pub base_field: Ident,
pub base_table: String,
}
#[derive(Clone, Debug)]
pub enum Limit {
EndRange(Expression),
Index(Expression),
LimitOffset(Expression, Expression),
NoLimit,
Range(Expression, Expression),
StartRange(Expression),
}
impl Default for Limit {
fn default() -> Limit {
Limit::NoLimit
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LogicalOperator {
And,
Not,
Or,
}
#[derive(Clone, Debug)]
pub struct MethodCall {
pub arguments: Vec<Expression>,
pub method_name: Ident,
pub object_name: Ident,
pub position: Span,
}
#[derive(Debug)]
pub enum Order {
Ascending(Ident),
Descending(Ident),
NoOrder,
}
#[derive(Clone, Copy, Debug)]
pub enum RelationalOperator {
Equal,
LesserThan,
LesserThanEqual,
NotEqual,
GreaterThan,
GreaterThanEqual,
}
#[derive(Debug)]
pub enum Query {
Aggregate {
aggregates: Vec<Aggregate>,
aggregate_filter: AggregateFilterExpression,
filter: FilterExpression,
groups: Groups,
joins: Vec<Join>,
table: String,
},
CreateTable {
table: String,
},
Delete {
filter: FilterExpression,
table: String,
use_pk: bool,
},
Drop {
table: String,
},
Insert {
assignments: Vec<Assignment>,
table: String,
},
Select {
filter: FilterExpression,
get: bool,
joins: Vec<Join>,
limit: Limit,
order: Vec<Order>,
table: String,
use_pk: bool,
},
Update {
assignments: Vec<Assignment>,
filter: FilterExpression,
table: String,
use_pk: bool,
},
}
pub enum QueryType {
AggregateMulti,
AggregateOne,
Create,
Exec,
InsertOne,
SelectMulti,
SelectOne,
}
#[derive(Debug)]
pub struct TypedField {
pub identifier: String,
pub typ: Tokens,
}
pub fn query_type(query: &Query) -> QueryType {
match *query {
Query::Aggregate { ref groups, .. } => {
if !groups.is_empty() {
QueryType::AggregateMulti
}
else {
QueryType::AggregateOne
}
},
Query::Insert { .. } => QueryType::InsertOne,
Query::Select { get, ref limit, .. } => {
let mut typ = QueryType::SelectMulti;
if get {
typ = QueryType::SelectOne;
}
if let Limit::Index(_) = *limit {
typ = QueryType::SelectOne;
}
typ
},
Query::CreateTable { .. } => QueryType::Create,
Query::Delete { .. } | Query::Drop { .. } | Query::Update { .. } => QueryType::Exec,
}
}
#[derive(Debug)]
pub struct WithSpan<T> {
pub node: T,
pub span: Span,
}
pub fn first_token_span(expr: &Expr) -> Span {
let tokens: TokenStream = expr.into_tokens().into();
tokens.into_iter().next().expect("first token of method call expression").span
}