Skip to main content

lora_executor/
errors.rs

1use crate::value::LoraValue;
2use lora_compiler::physical::PhysicalNodeId;
3use lora_store::{NodeId, RelationshipId};
4use thiserror::Error;
5
6#[derive(Debug, Error)]
7pub enum ExecutorError {
8    #[error("this query modifies the graph, but it was executed in read-only mode (CREATE at plan node {node_id:?})")]
9    ReadOnlyCreate { node_id: PhysicalNodeId },
10
11    #[error("this query modifies the graph, but it was executed in read-only mode (MERGE at plan node {node_id:?})")]
12    ReadOnlyMerge { node_id: PhysicalNodeId },
13
14    #[error("this query modifies the graph, but it was executed in read-only mode (DELETE at plan node {node_id:?})")]
15    ReadOnlyDelete { node_id: PhysicalNodeId },
16
17    #[error("this query modifies the graph, but it was executed in read-only mode (SET at plan node {node_id:?})")]
18    ReadOnlySet { node_id: PhysicalNodeId },
19
20    #[error("this query modifies the graph, but it was executed in read-only mode (REMOVE at plan node {node_id:?})")]
21    ReadOnlyRemove { node_id: PhysicalNodeId },
22
23    #[error("this query modifies the graph, but it was executed in read-only mode (FOREACH at plan node {node_id:?})")]
24    ReadOnlyForeach { node_id: PhysicalNodeId },
25
26    #[error("expected variable {var} to contain a node before expanding a relationship, but found {found}")]
27    ExpectedNodeForExpand { var: String, found: String },
28
29    #[error("CREATE/MERGE expected variable {var} to be bound to a node, but found {found}")]
30    ExpectedNodeForCreate { var: String, found: String },
31
32    #[error(
33        "CREATE/MERGE expected variable {var} to be bound to a relationship, but found {found}"
34    )]
35    ExpectedRelationshipForCreate { var: String, found: String },
36
37    #[error("expected a map value for properties, but found {found}")]
38    ExpectedPropertyMap { found: String },
39
40    #[error("grouping could not be executed because the group-by expression was not lowered to a variable")]
41    GroupByNotLowered,
42
43    #[error("aggregation could not be executed because the aggregate expression was not lowered to a variable")]
44    AggregateNotLowered,
45
46    #[error("variable-length relationships are not supported in CREATE")]
47    UnsupportedCreateRelationshipRange,
48
49    #[error("a CREATE relationship is missing its relationship type")]
50    MissingRelationshipType,
51
52    #[error("failed to create relationship `{rel_type}` from node {src} to node {dst}")]
53    RelationshipCreateFailed {
54        src: u64,
55        dst: u64,
56        rel_type: String,
57    },
58
59    #[error("failed to create node because storage is exhausted")]
60    NodeCreateFailed,
61
62    #[error("cannot delete node {node_id} because it still has relationships; use DETACH DELETE to remove the node and its relationships")]
63    DeleteNodeWithRelationships { node_id: NodeId },
64
65    #[error("failed to delete relationship {rel_id}")]
66    DeleteRelationshipFailed { rel_id: RelationshipId },
67
68    #[error(
69        "DELETE can only be used with nodes, relationships, or lists of them, but found {found}"
70    )]
71    InvalidDeleteTarget { found: String },
72
73    #[error("REMOVE label can only be applied to a node, but found {found}")]
74    ExpectedNodeForRemoveLabels { found: String },
75
76    #[error("REMOVE referenced variable {var}, but that variable is not bound in the current row")]
77    UnboundVariableForRemove { var: String },
78
79    #[error("SET label can only be applied to a node, but found {found}")]
80    ExpectedNodeForSetLabels { found: String },
81
82    #[error("SET referenced variable {var}, but that variable is not bound in the current row")]
83    UnboundVariableForSet { var: String },
84
85    #[error("SET target must be a node or relationship, but found {found}")]
86    InvalidSetTarget { found: String },
87
88    #[error("REMOVE property currently only supports direct property expressions like n.name or r.weight")]
89    UnsupportedRemoveTarget,
90
91    #[error("REMOVE target must be a node or relationship property, but found {found}")]
92    InvalidRemoveTarget { found: String },
93
94    #[error(
95        "SET property currently only supports direct property expressions like n.name or r.weight"
96    )]
97    UnsupportedSetTarget,
98
99    #[error("expected variable {var} to contain a relationship during EXPAND, but found {found}")]
100    ExpectedRelationshipForExpand { var: String, found: String },
101
102    #[error("query deadline exceeded")]
103    QueryTimeout,
104
105    /// A registered constraint rejected a proposed mutation. The
106    /// payload already includes the GQLSTATUS code (22N77/78/79) so the
107    /// outer error format is just the inner message.
108    #[error("{0}")]
109    ConstraintViolation(String),
110
111    #[error("{0}")]
112    RuntimeError(String),
113}
114
115pub type ExecResult<T> = Result<T, ExecutorError>;
116
117impl ExecutorError {
118    /// The error for a failed expression evaluation: the query timeout
119    /// when the expression stopped on the deadline, a runtime error
120    /// carrying its message otherwise.
121    pub(crate) fn from_eval(message: String) -> Self {
122        if message == crate::eval::DEADLINE_EXCEEDED {
123            ExecutorError::QueryTimeout
124        } else {
125            ExecutorError::RuntimeError(message)
126        }
127    }
128}
129
130pub fn value_kind(value: &LoraValue) -> String {
131    match value {
132        LoraValue::Null => "null".into(),
133        LoraValue::Bool(_) => "bool".into(),
134        LoraValue::Int(_) => "int".into(),
135        LoraValue::Float(_) => "float".into(),
136        LoraValue::String(_) => "string".into(),
137        LoraValue::Binary(_) => "binary".into(),
138        LoraValue::List(_) => "list".into(),
139        LoraValue::Map(_) => "map".into(),
140        LoraValue::Node(_) => "node".into(),
141        LoraValue::Relationship(_) => "relationship".into(),
142        LoraValue::Path(_) => "path".into(),
143        LoraValue::Date(_) => "date".into(),
144        LoraValue::DateTime(_) => "datetime".into(),
145        LoraValue::LocalDateTime(_) => "localdatetime".into(),
146        LoraValue::Time(_) => "time".into(),
147        LoraValue::LocalTime(_) => "localtime".into(),
148        LoraValue::Duration(_) => "duration".into(),
149        LoraValue::Point(_) => "point".into(),
150        LoraValue::Vector(_) => "vector".into(),
151    }
152}