tempest-engine 0.0.2

Relational database engine for TempestDB
Documentation
use tempest_core::test_utils::setup_tracing;
use tempest_io::VirtualIo;
use tempest_rt::block_on;

use crate::{Engine, query::QueryResult, types::TempestValue};

use super::{get_rows, open_engine};

// -- helpers --

/// Sets up `main.Point struct(Int64, Int64)` and `main.points : main.Point { primary key (0) }`.
async fn setup_point_schema(engine: &mut Engine<VirtualIo>) {
    engine.execute("create database main;").await.unwrap();
    engine
        .execute("create type main.Point struct(Int64, Int64);")
        .await
        .unwrap();
    engine
        .execute("create table main.points : main.Point { primary key (0) };")
        .await
        .unwrap();
}

/// Sets up `main.Pair[T, U] struct(T, U)` and `main.pairs : main.Pair[Int64, Int64] { primary key (0) }`.
async fn setup_pair_schema(engine: &mut Engine<VirtualIo>) {
    engine.execute("create database main;").await.unwrap();
    engine
        .execute("create type main.Pair[T, U] struct(T, U);")
        .await
        .unwrap();
    engine
        .execute("create table main.pairs : main.Pair[Int64, Int64] { primary key (0) };")
        .await
        .unwrap();
}

/// Inserts `(1, 10)`, `(2, 20)`, `(3, 30)` into `table`.
async fn insert_three_rows(engine: &mut Engine<VirtualIo>, table: &str) {
    engine
        .execute(&format!("insert into {} (1, 10);", table))
        .await
        .unwrap();
    engine
        .execute(&format!("insert into {} (2, 20);", table))
        .await
        .unwrap();
    engine
        .execute(&format!("insert into {} (3, 30);", table))
        .await
        .unwrap();
}

// -- unit struct --

#[test]
fn test_create_unit_struct() {
    setup_tracing();
    block_on(VirtualIo::default(), async {
        let mut engine = open_engine().await;
        engine.execute("create database main;").await.unwrap();
        let results = engine
            .execute("create type main.Empty struct;")
            .await
            .unwrap();
        assert!(matches!(results[0], QueryResult::Empty));
        engine.shutdown().await.unwrap();
    });
}

// -- concrete Point struct(Int64, Int64) --

#[test]
fn test_create_tuple_struct() {
    setup_tracing();
    block_on(VirtualIo::default(), async {
        let mut engine = open_engine().await;
        engine.execute("create database main;").await.unwrap();
        let type_result = engine
            .execute("create type main.Point struct(Int64, Int64);")
            .await
            .unwrap();
        assert!(matches!(type_result[0], QueryResult::Empty));
        let table_result = engine
            .execute("create table main.points : main.Point { primary key (0) };")
            .await
            .unwrap();
        assert!(matches!(table_result[0], QueryResult::Empty));
        engine.shutdown().await.unwrap();
    });
}

#[test]
fn test_insert_into_tuple_table() {
    setup_tracing();
    block_on(VirtualIo::default(), async {
        let mut engine = open_engine().await;
        setup_point_schema(&mut engine).await;
        let results = engine
            .execute("insert into main.points (1, 42);")
            .await
            .unwrap();
        assert!(matches!(results[0], QueryResult::Empty));
        engine.shutdown().await.unwrap();
    });
}

#[test]
fn test_select_all_from_tuple_table() {
    setup_tracing();
    block_on(VirtualIo::default(), async {
        let mut engine = open_engine().await;
        setup_point_schema(&mut engine).await;
        insert_three_rows(&mut engine, "main.points").await;
        let results = engine.execute("select * from main.points;").await.unwrap();
        let rows = get_rows(&results[0]);
        assert_eq!(rows.len(), 3);
        assert_eq!(rows[0][0], TempestValue::Int64(1));
        assert_eq!(rows[0][1], TempestValue::Int64(10));
        assert_eq!(rows[1][0], TempestValue::Int64(2));
        assert_eq!(rows[1][1], TempestValue::Int64(20));
        assert_eq!(rows[2][0], TempestValue::Int64(3));
        assert_eq!(rows[2][1], TempestValue::Int64(30));
        engine.shutdown().await.unwrap();
    });
}

#[test]
fn test_select_empty_tuple_table() {
    setup_tracing();
    block_on(VirtualIo::default(), async {
        let mut engine = open_engine().await;
        setup_point_schema(&mut engine).await;
        let results = engine.execute("select * from main.points;").await.unwrap();
        let rows = get_rows(&results[0]);
        assert_eq!(rows.len(), 0);
        engine.shutdown().await.unwrap();
    });
}

#[test]
fn test_delete_all_from_tuple_table() {
    setup_tracing();
    block_on(VirtualIo::default(), async {
        let mut engine = open_engine().await;
        setup_point_schema(&mut engine).await;
        insert_three_rows(&mut engine, "main.points").await;
        let del_results = engine.execute("delete from main.points;").await.unwrap();
        assert!(matches!(del_results[0], QueryResult::RowsChanged(3)));
        let results = engine.execute("select * from main.points;").await.unwrap();
        assert_eq!(get_rows(&results[0]).len(), 0);
        engine.shutdown().await.unwrap();
    });
}

// These require qualified field access (`p.0`) which is not yet implemented.
#[test]
fn test_select_where_tuple_field() {
    setup_tracing();
    block_on(VirtualIo::default(), async {
        let mut engine = open_engine().await;
        setup_point_schema(&mut engine).await;
        insert_three_rows(&mut engine, "main.points").await;
        let results = engine
            .execute("select * from main.points as p where p.0 = 2;")
            .await
            .unwrap();
        let rows = get_rows(&results[0]);
        assert_eq!(rows.len(), 1);
        assert_eq!(rows[0][0], TempestValue::Int64(2));
        assert_eq!(rows[0][1], TempestValue::Int64(20));
        engine.shutdown().await.unwrap();
    });
}

#[test]
fn test_delete_where_tuple_field() {
    setup_tracing();
    block_on(VirtualIo::default(), async {
        let mut engine = open_engine().await;
        setup_point_schema(&mut engine).await;
        insert_three_rows(&mut engine, "main.points").await;
        let del_results = engine
            .execute("delete from main.points as p where p.0 = 2;")
            .await
            .unwrap();
        assert!(matches!(del_results[0], QueryResult::RowsChanged(1)));
        let remaining = engine.execute("select * from main.points;").await.unwrap();
        let rows = get_rows(&remaining[0]);
        assert_eq!(rows.len(), 2);
        assert_eq!(rows[0][0], TempestValue::Int64(1));
        assert_eq!(rows[1][0], TempestValue::Int64(3));
        engine.shutdown().await.unwrap();
    });
}

// -- generic Pair[T, U] struct(T, U) --

#[test]
fn test_create_generic_tuple_struct() {
    setup_tracing();
    block_on(VirtualIo::default(), async {
        let mut engine = open_engine().await;
        engine.execute("create database main;").await.unwrap();
        let type_result = engine
            .execute("create type main.Pair[T, U] struct(T, U);")
            .await
            .unwrap();
        assert!(matches!(type_result[0], QueryResult::Empty));
        let table_result = engine
            .execute("create table main.pairs : main.Pair[Int64, Int64] { primary key (0) };")
            .await
            .unwrap();
        assert!(matches!(table_result[0], QueryResult::Empty));
        engine.shutdown().await.unwrap();
    });
}

#[test]
fn test_insert_into_generic_tuple_table() {
    setup_tracing();
    block_on(VirtualIo::default(), async {
        let mut engine = open_engine().await;
        setup_pair_schema(&mut engine).await;
        let results = engine
            .execute("insert into main.pairs (1, 42);")
            .await
            .unwrap();
        assert!(matches!(results[0], QueryResult::Empty));
        engine.shutdown().await.unwrap();
    });
}

#[test]
fn test_select_all_from_generic_tuple_table() {
    setup_tracing();
    block_on(VirtualIo::default(), async {
        let mut engine = open_engine().await;
        setup_pair_schema(&mut engine).await;
        insert_three_rows(&mut engine, "main.pairs").await;
        let results = engine.execute("select * from main.pairs;").await.unwrap();
        let rows = get_rows(&results[0]);
        assert_eq!(rows.len(), 3);
        assert_eq!(rows[0][0], TempestValue::Int64(1));
        assert_eq!(rows[0][1], TempestValue::Int64(10));
        assert_eq!(rows[1][0], TempestValue::Int64(2));
        assert_eq!(rows[1][1], TempestValue::Int64(20));
        assert_eq!(rows[2][0], TempestValue::Int64(3));
        assert_eq!(rows[2][1], TempestValue::Int64(30));
        engine.shutdown().await.unwrap();
    });
}

#[test]
fn test_select_empty_generic_tuple_table() {
    setup_tracing();
    block_on(VirtualIo::default(), async {
        let mut engine = open_engine().await;
        setup_pair_schema(&mut engine).await;
        let results = engine.execute("select * from main.pairs;").await.unwrap();
        assert_eq!(get_rows(&results[0]).len(), 0);
        engine.shutdown().await.unwrap();
    });
}

#[test]
fn test_delete_all_from_generic_tuple_table() {
    setup_tracing();
    block_on(VirtualIo::default(), async {
        let mut engine = open_engine().await;
        setup_pair_schema(&mut engine).await;
        insert_three_rows(&mut engine, "main.pairs").await;
        let del_results = engine.execute("delete from main.pairs;").await.unwrap();
        assert!(matches!(del_results[0], QueryResult::RowsChanged(3)));
        let results = engine.execute("select * from main.pairs;").await.unwrap();
        assert_eq!(get_rows(&results[0]).len(), 0);
        engine.shutdown().await.unwrap();
    });
}

#[test]
fn test_select_where_generic_tuple_field() {
    setup_tracing();
    block_on(VirtualIo::default(), async {
        let mut engine = open_engine().await;
        setup_pair_schema(&mut engine).await;
        insert_three_rows(&mut engine, "main.pairs").await;
        let results = engine
            .execute("select * from main.pairs as p where p.0 = 2;")
            .await
            .unwrap();
        let rows = get_rows(&results[0]);
        assert_eq!(rows.len(), 1);
        assert_eq!(rows[0][0], TempestValue::Int64(2));
        assert_eq!(rows[0][1], TempestValue::Int64(20));
        engine.shutdown().await.unwrap();
    });
}

#[test]
fn test_delete_where_generic_tuple_field() {
    setup_tracing();
    block_on(VirtualIo::default(), async {
        let mut engine = open_engine().await;
        setup_pair_schema(&mut engine).await;
        insert_three_rows(&mut engine, "main.pairs").await;
        let del_results = engine
            .execute("delete from main.pairs as p where p.0 = 2;")
            .await
            .unwrap();
        assert!(matches!(del_results[0], QueryResult::RowsChanged(1)));
        let remaining = engine.execute("select * from main.pairs;").await.unwrap();
        let rows = get_rows(&remaining[0]);
        assert_eq!(rows.len(), 2);
        assert_eq!(rows[0][0], TempestValue::Int64(1));
        assert_eq!(rows[1][0], TempestValue::Int64(3));
        engine.shutdown().await.unwrap();
    });
}