use std::sync::{Arc, RwLock};
use alopex_core::kv::memory::MemoryKV;
use alopex_sql::catalog::MemoryCatalog;
use alopex_sql::dialect::AlopexDialect;
use alopex_sql::executor::{ExecutionResult, Executor};
use alopex_sql::parser::Parser;
use alopex_sql::planner::Planner;
fn run_sql(
sql: &str,
) -> (
Executor<MemoryKV, MemoryCatalog>,
Arc<RwLock<MemoryCatalog>>,
) {
let store = Arc::new(MemoryKV::new());
let catalog = Arc::new(RwLock::new(MemoryCatalog::new()));
let mut executor = Executor::new(store, catalog.clone());
let dialect = AlopexDialect;
let stmts = Parser::parse_sql(&dialect, sql).expect("parse sql");
for stmt in stmts {
let plan = {
let guard = catalog.read().unwrap();
Planner::new(&*guard).plan(&stmt).expect("plan")
};
let _ = executor.execute(plan).expect("execute");
}
(executor, catalog)
}
#[cfg_attr(not(feature = "lane_ci"), ignore)]
#[test]
fn knn_optimization_without_index() {
let sql = r#"
CREATE TABLE items (id INT PRIMARY KEY, embedding VECTOR(2, L2));
INSERT INTO items (id, embedding) VALUES
(1, [0.0, 0.0]),
(2, [1.0, 0.0]),
(3, [2.0, 0.0]);
"#;
let (mut executor, catalog) = run_sql(sql);
let query =
"SELECT id FROM items ORDER BY vector_similarity(embedding, [0.5, 0.0], 'l2') ASC LIMIT 2";
let stmt = Parser::parse_sql(&AlopexDialect, query)
.unwrap()
.pop()
.unwrap();
let plan = {
let guard = catalog.read().unwrap();
Planner::new(&*guard).plan(&stmt).unwrap()
};
match executor.execute(plan).unwrap() {
ExecutionResult::Query(q) => {
let mut ids: Vec<i32> = q
.rows
.iter()
.map(|r| match &r[0] {
alopex_sql::storage::SqlValue::Integer(v) => *v,
other => panic!("unexpected {other:?}"),
})
.collect();
ids.sort_unstable();
assert_eq!(ids, vec![1, 2]);
}
other => panic!("unexpected {other:?}"),
}
}