vecdb_core/planner/sql/
converter.rs1use crate::errors::{Result, VecDbError};
2use crate::planner::plan::{PhysicalPlan, QueryPlanner};
3use crate::types::{SearchRequest, Vector};
4
5use super::ast::{Condition, Literal, Operator, ScalarCondition, SelectStatement};
6
7pub struct AstConverter {
14 pub planner: QueryPlanner,
15}
16
17impl AstConverter {
18 pub fn new(planner: QueryPlanner) -> Self {
19 Self { planner }
20 }
21
22 pub fn convert(&self, stmt: SelectStatement, vector_count: usize) -> Result<PhysicalPlan> {
29 let output_columns: Vec<String> = stmt.columns.clone();
31
32 let query_vector: Option<Vector> = stmt
34 .where_clause
35 .as_ref()
36 .and_then(find_vector_condition)
37 .map(|vc| vc.vector.clone());
38
39 if query_vector.is_none() {
40 return Err(VecDbError::InvalidQuery(
41 "SQL query must contain a VECTOR_SIM condition".into(),
42 ));
43 }
44
45 let scalar_filter: Option<serde_json::Value> =
47 stmt.where_clause.as_ref().and_then(collect_all_conditions);
48
49 let k = stmt.limit.unwrap_or(10);
50
51 let request = SearchRequest {
52 vector: query_vector,
53 query_text: None,
54 k,
55 alpha: 0.7,
56 collection: stmt.table,
57 filter: scalar_filter,
58 };
59
60 let mut plan = self.planner.plan_search(&request, vector_count)?;
61
62 plan.output_columns = output_columns;
65
66 Ok(plan)
67 }
68
69 pub fn extract_query_vector(stmt: &SelectStatement) -> Option<Vector> {
71 stmt.where_clause
72 .as_ref()
73 .and_then(find_vector_condition)
74 .map(|vc| vc.vector.clone())
75 }
76}
77
78pub fn find_vector_condition(cond: &Condition) -> Option<&super::ast::VectorCondition> {
84 match cond {
85 Condition::Vector(vc) => Some(vc),
86 Condition::And(l, r) | Condition::Or(l, r) => {
87 find_vector_condition(l).or_else(|| find_vector_condition(r))
88 }
89 Condition::Not(inner) => find_vector_condition(inner),
90 Condition::Scalar(_) => None,
91 }
92}
93
94fn collect_all_conditions(cond: &Condition) -> Option<serde_json::Value> {
101 let mut items: Vec<serde_json::Value> = Vec::new();
102 collect_scalar_into(cond, &mut items);
103 match items.len() {
104 0 => None,
105 1 => Some(items.remove(0)),
106 _ => Some(serde_json::Value::Array(items)),
107 }
108}
109
110fn collect_scalar_into(cond: &Condition, out: &mut Vec<serde_json::Value>) {
111 match cond {
112 Condition::Scalar(sc) => {
113 if let Some(obj) = scalar_to_json(sc) {
114 out.push(obj);
115 }
116 }
117 Condition::And(l, r) => {
118 collect_scalar_into(l, out);
119 collect_scalar_into(r, out);
120 }
121 _ => {}
123 }
124}
125
126fn scalar_to_json(sc: &ScalarCondition) -> Option<serde_json::Value> {
127 let op_str = match sc.op {
128 Operator::Eq => "=",
129 Operator::NotEq => "!=",
130 Operator::Lt => "<",
131 Operator::LtEq => "<=",
132 Operator::Gt => ">",
133 Operator::GtEq => ">=",
134 Operator::Like => "LIKE",
135 };
136 Some(serde_json::json!({
137 "field": sc.field,
138 "op": op_str,
139 "value": literal_to_json(&sc.value),
140 }))
141}
142
143fn literal_to_json(lit: &Literal) -> serde_json::Value {
144 match lit {
145 Literal::String(s) => serde_json::Value::String(s.clone()),
146 Literal::Float(f) => serde_json::json!(f),
147 Literal::Integer(i) => serde_json::json!(i),
148 Literal::Bool(b) => serde_json::Value::Bool(*b),
149 }
150}