uni_query/query/df_graph/locy_traits.rs
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2024-2026 Dragonscale Team
3
4//! Traits for native Locy command dispatch.
5//!
6//! `DerivedFactSource` provides read-only access to derived facts and the graph,
7//! replacing `CypherExecutor` for read operations in the native path.
8//!
9//! `LocyExecutionContext` extends it with write operations (mutations, savepoints,
10//! and strata re-evaluation) needed by ASSUME, DERIVE, and ABDUCE.
11
12use std::collections::HashMap;
13
14use arrow_array::RecordBatch;
15use async_trait::async_trait;
16use uni_common::Value;
17use uni_cypher::ast::{Expr, Pattern, Query};
18use uni_locy::{CompiledProgram, LocyConfig, LocyError, Row, SavepointId};
19
20use super::locy_delta::RowStore;
21
22/// Read-only access to derived facts and graph data.
23///
24/// Replaces `CypherExecutor` for read operations in the native command dispatch path.
25/// `lookup_derived` converts RecordBatch-based native facts to Row-based format internally.
26#[async_trait(?Send)]
27pub trait DerivedFactSource: Send + Sync {
28 /// Look up all facts for a rule. Returns Row-based results.
29 fn lookup_derived(&self, rule_name: &str) -> Result<Vec<Row>, LocyError>;
30
31 /// Look up all facts for a rule as raw RecordBatches (zero-copy from native store).
32 ///
33 /// Default implementation returns an error. Override in native adapters to read
34 /// directly from `DerivedStore` without converting to rows.
35 fn lookup_derived_batches(&self, _rule_name: &str) -> Result<Vec<RecordBatch>, LocyError> {
36 Err(LocyError::EvaluationError {
37 message: "lookup_derived_batches not implemented for this adapter".into(),
38 })
39 }
40
41 /// Execute a graph MATCH query with optional WHERE conditions.
42 ///
43 /// Returns raw `RecordBatch`es so the native path stays columnar.
44 /// Callers that need `Vec<Row>` must convert via `record_batches_to_locy_rows`.
45 ///
46 /// Used by SLG clause resolution, EXPLAIN re-execution, and delta resolution.
47 /// AST construction happens inside the adapter via `build_match_return_query`.
48 async fn execute_pattern(
49 &self,
50 pattern: &Pattern,
51 where_conditions: &[Expr],
52 ) -> Result<Vec<RecordBatch>, LocyError>;
53}
54
55/// DB operations needed by ASSUME, DERIVE, and ABDUCE.
56///
57/// Extends `DerivedFactSource` with write operations.
58#[async_trait(?Send)]
59pub trait LocyExecutionContext: DerivedFactSource {
60 /// Look up facts enriched with full node objects (for VID-based stores).
61 ///
62 /// Default implementation delegates to `lookup_derived()` (no enrichment needed
63 /// for the orchestrator path which already returns full `Value::Node` objects).
64 /// Override in native adapters to replace UInt64 VID values with full nodes so
65 /// that commands like DERIVE can access node properties.
66 async fn lookup_derived_enriched(&self, rule_name: &str) -> Result<Vec<Row>, LocyError> {
67 self.lookup_derived(rule_name)
68 }
69
70 /// Execute a pre-compiled Cypher read query (e.g. from a `CompiledCommand::Cypher`).
71 ///
72 /// Used by ASSUME/ABDUCE body dispatch where a Query AST is already available.
73 async fn execute_cypher_read(&self, ast: Query) -> Result<Vec<Row>, LocyError>;
74
75 /// Execute a mutation (CREATE/MERGE/DELETE), returning affected row count.
76 async fn execute_mutation(
77 &self,
78 ast: Query,
79 params: HashMap<String, Value>,
80 ) -> Result<usize, LocyError>;
81
82 /// Begin a savepoint for transactional rollback.
83 async fn begin_savepoint(&self) -> Result<SavepointId, LocyError>;
84
85 /// Rollback to a previously created savepoint.
86 async fn rollback_savepoint(&self, id: SavepointId) -> Result<(), LocyError>;
87
88 /// Re-evaluate all strata in the current (possibly mutated) state.
89 ///
90 /// Used by ASSUME and ABDUCE `validate_modification` to check hypothetical states.
91 /// Returns the row-based `RowStore` after convergence.
92 async fn re_evaluate_strata(
93 &self,
94 program: &CompiledProgram,
95 config: &LocyConfig,
96 ) -> Result<RowStore, LocyError>;
97}