92 lines
2.5 KiB
Rust
Raw Normal View History

2026-06-03 12:02:14 +02:00
//! Hand-written query plan composed from `scan_atom`, `semijoin`, and `natural_join`.
//!
//! Schema:
2026-06-03 12:02:14 +02:00
//! - `author(name, book)`: who wrote each book
//! - `bestseller(book)`: the set of bestseller titles
//! - `price(book, dollars)`: price of each book
//!
2026-06-03 12:02:14 +02:00
//! Rule:
//! - `Q(name, book, dollars) :- author(name, book), bestseller(book), price(book, dollars).`
//! ("Authors of bestsellers along with each book's price.")
//!
//! The plan first scans each input table, then narrows `author` to authors of
//! bestsellers via a semijoin against `bestseller`, then attaches each book's
//! price via a natural join against `price`.
2026-06-03 12:02:14 +02:00
use query_ops::atom::{AtomPattern, Term, scan_atom};
use query_ops::join::{natural_join, semijoin};
use query_ops::table::Table;
use query_ops::value::Value;
2026-06-03 12:02:14 +02:00
fn s(x: &str) -> Value {
Value::Str(x.to_string())
}
2026-06-03 12:02:14 +02:00
fn i(x: i64) -> Value {
Value::Int(x)
}
#[test]
2026-06-03 12:02:14 +02:00
fn authors_of_bestsellers_with_price() {
let author = Table::from_rows(
2,
vec![
2026-06-03 12:02:14 +02:00
vec![s("Alice"), s("Foo")],
vec![s("Bob"), s("Bar")],
vec![s("Alice"), s("Baz")],
vec![s("Carol"), s("Qux")],
],
);
let bestseller = Table::from_rows(1, vec![vec![s("Foo")], vec![s("Baz")]]);
let price = Table::from_rows(
2,
vec![
vec![s("Foo"), i(25)],
vec![s("Bar"), i(15)],
vec![s("Baz"), i(30)],
vec![s("Qux"), i(20)],
],
);
2026-06-03 12:02:14 +02:00
let author_rel = scan_atom(
&author,
&AtomPattern {
2026-06-03 12:02:14 +02:00
columns: vec![Term::Var("name".to_string()), Term::Var("book".to_string())],
},
);
2026-06-03 12:02:14 +02:00
let bestseller_rel = scan_atom(
&bestseller,
&AtomPattern {
2026-06-03 12:02:14 +02:00
columns: vec![Term::Var("book".to_string())],
},
);
2026-06-03 12:02:14 +02:00
let price_rel = scan_atom(
&price,
&AtomPattern {
2026-06-03 12:02:14 +02:00
columns: vec![
Term::Var("book".to_string()),
Term::Var("dollars".to_string()),
],
},
);
2026-06-03 12:02:14 +02:00
let authors_of_bestsellers = semijoin(&author_rel, &bestseller_rel);
let result = natural_join(&authors_of_bestsellers, &price_rel);
assert_eq!(
result.columns,
vec![
"name".to_string(),
"book".to_string(),
"dollars".to_string()
],
);
assert_eq!(
2026-06-03 12:02:14 +02:00
result.rows,
vec![
2026-06-03 12:02:14 +02:00
vec![s("Alice"), s("Foo"), i(25)],
vec![s("Alice"), s("Baz"), i(30)],
],
);
}