Skip to content

Commit c8b9251

Browse files
feat(storage): improve error messages with actionable suggestions (#102)
* feat(storage): improve error messages with actionable suggestions - Add NXM-STOR-xxx error codes for programmatic handling - Include context-aware suggestions for common errors - Implement 'Did you mean?' feature using Levenshtein distance - Add comprehensive documentation and test coverage - Improve error formatting for better readability - Maintain backward compatibility with existing code * fix(executor): use KeyNotFound error for table lookup failures - Replace ReadError with key_not_found for table not found cases - Provide proper error code NXM-STOR-104 instead of NXM-STOR-103 - Add context to table lookup errors (SELECT, UPDATE, DELETE, etc.) - Improves error clarity for users when tables don't exist * chore(storage): export find_similar_keys for fuzzy matching - Export find_similar_keys function from error module - Enables 'Did you mean?' suggestions across the codebase - Required for table name fuzzy matching in executor * chore: run cargo fmt and clippy * fix(storage): refine KeyNotFound wording and sled Io error mapping - Adjust suggestion text to handle singular vs plural similar keys - Use open_error for sled::Error::Io to avoid mislabeling read-path failures Signed-off-by: noor05-creator <noorasif.noor05@gmail.com> * chore(executor): import find_similar_keys to simplify call sites Signed-off-by: noor05-creator <noorasif.noor05@gmail.com> --------- Signed-off-by: noor05-creator <noorasif.noor05@gmail.com>
1 parent d4b8d3d commit c8b9251

3 files changed

Lines changed: 546 additions & 38 deletions

File tree

nexum_core/src/executor/mod.rs

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::bridge::SemanticCache;
22
use crate::catalog::Catalog;
33
use crate::sql::types::{Column, DataType, SelectItem, Statement, Value};
4-
use crate::storage::{Result, StorageEngine, StorageError};
4+
use crate::storage::{find_similar_keys, Result, StorageEngine, StorageError};
55
use serde::{Deserialize, Serialize};
66
use std::time::Instant;
77

@@ -61,11 +61,14 @@ impl Executor {
6161
columns,
6262
values,
6363
} => {
64-
let schema = self
65-
.catalog
66-
.get_table(&table)?
67-
.ok_or_else(|| StorageError::ReadError(format!("Table {} not found", table)))?;
68-
64+
let schema = self.catalog.get_table(&table)?.ok_or_else(|| {
65+
let similar = self.catalog.list_tables().unwrap_or_default();
66+
StorageError::key_not_found(
67+
&table,
68+
"INSERT query execution",
69+
find_similar_keys(&table, &similar, 2),
70+
)
71+
})?;
6972
let prepared_rows = Self::prepare_insert_rows(&schema, &table, &columns, &values)?;
7073

7174
for row in prepared_rows {
@@ -88,10 +91,14 @@ impl Executor {
8891
order_by,
8992
limit,
9093
} => {
91-
let schema = self
92-
.catalog
93-
.get_table(&table)?
94-
.ok_or_else(|| StorageError::ReadError(format!("Table {} not found", table)))?;
94+
let schema = self.catalog.get_table(&table)?.ok_or_else(|| {
95+
let similar = self.catalog.list_tables().unwrap_or_default();
96+
StorageError::key_not_found(
97+
&table,
98+
"SELECT query execution",
99+
find_similar_keys(&table, &similar, 2),
100+
)
101+
})?;
95102

96103
let (projection_indices, output_columns) =
97104
Self::build_projection(&schema, &projection)?;
@@ -205,10 +212,14 @@ impl Executor {
205212
Ok(ExecutionResult::TableList { tables })
206213
}
207214
Statement::DescribeTable { name } => {
208-
let schema = self
209-
.catalog
210-
.get_table(&name)?
211-
.ok_or_else(|| StorageError::ReadError(format!("Table {} not found", name)))?;
215+
let schema = self.catalog.get_table(&name)?.ok_or_else(|| {
216+
let similar = self.catalog.list_tables().unwrap_or_default();
217+
StorageError::key_not_found(
218+
&name,
219+
"DESCRIBE command",
220+
find_similar_keys(&name, &similar, 2),
221+
)
222+
})?;
212223
Ok(ExecutionResult::TableDescription {
213224
table: name,
214225
columns: schema.columns,
@@ -223,7 +234,12 @@ impl Executor {
223234
rows: 0,
224235
});
225236
}
226-
return Err(StorageError::ReadError(format!("Table {} not found", name)));
237+
let similar = self.catalog.list_tables().unwrap_or_default();
238+
return Err(StorageError::key_not_found(
239+
&name,
240+
"DROP TABLE command",
241+
find_similar_keys(&name, &similar, 2),
242+
));
227243
}
228244

229245
let prefix = Self::table_data_prefix(&name);
@@ -245,10 +261,14 @@ impl Executor {
245261
table,
246262
where_clause,
247263
} => {
248-
let schema = self
249-
.catalog
250-
.get_table(&table)?
251-
.ok_or_else(|| StorageError::ReadError(format!("Table {} not found", table)))?;
264+
let schema = self.catalog.get_table(&table)?.ok_or_else(|| {
265+
let similar = self.catalog.list_tables().unwrap_or_default();
266+
StorageError::key_not_found(
267+
&table,
268+
"DELETE query execution",
269+
find_similar_keys(&table, &similar, 2),
270+
)
271+
})?;
252272

253273
let prefix = Self::table_data_prefix(&table);
254274

@@ -316,10 +336,14 @@ impl Executor {
316336
assignments,
317337
where_clause,
318338
} => {
319-
let schema = self
320-
.catalog
321-
.get_table(&table)?
322-
.ok_or_else(|| StorageError::ReadError(format!("Table {} not found", table)))?;
339+
let schema = self.catalog.get_table(&table)?.ok_or_else(|| {
340+
let similar = self.catalog.list_tables().unwrap_or_default();
341+
StorageError::key_not_found(
342+
&table,
343+
"UPDATE query execution",
344+
find_similar_keys(&table, &similar, 2),
345+
)
346+
})?;
323347

324348
let column_names: Vec<String> =
325349
schema.columns.iter().map(|c| c.name.clone()).collect();

0 commit comments

Comments
 (0)