nodedb_lite/error/
from_sql.rs1use nodedb_sql::SqlError;
6
7use super::LiteError;
8
9impl From<SqlError> for LiteError {
12 fn from(e: SqlError) -> Self {
13 match e {
14 mismatch @ (SqlError::TypeMismatch { .. }
16 | SqlError::VectorElementNotNumeric { .. }) => Self::TypeMismatch {
17 collection: String::new(),
18 detail: mismatch.to_string(),
19 },
20 range @ (SqlError::ConstantOverflow { .. }
22 | SqlError::NumericLiteralOutOfRange { .. }
23 | SqlError::IntegerOutOfRange { .. }
24 | SqlError::FloatOutOfRange { .. }
25 | SqlError::DecimalOutOfRange { .. }) => Self::NumericValueOutOfRange {
26 detail: range.to_string(),
27 },
28 data @ (SqlError::DivisionByZero | SqlError::DataException { .. }) => {
30 Self::DataException {
31 detail: data.to_string(),
32 }
33 }
34 SqlError::UndefinedObject { kind, name } => Self::UndefinedObject {
35 object: format!("{kind} \"{name}\""),
36 },
37 SqlError::ObjectNotInPrerequisiteState { object, detail } => {
38 Self::ObjectNotReady { object, detail }
39 }
40 SqlError::Unsupported { detail } => Self::Unsupported { detail },
41 SqlError::WrongObjectType { detail } => Self::BadRequest { detail },
44 refused @ (SqlError::SequencePerRowUnsupported { .. }
46 | SqlError::SearchFunctionOutsideSearch { .. }
47 | SqlError::UnsupportedConstraint { .. }
48 | SqlError::ConflictingEngineClause { .. }) => Self::Unsupported {
49 detail: refused.to_string(),
50 },
51 retry @ SqlError::RetryableSchemaChanged { .. } => Self::RetryableRefusal {
52 detail: retry.to_string(),
53 },
54 plan @ (SqlError::Parse { .. }
56 | SqlError::UnknownTable { .. }
57 | SqlError::UndefinedFunction { .. }
58 | SqlError::UnknownColumn { .. }
59 | SqlError::TextColumn { .. }
60 | SqlError::AmbiguousColumn { .. }
61 | SqlError::Arity { .. }
62 | SqlError::InvalidLimitValue { .. }
63 | SqlError::UnevaluableDefault { .. }
64 | SqlError::SetvalInColumnDefault { .. }
65 | SqlError::InvalidFunction { .. }
66 | SqlError::InvalidWindowFrame { .. }
67 | SqlError::MissingField { .. }
68 | SqlError::InsertColumnArityMismatch { .. }
69 | SqlError::PositionalKvInsertUnsupported { .. }
70 | SqlError::InvalidIdentifier { .. }
71 | SqlError::ReservedIdentifier { .. }
72 | SqlError::InvalidRecursiveSetOp { .. }
73 | SqlError::InvalidRecursiveSelfRef { .. }
74 | SqlError::RecursiveColumnMismatch { .. }
75 | SqlError::DuplicateRecursiveColumn { .. }
76 | SqlError::RecursionDepthExceeded { .. }
77 | SqlError::CollectionDeactivated { .. }) => Self::Query(plan.to_string()),
78 }
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use nodedb_types::error::{ErrorCode, NodeDbError};
85
86 use super::*;
87
88 fn public(e: SqlError) -> NodeDbError {
89 NodeDbError::from(LiteError::from(e))
90 }
91
92 #[test]
93 fn a_text_element_in_a_vector_literal_is_a_type_mismatch() {
94 let e = LiteError::from(SqlError::VectorElementNotNumeric {
95 column: "embedding".into(),
96 dim: 3,
97 element: "text 'a'".into(),
98 });
99 assert!(matches!(e, LiteError::TypeMismatch { .. }), "{e:?}");
100 assert_eq!(NodeDbError::from(e).code(), ErrorCode::TYPE_MISMATCH);
101 let plain = public(SqlError::TypeMismatch { detail: "x".into() });
102 assert_eq!(plain.code(), ErrorCode::TYPE_MISMATCH);
103 }
104
105 #[test]
106 fn an_out_of_range_value_is_numeric_value_out_of_range() {
107 for e in [
108 SqlError::NumericLiteralOutOfRange {
109 literal: "1e40".into(),
110 },
111 SqlError::ConstantOverflow { detail: "x".into() },
112 SqlError::IntegerOutOfRange {
113 column: "n".into(),
114 value: i64::MAX,
115 declared_type: "INTEGER",
116 },
117 ] {
118 let mapped = public(e);
119 assert_eq!(mapped.code(), ErrorCode::OVERFLOW);
120 assert!(mapped.is_overflow(), "{mapped}");
121 }
122 }
123
124 #[test]
125 fn a_failed_constant_is_a_data_exception() {
126 let mapped = public(SqlError::DataException { detail: "x".into() });
127 assert_eq!(mapped.code(), ErrorCode::DATA_EXCEPTION);
128 }
129
130 #[test]
131 fn a_statement_error_is_a_plan_error() {
132 for e in [
133 SqlError::Parse { detail: "x".into() },
134 SqlError::UndefinedFunction { name: "f".into() },
135 ] {
136 assert_eq!(public(e).code(), ErrorCode::PLAN_ERROR);
137 }
138 assert_eq!(
139 NodeDbError::from(LiteError::Query("x".into())).code(),
140 ErrorCode::PLAN_ERROR
141 );
142 }
143
144 #[test]
145 fn an_absent_object_is_an_undefined_object() {
146 let mapped = public(SqlError::UndefinedObject {
147 kind: "sequence",
148 name: "s".into(),
149 });
150 assert_eq!(mapped.code(), ErrorCode::UNDEFINED_OBJECT);
151 }
152}