llkv-runtime 0.8.5-alpha

Execution runtime for the LLKV toolkit.
Documentation
use std::sync::Arc;

use arrow::datatypes::DataType;
use llkv_result::Error;
use llkv_runtime::{
    CreateIndexPlan, IndexColumnPlan, PlanValue, RuntimeContext, RuntimeStatementResult, row,
};
use llkv_storage::pager::{BoxedPager, MemPager};
use llkv_table::CatalogDdl;

#[test]
fn multi_column_unique_survives_restart() {
    let pager = Arc::new(BoxedPager::from_arc(Arc::new(MemPager::default())));
    let context = Arc::new(RuntimeContext::new(Arc::clone(&pager)));

    context
        .create_table_builder("people")
        .with_column("first_name", DataType::Utf8)
        .with_column("last_name", DataType::Utf8)
        .with_column("age", DataType::Int64)
        .finish()
        .expect("create table");

    let table = context.table("people").expect("table handle");
    table
        .insert_rows([
            row()
                .with("first_name", "Ada")
                .with("last_name", "Lovelace")
                .with("age", 36_i64),
            row()
                .with("first_name", "Grace")
                .with("last_name", "Hopper")
                .with("age", 44_i64),
        ])
        .expect("initial insert");

    let create_index_plan = CreateIndexPlan::new("people")
        .with_name(Some("uniq_fullname".into()))
        .with_unique(true)
        .with_columns(vec![
            IndexColumnPlan::new("first_name"),
            IndexColumnPlan::new("last_name"),
        ]);

    let index_result = context
        .create_index(create_index_plan)
        .expect("create index");
    assert!(matches!(
        index_result,
        RuntimeStatementResult::CreateIndex { .. }
    ));

    drop(table);
    drop(context);

    let context = Arc::new(RuntimeContext::new(pager));
    let table = context.table("people").expect("table handle");

    let duplicate = table.insert_rows([row()
        .with("first_name", "Ada")
        .with("last_name", "Lovelace")
        .with("age", 40_i64)]);

    match duplicate {
        Err(Error::ConstraintError(message)) => assert!(
            message.contains("first_name") && message.contains("last_name"),
            "unexpected message: {message}"
        ),
        other => panic!("expected constraint error, got {:?}", other),
    }

    let distinct = table
        .insert_rows([row()
            .with("first_name", "Ada")
            .with("last_name", "Byron")
            .with("age", 40_i64)])
        .expect("insert distinct");
    assert!(matches!(
        distinct,
        RuntimeStatementResult::Insert {
            rows_inserted: 1,
            ..
        }
    ));

    let rows = table
        .lazy()
        .expect("lazy scan")
        .select_columns(["first_name", "last_name", "age"])
        .collect_rows_vec()
        .expect("collect rows");
    assert!(rows.contains(&vec![
        PlanValue::String("Ada".into()),
        PlanValue::String("Byron".into()),
        PlanValue::Integer(40),
    ]));
}