selene-db-gql 1.3.0

ISO/IEC 39075:2024 GQL parser, planner, optimizer, and executor for selene-db.
Documentation
//! Executor subplan tests.

mod exec_common;

use exec_common::{ExecFixture, execute_pattern, node_ids_for, planned, props};
use selene_core::{LabelSet, Value};
use selene_gql::{ExecutorError, JoinTree, PipelineOp};

#[test]
fn subplan_recursively_executes_nested_pattern() {
    let fixture = ExecFixture::build();
    let mut plan = planned("MATCH (n:Person) RETURN n");
    let mut subplan = plan.clone();
    subplan.pipeline.clear();
    plan.pattern_plan.as_mut().expect("pattern plan").join_tree =
        JoinTree::Subplan(Box::new(subplan));
    let pattern = plan.pattern_plan.as_ref().expect("pattern plan");
    let ctx = fixture.context_caps(&plan);

    let table = execute_pattern(pattern, &ctx);

    assert_eq!(node_ids_for(&table, "n"), vec![Some(1), Some(2), Some(3)]);
}

#[test]
fn subplan_uses_same_tx_context_no_new_snapshot() {
    let fixture = ExecFixture::build();
    let mut plan = planned("MATCH (n:Person) RETURN n");
    let mut subplan = plan.clone();
    subplan.pipeline.clear();
    plan.pattern_plan.as_mut().expect("pattern plan").join_tree =
        JoinTree::Subplan(Box::new(subplan));
    let ctx = fixture.context_caps(&plan);

    {
        let mut txn = fixture.graph.begin_write();
        let mut mutator = txn.mutator();
        mutator
            .create_node(
                LabelSet::single(fixture.person.clone()),
                props([(fixture.score.clone(), Value::Int(12))]),
            )
            .expect("late node inserts");
        txn.commit().expect("late update commits");
    }

    let pattern = plan.pattern_plan.as_ref().expect("pattern plan");
    let table = execute_pattern(pattern, &ctx);

    assert_eq!(node_ids_for(&table, "n"), vec![Some(1), Some(2), Some(3)]);
}

#[test]
fn subplan_with_pipeline_ops_returns_implementation_defined() {
    let fixture = ExecFixture::build();
    let mut plan = planned("MATCH (n:Person) RETURN n");
    let mut subplan = plan.clone();
    subplan.pipeline.push(PipelineOp::Distinct);
    plan.pattern_plan.as_mut().expect("pattern plan").join_tree =
        JoinTree::Subplan(Box::new(subplan));
    let pattern = plan.pattern_plan.as_ref().expect("pattern plan");
    let ctx = fixture.context_caps(&plan);

    let err = selene_gql::execute_pattern(pattern, &ctx).expect_err("guard fires");

    assert!(matches!(
        err,
        ExecutorError::ImplementationDefined {
            detail: "Subplan pipeline ops not yet supported"
        }
    ));
}

#[test]
fn subplan_with_seed_executes_correlated_rows() {
    let fixture = ExecFixture::build();
    let mut plan = planned("MATCH (a:Person) OPTIONAL MATCH (a)-[:KNOWS]->(b:Sensor) RETURN a, b");
    let mut subplan = planned("MATCH (a:Person)-[:KNOWS]->(b:Sensor) RETURN a, b");
    subplan.pipeline.clear();
    let pattern_plan = plan.pattern_plan.as_mut().expect("pattern plan");
    let JoinTree::Outer { right, .. } = &mut pattern_plan.join_tree else {
        panic!("expected outer tree");
    };
    **right = JoinTree::Subplan(Box::new(subplan));
    let pattern = plan.pattern_plan.as_ref().expect("pattern plan");
    let ctx = fixture.context_caps(&plan);

    let table = selene_gql::execute_pattern(pattern, &ctx).expect("seeded subplan executes");

    assert_eq!(node_ids_for(&table, "a"), vec![Some(1), Some(2), Some(3)]);
    assert_eq!(node_ids_for(&table, "b"), vec![None, Some(4), None]);
}