alopex-sql 0.8.9

SQL parser components for the Alopex DB dialect
Documentation
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;
use alopex_sql::storage::SqlValue;

fn last_query(sql: &str) -> alopex_sql::executor::QueryResult {
    let statements = Parser::parse_sql(&AlopexDialect, sql).expect("parse sql");
    let catalog = Arc::new(RwLock::new(MemoryCatalog::new()));
    let store = Arc::new(MemoryKV::new());
    let mut executor = Executor::new(store, catalog.clone());

    let mut results = Vec::new();
    for statement in statements {
        let catalog = catalog.read().expect("catalog lock");
        let plan = Planner::new(&*catalog).plan(&statement).expect("plan sql");
        drop(catalog);
        results.push(executor.execute(plan).expect("execute sql"));
    }
    results
        .into_iter()
        .rev()
        .find_map(|result| match result {
            ExecutionResult::Query(query) => Some(query),
            _ => None,
        })
        .expect("query result")
}

#[test]
fn qualified_wildcards_expand_the_named_table_only() {
    let single = last_query(
        "
        CREATE TABLE users (id INT PRIMARY KEY, name TEXT);
        INSERT INTO users (id, name) VALUES (1, 'alice'), (2, 'bob');
        SELECT users.* FROM users ORDER BY users.id;
        ",
    );
    assert_eq!(
        single.rows,
        vec![
            vec![SqlValue::Integer(1), SqlValue::Text("alice".into())],
            vec![SqlValue::Integer(2), SqlValue::Text("bob".into())],
        ]
    );

    let joined = last_query(
        "
        CREATE TABLE a (id INT PRIMARY KEY, x TEXT);
        CREATE TABLE b (id INT PRIMARY KEY, y TEXT);
        INSERT INTO a (id, x) VALUES (1, 'left');
        INSERT INTO b (id, y) VALUES (1, 'right');
        SELECT a.*, b.y FROM a JOIN b ON a.id = b.id;
        ",
    );
    assert_eq!(
        joined.rows,
        vec![vec![
            SqlValue::Integer(1),
            SqlValue::Text("left".into()),
            SqlValue::Text("right".into()),
        ]]
    );
}