use selene_core::DbString;
use crate::ast::{
call::{InlineProcedureCall, ProcedureCall},
ddl::DdlStatement,
expr::{CharacterStringLiteralKind, ValueExpr},
mutation::MutationPipeline,
pattern::MatchClause,
span::SourceSpan,
types::GqlType,
util::NonEmpty,
};
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
#[non_exhaustive]
pub enum Statement {
Query(QueryPipeline),
Composite {
first: QueryPipeline,
rest: NonEmpty<(SetOp, QueryPipeline)>,
span: SourceSpan,
},
Chained {
blocks: Vec<QueryPipeline>,
span: SourceSpan,
},
Mutate(MutationPipeline),
Ddl(DdlStatement),
Call(ProcedureCall),
Explain {
inner: Box<Statement>,
span: SourceSpan,
},
StartTransaction {
span: SourceSpan,
},
Commit {
span: SourceSpan,
},
Rollback {
span: SourceSpan,
},
SessionSetValue {
param: DbString,
declared_type: Option<GqlType>,
value: Box<ValueExpr>,
if_not_exists: bool,
span: SourceSpan,
},
SessionSetTimeZone {
zone: String,
zone_source_kind: CharacterStringLiteralKind,
span: SourceSpan,
},
SessionSetGraph {
target: SessionSetGraphTarget,
span: SourceSpan,
},
SessionReset {
target: SessionResetTarget,
span: SourceSpan,
},
SessionClose {
span: SourceSpan,
},
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub enum SessionSetGraphTarget {
CurrentGraph,
CurrentPropertyGraph,
}
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
#[non_exhaustive]
pub enum SessionResetTarget {
AllCharacteristics,
Parameters,
TimeZone,
Parameter(DbString),
}
impl Statement {
#[must_use]
pub const fn span(&self) -> SourceSpan {
match self {
Self::Query(pipeline) => pipeline.span,
Self::Composite { span, .. } | Self::Chained { span, .. } => *span,
Self::Mutate(pipeline) => pipeline.span,
Self::Ddl(statement) => statement.span(),
Self::Call(call) => call.span,
Self::Explain { span, .. } => *span,
Self::StartTransaction { span } | Self::Commit { span } | Self::Rollback { span } => {
*span
}
Self::SessionSetValue { span, .. }
| Self::SessionSetTimeZone { span, .. }
| Self::SessionSetGraph { span, .. }
| Self::SessionReset { span, .. }
| Self::SessionClose { span } => *span,
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
pub enum SetOp {
Union,
UnionAll,
Intersect,
IntersectAll,
Except,
ExceptAll,
Otherwise,
}
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct QueryPipeline {
pub statements: Vec<PipelineStatement>,
pub span: SourceSpan,
}
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
#[non_exhaustive]
pub enum PipelineStatement {
Match(MatchClause),
Filter(ValueExpr),
Let(Vec<LetBinding>),
For(ForStatement),
Sorting(Vec<OrderTerm>),
Limit(LimitValue),
Offset(LimitValue),
Return(ReturnClause),
With(WithClause),
Call(ProcedureCall),
CallSubquery(InlineProcedureCall),
}
impl PipelineStatement {
#[must_use]
pub fn span(&self) -> SourceSpan {
match self {
Self::Match(value) => value.span,
Self::Filter(value) => value.span(),
Self::Let(values) => span_from_iter(values.iter().map(|value| value.span)),
Self::For(value) => value.span,
Self::Sorting(values) => span_from_iter(values.iter().map(|value| value.span)),
Self::Limit(value) | Self::Offset(value) => value.span(),
Self::Return(value) => value.span,
Self::With(value) => value.span,
Self::Call(value) => value.span,
Self::CallSubquery(value) => value.span,
}
}
}
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct LetBinding {
pub alias: DbString,
pub declared_type: Option<GqlType>,
pub value: ValueExpr,
pub span: SourceSpan,
}
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct ForStatement {
pub source: ValueExpr,
pub alias: DbString,
pub position: Option<RowExpansionPosition>,
pub span: SourceSpan,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct RowExpansionPosition {
pub kind: RowExpansionPositionKind,
pub alias: DbString,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub enum RowExpansionPositionKind {
Ordinality,
Offset,
}
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct OrderTerm {
pub expr: ValueExpr,
pub direction: OrderDirection,
pub nulls: Option<NullsPolicy>,
pub span: SourceSpan,
}
#[derive(
Clone, Copy, Debug, Default, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize,
)]
pub enum OrderDirection {
#[default]
Asc,
Desc,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
pub enum NullsPolicy {
NullsFirst,
NullsLast,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[non_exhaustive]
pub enum LimitValue {
Count(u64, SourceSpan),
Parameter {
name: DbString,
declared_type: Option<GqlType>,
span: SourceSpan,
},
}
impl LimitValue {
#[must_use]
pub const fn span(&self) -> SourceSpan {
match self {
Self::Count(_, span) | Self::Parameter { span, .. } => *span,
}
}
}
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct ReturnClause {
pub distinct: bool,
pub star: bool,
pub items: Vec<ReturnItem>,
pub group_by: Option<Vec<ValueExpr>>,
pub having: Option<ValueExpr>,
pub span: SourceSpan,
}
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct ReturnItem {
pub expr: ValueExpr,
pub alias: Option<DbString>,
pub span: SourceSpan,
}
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct WithClause {
pub distinct: bool,
pub items: Vec<ReturnItem>,
pub group_by: Option<Vec<ValueExpr>>,
pub having: Option<ValueExpr>,
pub where_clause: Option<ValueExpr>,
pub span: SourceSpan,
}
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct TypedBinding {
pub name: DbString,
pub ty: GqlType,
pub span: SourceSpan,
}
fn span_from_iter(mut spans: impl Iterator<Item = SourceSpan>) -> SourceSpan {
let Some(first) = spans.next() else {
return SourceSpan::default();
};
spans.fold(first, SourceSpan::merge)
}