use linkrs_core::Value;
use linkrs_query::executor::streaming::executor::StreamingExecutor;
use linkrs_query::executor::streaming::operators::base::OperatorBase;
use linkrs_query::executor::streaming::operators::source_operator::{
SourceOperator, SourceOperatorKind,
};
use linkrs_query::executor::streaming::operators::unary_operator::{
UnaryOperator, UnaryOperatorKind,
};
use linkrs_query::executor::streaming::slot::SlotLayout;
use std::sync::Arc;
fn make_scan(data: Vec<Vec<Value>>) -> StreamingExecutor {
StreamingExecutor::Source(
OperatorBase::new(0),
SourceOperator::new(
SourceOperatorKind::ScanVertices {
buffer: data,
current_index: 0,
col_names: vec![],
},
Arc::new(SlotLayout::from_names(&[])),
),
)
}
fn collect_all(mut exec: StreamingExecutor) -> Vec<Vec<Value>> {
exec.open().unwrap();
let mut rows = Vec::new();
while let Some(chunk) = exec.advance().unwrap() {
rows.extend(chunk.rows);
}
exec.close().unwrap();
rows
}
#[test]
fn contract_single_chunk() {
let data = vec![
vec![Value::Int(1), Value::string("a")],
vec![Value::Int(2), Value::string("b")],
];
let exec = make_scan(data.clone());
let rows = collect_all(exec);
assert_eq!(rows, data);
}
#[test]
fn contract_multi_chunk() {
let data: Vec<Vec<Value>> = (0..50)
.map(|i| vec![Value::Int(i), Value::string(format!("n{}", i))])
.collect();
let scan = make_scan(data.clone());
let exec = StreamingExecutor::Unary(
OperatorBase::new(1),
Box::new(scan),
UnaryOperator::new(
UnaryOperatorKind::Limit {
offset: 0,
limit: 50,
skipped: 0,
consumed: 0,
},
Arc::new(SlotLayout::from_names(&[])),
),
);
let rows = collect_all(exec);
assert_eq!(rows.len(), 50);
assert_eq!(rows, data);
}
#[test]
fn contract_empty_input_returns_none() {
let exec = make_scan(vec![]);
let rows = collect_all(exec);
assert!(rows.is_empty());
}
#[test]
fn contract_first_row_null() {
let data = vec![
vec![Value::Null(Default::default()), Value::string("null_id")],
vec![Value::Int(1), Value::string("a")],
];
let exec = make_scan(data.clone());
let rows = collect_all(exec);
assert_eq!(rows.len(), 2);
assert_eq!(rows[0][0], Value::Null(Default::default()));
assert_eq!(rows[1][0], Value::Int(1));
}
#[test]
fn contract_none_is_permanent_eof() {
let data = vec![vec![Value::Int(1), Value::string("a")]];
let exec = make_scan(data);
let rows = collect_all(exec);
assert_eq!(rows.len(), 1);
}
#[test]
fn contract_cancel_during_execution() {
let data: Vec<Vec<Value>> = (0..10)
.map(|i| vec![Value::Int(i), Value::string(format!("n{}", i))])
.collect();
let exec = make_scan(data);
let rows = collect_all(exec);
assert_eq!(rows.len(), 10);
}
#[test]
fn contract_early_stop() {
let data: Vec<Vec<Value>> = (0..100)
.map(|i| vec![Value::Int(i), Value::string(format!("n{}", i))])
.collect();
let mut exec = make_scan(data);
exec.open().unwrap();
let first = exec.advance().unwrap();
assert!(first.is_some());
exec.stop_tree().unwrap();
exec.close_tree().unwrap();
}
#[test]
fn contract_close_without_open() {
let mut exec = make_scan(vec![vec![Value::Int(1), Value::string("a")]]);
exec.close_tree().unwrap();
}
#[test]
fn contract_double_close() {
let mut exec = make_scan(vec![vec![Value::Int(1), Value::string("a")]]);
exec.open().unwrap();
let _ = exec.advance().unwrap();
exec.close().unwrap();
exec.close().unwrap();
}