mod admin;
mod aggregation;
pub(crate) mod condition;
mod ddl;
mod dml;
mod fusion;
mod introspection;
mod join;
mod select;
mod train;
mod values;
mod window;
mod with_clause;
use serde::{Deserialize, Serialize};
pub use admin::{AdminStatement, FlushStatement};
pub use aggregation::{
AggregateArg, AggregateFunction, AggregateType, GroupByClause, HavingClause, HavingCondition,
LogicalOp,
};
pub use condition::{
BetweenCondition, CompareOp, Comparison, Condition, ContainsCondition, ContainsMode,
ContainsTextCondition, GeoBboxCondition, GeoDistanceCondition, GraphMatchPredicate,
InCondition, IsNullCondition, LikeCondition, MatchCondition, SimilarityCondition,
SparseVectorExpr, SparseVectorSearch, VectorFusedSearch, VectorSearch,
};
pub use ddl::{
AlterCollectionStatement, AnalyzeStatement, CreateCollectionKind, CreateCollectionStatement,
CreateIndexStatement, DdlStatement, DropCollectionStatement, DropIndexStatement,
GraphCollectionParams, GraphSchemaMode, SchemaDefinition, TruncateStatement,
VectorCollectionParams,
};
pub use dml::{
DeleteEdgeStatement, DeleteStatement, DmlStatement, InsertEdgeStatement, InsertNodeStatement,
InsertStatement, SelectEdgesStatement, UpdateAssignment, UpdateStatement,
};
pub use fusion::{FusionClause, FusionConfig, FusionStrategyType};
pub use introspection::{DescribeCollectionStatement, IntrospectionStatement};
pub use join::{ColumnRef, JoinClause, JoinCondition, JoinType};
pub use select::{
ArithmeticExpr, ArithmeticOp, Column, DistinctMode, LetBinding, OrderByExpr, SelectColumns,
SelectOrderBy, SelectStatement, SimilarityOrderBy, SimilarityScoreExpr, DEFAULT_SELECT_LIMIT,
};
pub use train::TrainStatement;
pub use values::{
CorrelatedColumn, IntervalUnit, IntervalValue, Subquery, TemporalExpr, Value, VectorExpr,
};
pub use window::{OverClause, WindowFunction, WindowFunctionType, WindowOrderBy};
pub use with_clause::{QuantizationMode, WithClause, WithOption, WithValue};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Query {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub let_bindings: Vec<LetBinding>,
pub select: SelectStatement,
#[serde(default)]
pub compound: Option<CompoundQuery>,
#[serde(default)]
pub match_clause: Option<crate::velesql::MatchClause>,
#[serde(default)]
pub dml: Option<DmlStatement>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub train: Option<TrainStatement>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ddl: Option<DdlStatement>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub introspection: Option<IntrospectionStatement>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub admin: Option<AdminStatement>,
}
impl Query {
#[must_use]
pub fn from_select(select: SelectStatement) -> Self {
Self::new_select(select)
}
#[must_use]
pub fn is_match_query(&self) -> bool {
self.match_clause.is_some()
}
#[must_use]
pub fn is_select_query(&self) -> bool {
self.match_clause.is_none()
&& self.dml.is_none()
&& self.train.is_none()
&& self.ddl.is_none()
&& self.introspection.is_none()
&& self.admin.is_none()
}
#[must_use]
pub fn is_dml_query(&self) -> bool {
self.dml.is_some()
}
#[must_use]
pub fn is_train(&self) -> bool {
self.train.is_some()
}
#[must_use]
pub fn is_ddl_query(&self) -> bool {
self.ddl.is_some()
}
#[must_use]
pub fn is_introspection_query(&self) -> bool {
self.introspection.is_some()
}
#[must_use]
pub fn is_admin_query(&self) -> bool {
self.admin.is_some()
}
#[must_use]
pub fn is_select_edges_query(&self) -> bool {
matches!(self.dml, Some(DmlStatement::SelectEdges(_)))
}
fn having_clauses(&self) -> impl Iterator<Item = (&SelectStatement, &HavingClause)> {
let compound_stmts = self
.compound
.iter()
.flat_map(|c| c.operations.iter().map(|(_, stmt)| stmt));
std::iter::once(&self.select)
.chain(compound_stmts)
.filter_map(|stmt| stmt.having.as_ref().map(|h| (stmt, h)))
}
#[must_use]
pub fn has_having_subquery(&self) -> bool {
self.having_clauses()
.any(|(_, having)| having.has_subquery())
}
#[must_use]
pub fn has_correlated_having_subquery(&self) -> bool {
self.having_clauses()
.any(|(stmt, having)| having.has_correlated_subquery(&stmt.outer_table_scope()))
}
#[must_use]
pub fn is_insert_node_query(&self) -> bool {
matches!(self.dml, Some(DmlStatement::InsertNode(_)))
}
#[must_use]
pub fn dml_collection_name(&self) -> Option<&str> {
let name = match self.dml.as_ref()? {
DmlStatement::Insert(s) | DmlStatement::Upsert(s) => &s.table,
DmlStatement::Update(s) => &s.table,
DmlStatement::Delete(s) => &s.table,
DmlStatement::InsertEdge(s) => &s.collection,
DmlStatement::DeleteEdge(s) => &s.collection,
DmlStatement::SelectEdges(s) => &s.collection,
DmlStatement::InsertNode(s) => &s.collection,
};
if name.is_empty() {
None
} else {
Some(name)
}
}
#[must_use]
pub fn new_select(select: SelectStatement) -> Self {
Self {
let_bindings: Vec::new(),
select,
compound: None,
match_clause: None,
dml: None,
train: None,
ddl: None,
introspection: None,
admin: None,
}
}
#[must_use]
pub fn new_match(match_clause: crate::velesql::MatchClause) -> Self {
let mut select = SelectStatement::empty();
select.where_clause.clone_from(&match_clause.where_clause);
select.limit = match_clause.return_clause.limit;
Self {
let_bindings: Vec::new(),
select,
compound: None,
match_clause: Some(match_clause),
dml: None,
train: None,
ddl: None,
introspection: None,
admin: None,
}
}
#[must_use]
pub fn new_dml(dml: DmlStatement) -> Self {
Self {
let_bindings: Vec::new(),
select: SelectStatement::empty(),
compound: None,
match_clause: None,
dml: Some(dml),
train: None,
ddl: None,
introspection: None,
admin: None,
}
}
#[must_use]
pub fn new_train(train: TrainStatement) -> Self {
Self {
let_bindings: Vec::new(),
select: SelectStatement::empty(),
compound: None,
match_clause: None,
dml: None,
train: Some(train),
ddl: None,
introspection: None,
admin: None,
}
}
#[must_use]
pub fn new_ddl(ddl: DdlStatement) -> Self {
Self {
let_bindings: Vec::new(),
select: SelectStatement::empty(),
compound: None,
match_clause: None,
dml: None,
train: None,
ddl: Some(ddl),
introspection: None,
admin: None,
}
}
#[must_use]
pub fn new_introspection(stmt: IntrospectionStatement) -> Self {
Self {
let_bindings: Vec::new(),
select: SelectStatement::empty(),
compound: None,
match_clause: None,
dml: None,
train: None,
ddl: None,
introspection: Some(stmt),
admin: None,
}
}
#[must_use]
pub fn new_admin(stmt: AdminStatement) -> Self {
Self {
let_bindings: Vec::new(),
select: SelectStatement::empty(),
compound: None,
match_clause: None,
dml: None,
train: None,
ddl: None,
introspection: None,
admin: Some(stmt),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum SetOperator {
Union,
UnionAll,
Intersect,
Except,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CompoundQuery {
pub operations: Vec<(SetOperator, SelectStatement)>,
}
#[cfg(test)]
#[path = "ast_tests.rs"]
mod tests;