plexus-engine 0.3.4

Engine integration traits for consuming Plexus plans
Documentation
use std::path::PathBuf;

use plexus_engine::{
    flagship_graph_rag_reference_contract, proof_fixture_graph, IndependentConsumerEngine,
    PlanEngine, Value,
};
use plexus_serde::{
    current_plan_version, CmpOp, ColDef, ColKind, Expr, LogicalType, Op, Plan, SortDir,
};
use serde::Serialize;

#[derive(Debug, Serialize)]
struct IndependentConsumerProofReport {
    proof_id: String,
    consumer: String,
    implementation: String,
    supported_subset: SupportedSubset,
    reference_contract: plexus_engine::FlagshipGraphRagReferenceContract,
    case_sources: Vec<String>,
    total: usize,
    passed: usize,
    failed: usize,
    cases: Vec<IndependentConsumerProofCase>,
}

#[derive(Debug, Serialize)]
struct SupportedSubset {
    ops: Vec<&'static str>,
    exprs: Vec<&'static str>,
    notes: Vec<&'static str>,
}

#[derive(Debug, Serialize)]
struct IndependentConsumerProofCase {
    case: String,
    passed: bool,
    error: Option<String>,
}

fn main() -> Result<(), String> {
    let case_paths = proof_case_paths();
    let cases = proof_cases();

    let mut reports = Vec::with_capacity(cases.len());
    let mut passed = 0usize;
    for case in cases {
        let mut engine = IndependentConsumerEngine::new(proof_fixture_graph());
        let outcome = engine
            .execute_plan(&case.plan)
            .map_err(|err| err.to_string());
        let assertion = match outcome {
            Ok(result) if result.rows == case.expected_rows => Ok(()),
            Ok(result) => Err(format!(
                "row mismatch: expected {:?}, got {:?}",
                case.expected_rows, result.rows
            )),
            Err(err) => Err(err),
        };
        if assertion.is_ok() {
            passed += 1;
        }
        reports.push(IndependentConsumerProofCase {
            case: case.name,
            passed: assertion.is_ok(),
            error: assertion.err(),
        });
    }

    let report = IndependentConsumerProofReport {
        proof_id: "plexus-independent-consumer-proof-v1".to_string(),
        consumer: "independent-consumer-example".to_string(),
        implementation: "independent PlanEngine implementation with a private flat graph store"
            .to_string(),
        supported_subset: SupportedSubset {
            ops: vec![
                "ScanNodes",
                "Expand",
                "OptionalExpand",
                "Filter",
                "Project",
                "Sort",
                "Return",
            ],
            exprs: vec![
                "ColRef",
                "PropAccess",
                "IntLiteral",
                "FloatLiteral",
                "BoolLiteral",
                "StringLiteral",
                "NullLiteral",
                "Cmp",
            ],
            notes: vec![
                "This proof intentionally covers a bounded core-read subset only.",
                "The example does not reuse the reference engine execution path.",
                "The checked-in JSON artifact is produced by running this example.",
            ],
        },
        reference_contract: flagship_graph_rag_reference_contract(),
        case_sources: case_paths
            .iter()
            .map(|path| path.display().to_string())
            .collect(),
        total: reports.len(),
        passed,
        failed: reports.len().saturating_sub(passed),
        cases: reports,
    };

    println!(
        "{}",
        serde_json::to_string_pretty(&report).map_err(|err| err.to_string())?
    );
    Ok(())
}

fn proof_case_paths() -> Vec<PathBuf> {
    let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("src/tests/fixtures/readonly");
    vec![
        root.join("001_match_return_order_by.case"),
        root.join("002_match_expand_filter.case"),
        root.join("003_optional_match_null_projection.case"),
    ]
}

struct ProofCase {
    name: String,
    plan: Plan,
    expected_rows: Vec<Vec<Value>>,
}

fn proof_cases() -> Vec<ProofCase> {
    let value_col = || ColDef {
        name: "value".to_string(),
        kind: ColKind::Value,
        logical_type: LogicalType::Unknown,
    };
    let node_col = |name: &str| ColDef {
        name: name.to_string(),
        kind: ColKind::Node,
        logical_type: LogicalType::Unknown,
    };
    let rel_col = |name: &str| ColDef {
        name: name.to_string(),
        kind: ColKind::Rel,
        logical_type: LogicalType::Unknown,
    };
    let version = current_plan_version("independent-consumer-proof");

    vec![
        ProofCase {
            name: "match-return-order-by".to_string(),
            plan: Plan {
                version: version.clone(),
                ops: vec![
                    Op::ScanNodes {
                        labels: vec!["Person".to_string()],
                        schema: vec![node_col("n")],
                        must_labels: vec!["Person".to_string()],
                        forbidden_labels: vec![],
                        est_rows: -1,
                        selectivity: 1.0,
                        graph_ref: None,
                    },
                    Op::Project {
                        input: 0,
                        exprs: vec![Expr::PropAccess {
                            col: 0,
                            prop: "name".to_string(),
                        }],
                        schema: vec![value_col()],
                    },
                    Op::Sort {
                        input: 1,
                        keys: vec![0],
                        dirs: vec![SortDir::Asc],
                    },
                    Op::Return { input: 2 },
                ],
                root_op: 3,
            },
            expected_rows: vec![
                vec![Value::String("Alice".to_string())],
                vec![Value::String("Bob".to_string())],
            ],
        },
        ProofCase {
            name: "match-expand-filter".to_string(),
            plan: Plan {
                version: version.clone(),
                ops: vec![
                    Op::ScanNodes {
                        labels: vec!["Person".to_string()],
                        schema: vec![node_col("n")],
                        must_labels: vec!["Person".to_string()],
                        forbidden_labels: vec![],
                        est_rows: -1,
                        selectivity: 1.0,
                        graph_ref: None,
                    },
                    Op::Expand {
                        input: 0,
                        src_col: 0,
                        types: vec!["KNOWS".to_string()],
                        dir: plexus_serde::ExpandDir::Out,
                        schema: vec![node_col("n"), rel_col("r"), node_col("m")],
                        src_var: "n".to_string(),
                        rel_var: "r".to_string(),
                        dst_var: "m".to_string(),
                        legal_src_labels: vec!["Person".to_string()],
                        legal_dst_labels: vec!["Person".to_string()],
                        est_degree: 1.0,
                        graph_ref: None,
                    },
                    Op::Filter {
                        input: 1,
                        predicate: Expr::Cmp {
                            op: CmpOp::Gt,
                            lhs: Box::new(Expr::PropAccess {
                                col: 2,
                                prop: "age".to_string(),
                            }),
                            rhs: Box::new(Expr::IntLiteral(30)),
                        },
                    },
                    Op::Project {
                        input: 2,
                        exprs: vec![Expr::PropAccess {
                            col: 0,
                            prop: "name".to_string(),
                        }],
                        schema: vec![value_col()],
                    },
                    Op::Sort {
                        input: 3,
                        keys: vec![0],
                        dirs: vec![SortDir::Asc],
                    },
                    Op::Return { input: 4 },
                ],
                root_op: 5,
            },
            expected_rows: vec![vec![Value::String("Alice".to_string())]],
        },
        ProofCase {
            name: "optional-match-null-projection".to_string(),
            plan: Plan {
                version,
                ops: vec![
                    Op::ScanNodes {
                        labels: vec!["Person".to_string()],
                        schema: vec![node_col("n")],
                        must_labels: vec!["Person".to_string()],
                        forbidden_labels: vec![],
                        est_rows: -1,
                        selectivity: 1.0,
                        graph_ref: None,
                    },
                    Op::OptionalExpand {
                        input: 0,
                        src_col: 0,
                        types: vec!["WORKS_AT".to_string()],
                        dir: plexus_serde::ExpandDir::Out,
                        schema: vec![node_col("n"), rel_col("r"), node_col("c")],
                        src_var: "n".to_string(),
                        rel_var: "r".to_string(),
                        dst_var: "c".to_string(),
                        legal_src_labels: vec!["Person".to_string()],
                        legal_dst_labels: vec!["Company".to_string()],
                        graph_ref: None,
                    },
                    Op::Project {
                        input: 1,
                        exprs: vec![Expr::PropAccess {
                            col: 2,
                            prop: "name".to_string(),
                        }],
                        schema: vec![value_col()],
                    },
                    Op::Sort {
                        input: 2,
                        keys: vec![0],
                        dirs: vec![SortDir::Asc],
                    },
                    Op::Return { input: 3 },
                ],
                root_op: 4,
            },
            expected_rows: vec![vec![Value::Null], vec![Value::String("Acme".to_string())]],
        },
    ]
}