1use sqlparser::ast::{Expr, Query, SetExpr, Statement, Value};
2
3#[derive(Debug, PartialEq)]
4pub enum LogicalPlan {
5 CreateTable {
6 name: String,
7 },
8 Insert {
9 table: String,
10 id: String,
11 vector: Vec<f32>,
12 metadata: Option<String>,
13 },
14 Search {
15 table: String,
16 query_vector: Vec<f32>,
17 limit: usize,
18 filter: Option<String>,
19 },
20 Compact {
21 table: String,
22 },
23 RetentionPolicy {
24 table: String,
25 interval: String,
26 },
27}
28
29pub struct PlanBuilder;
30
31impl PlanBuilder {
32 pub fn build_from_sql(query: &str) -> Result<LogicalPlan, String> {
33 let q = query.trim();
34 let upper = q.to_uppercase();
35 if upper.starts_with("VACUUM") || upper.starts_with("COMPACT") {
36 let parts: Vec<&str> = q.split_whitespace().collect();
37 if parts.len() >= 2 {
38 let table = parts[1].trim_end_matches(';').to_string();
39 return Ok(LogicalPlan::Compact { table });
40 }
41 }
42
43 let stmts = crate::parser::parse_sql(query)?;
44 if stmts.is_empty() {
45 return Err("No statements found".to_string());
46 }
47 Self::build(stmts[0].clone())
48 }
49
50 pub fn build(stmt: Statement) -> Result<LogicalPlan, String> {
51 match stmt {
52 Statement::CreateTable { name, .. } => {
53 let table_name = name.to_string();
54 Ok(LogicalPlan::CreateTable { name: table_name })
55 }
56 Statement::Insert {
57 table_name, source, ..
58 } => {
59 let table = table_name.to_string();
60 let body = match source.as_ref().map(|s| &*s.body) {
61 Some(SetExpr::Values(values)) => values,
62 _ => return Err("Only VALUES inserts are supported".to_string()),
63 };
64
65 if body.rows.len() != 1 {
66 return Err("Only single row inserts are supported".to_string());
67 }
68
69 let row = &body.rows[0];
70 if row.len() < 2 {
71 return Err("Insert requires at least id and vector".to_string());
72 }
73
74 let id = Self::extract_string(&row[0])?;
75 let vector = Self::extract_vector(&row[1])?;
76 let metadata = if row.len() > 2 {
77 Some(Self::extract_string(&row[2])?)
78 } else {
79 None
80 };
81
82 Ok(LogicalPlan::Insert {
83 table,
84 id,
85 vector,
86 metadata,
87 })
88 }
89 Statement::Query(query) => Self::build_query(*query),
90 _ => Err(format!("Unsupported statement: {:?}", stmt)),
91 }
92 }
93
94 fn build_query(query: Query) -> Result<LogicalPlan, String> {
95 let select = match *query.body {
96 SetExpr::Select(s) => s,
97 _ => return Err("Only SELECT queries are supported".to_string()),
98 };
99
100 if select.from.is_empty() {
101 return Err("FROM clause is required".to_string());
102 }
103
104 let table = select.from[0].relation.to_string();
105
106 let limit = match query.limit {
107 Some(Expr::Value(Value::Number(n, _))) => n.parse::<usize>().unwrap_or(10),
108 _ => 10,
109 };
110
111 let mut query_vector = vec![];
112
113 if !query.order_by.is_empty() {
114 let order_expr = &query.order_by[0];
115 match &order_expr.expr {
116 Expr::BinaryOp { left: _, op, right } => {
117 let op_str = op.to_string();
118 if op_str.contains("<->") || op_str.contains("<=>") || op_str.contains("<#>") {
120 query_vector = Self::extract_vector(right)?;
121 } else {
122 return Err(format!("Unsupported order by operator: {}", op_str));
123 }
124 }
125 _ => return Err("Unsupported ORDER BY expression".to_string()),
126 }
127 } else {
128 return Err("ORDER BY vector distance is required for Search".to_string());
129 }
130
131 Ok(LogicalPlan::Search {
132 table,
133 query_vector,
134 limit,
135 filter: None,
136 })
137 }
138
139 fn extract_string(expr: &Expr) -> Result<String, String> {
140 match expr {
141 Expr::Value(Value::SingleQuotedString(s)) => Ok(s.clone()),
142 Expr::Value(Value::DoubleQuotedString(s)) => Ok(s.clone()),
143 _ => Err("Expected string value".to_string()),
144 }
145 }
146
147 fn extract_vector(expr: &Expr) -> Result<Vec<f32>, String> {
148 match expr {
149 Expr::Value(Value::SingleQuotedString(s))
150 | Expr::Value(Value::DoubleQuotedString(s)) => {
151 let trimmed = s.trim_matches(|c| c == '[' || c == ']');
152 let mut vec = Vec::new();
153 if trimmed.is_empty() {
154 return Ok(vec);
155 }
156 for part in trimmed.split(',') {
157 let val: f32 = part
158 .trim()
159 .parse()
160 .map_err(|_| format!("Invalid number in vector: {}", part))?;
161 vec.push(val);
162 }
163 Ok(vec)
164 }
165 Expr::Array(sqlparser::ast::Array { elem, .. }) => {
166 let mut vec = Vec::new();
167 for e in elem {
168 match e {
169 Expr::Value(Value::Number(n, _)) => {
170 let val: f32 = n
171 .parse()
172 .map_err(|_| format!("Invalid number in array: {}", n))?;
173 vec.push(val);
174 }
175 _ => return Err("Expected numbers in array".to_string()),
176 }
177 }
178 Ok(vec)
179 }
180 _ => Err(format!("Expected vector string or array, got {:?}", expr)),
181 }
182 }
183}