Skip to main content

powdb_query/
result.rs

1use std::fmt;
2
3use powdb_storage::types::Value;
4
5/// The result of executing a query.
6#[derive(Debug)]
7pub enum QueryResult {
8    Rows {
9        columns: Vec<String>,
10        rows: Vec<Vec<Value>>,
11    },
12    Scalar(Value),   // count, avg, etc.
13    Modified(u64),   // insert/update/delete — number of rows affected
14    Created(String), // DDL — type name created
15    Executed {
16        message: String,
17    }, // DDL — alter/drop feedback
18}
19
20impl QueryResult {
21    pub fn row_count(&self) -> usize {
22        match self {
23            QueryResult::Rows { rows, .. } => rows.len(),
24            QueryResult::Scalar(_) => 1,
25            QueryResult::Modified(n) => *n as usize,
26            QueryResult::Created(_) => 0,
27            QueryResult::Executed { .. } => 0,
28        }
29    }
30}
31
32/// Typed error enum for query execution failures.
33///
34/// Replaces the previous `Result<QueryResult, String>` pattern with
35/// structured variants that callers can programmatically match on.
36/// The `From<String>` impl enables gradual migration — existing
37/// `Err(format!(...))` sites continue to compile via `?` propagation.
38#[derive(Debug, Clone, PartialEq)]
39pub enum QueryError {
40    /// Table does not exist.
41    TableNotFound(String),
42    /// Column does not exist on table.
43    ColumnNotFound { table: String, column: String },
44    /// Type mismatch in expression.
45    TypeError(String),
46    /// Join result exceeded MAX_JOIN_ROWS.
47    JoinLimitExceeded,
48    /// Sort exceeded MAX_SORT_ROWS.
49    SortLimitExceeded,
50    /// Parse error (wraps parser error).
51    Parse(String),
52    /// Index-related error.
53    IndexError(String),
54    /// View-related error.
55    ViewError(String),
56    /// WAL or I/O error.
57    StorageError(String),
58    /// Readonly path needs write lock (internal sentinel).
59    ReadonlyNeedsWrite,
60    /// Generic execution error (catch-all for migration).
61    Execution(String),
62}
63
64impl fmt::Display for QueryError {
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66        match self {
67            QueryError::TableNotFound(t) => write!(f, "table '{t}' not found"),
68            QueryError::ColumnNotFound { table, column } => {
69                if table.is_empty() {
70                    write!(f, "column '{column}' not found")
71                } else {
72                    write!(f, "column '{column}' not found in table '{table}'")
73                }
74            }
75            QueryError::TypeError(msg) => write!(f, "type mismatch: {msg}"),
76            QueryError::JoinLimitExceeded => write!(f, "join result exceeds row limit"),
77            QueryError::SortLimitExceeded => {
78                write!(f, "sort input exceeds row limit — add a LIMIT clause")
79            }
80            QueryError::Parse(msg) => write!(f, "{msg}"),
81            QueryError::IndexError(msg) => write!(f, "{msg}"),
82            QueryError::ViewError(msg) => write!(f, "{msg}"),
83            QueryError::StorageError(msg) => write!(f, "{msg}"),
84            QueryError::ReadonlyNeedsWrite => {
85                write!(f, "__POWDB_READONLY_NEEDS_WRITE__")
86            }
87            QueryError::Execution(msg) => write!(f, "{msg}"),
88        }
89    }
90}
91
92impl std::error::Error for QueryError {}
93
94impl From<String> for QueryError {
95    fn from(s: String) -> Self {
96        QueryError::Execution(s)
97    }
98}
99
100impl From<&str> for QueryError {
101    fn from(s: &str) -> Self {
102        QueryError::Execution(s.to_string())
103    }
104}