Skip to content

Commit 71f48ff

Browse files
Datastore Extraction: Create DatastoreError type (#2798)
Signed-off-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
1 parent afc9e5b commit 71f48ff

File tree

12 files changed

+300
-240
lines changed

12 files changed

+300
-240
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
use super::system_tables::SystemTable;
2+
use enum_as_inner::EnumAsInner;
3+
use spacetimedb_lib::buffer::DecodeError;
4+
use spacetimedb_lib::{
5+
db::{
6+
error::LibError,
7+
raw_def::{v9::RawSql, RawIndexDefV8},
8+
},
9+
AlgebraicType, AlgebraicValue, ProductValue,
10+
};
11+
use spacetimedb_primitives::{ColId, ColList, IndexId, SequenceId, TableId};
12+
use spacetimedb_sats::{product_value::InvalidFieldError, satn::Satn};
13+
use spacetimedb_snapshot::SnapshotError;
14+
use spacetimedb_table::{
15+
bflatn_to, read_column,
16+
table::{self, ReadViaBsatnError, UniqueConstraintViolation},
17+
};
18+
use thiserror::Error;
19+
20+
#[derive(Error, Debug, EnumAsInner)]
21+
pub enum DatastoreError {
22+
#[error("LibError: {0}")]
23+
Lib(#[from] LibError),
24+
#[error("TableError: {0}")]
25+
Table(#[from] TableError),
26+
#[error("IndexError: {0}")]
27+
Index(#[from] IndexError),
28+
#[error("SequenceError: {0}")]
29+
Sequence(#[from] SequenceError),
30+
#[error(transparent)]
31+
// Box the inner [`SnapshotError`] to keep Clippy quiet about large `Err` variants.
32+
Snapshot(#[from] Box<SnapshotError>),
33+
// TODO(cloutiertyler): should this be a TableError? I couldn't get it to compile
34+
#[error("Error reading a value from a table through BSATN: {0}")]
35+
ReadViaBsatnError(#[from] ReadViaBsatnError),
36+
#[error(transparent)]
37+
Other(#[from] anyhow::Error),
38+
}
39+
40+
#[derive(Error, Debug, EnumAsInner)]
41+
pub enum TableError {
42+
#[error("Table with name `{0}` start with 'st_' and that is reserved for internal system tables.")]
43+
System(Box<str>),
44+
#[error("Table with name `{0}` already exists.")]
45+
Exist(String),
46+
#[error("Table with name `{0}` not found.")]
47+
NotFound(String),
48+
#[error("Table with ID `{1}` not found in `{0}`.")]
49+
IdNotFound(SystemTable, u32),
50+
#[error("Sql `{1}` not found in `{0}`.")]
51+
RawSqlNotFound(SystemTable, RawSql),
52+
#[error("Table with ID `{0}` not found in `TxState`.")]
53+
IdNotFoundState(TableId),
54+
#[error("Column `{0}.{1}` is missing a name")]
55+
ColumnWithoutName(String, ColId),
56+
#[error("schema_for_table: Table has invalid schema: {0} Err: {1}")]
57+
InvalidSchema(TableId, LibError),
58+
#[error("Row has invalid row type for table: {0} Err: {1}", table_id, row.to_satn())]
59+
RowInvalidType { table_id: TableId, row: ProductValue },
60+
#[error("failed to decode row in table")]
61+
RowDecodeError(DecodeError),
62+
#[error("Column with name `{0}` already exists")]
63+
DuplicateColumnName(String),
64+
#[error("Column `{0}` not found")]
65+
ColumnNotFound(ColId),
66+
#[error(
67+
"DecodeError for field `{0}.{1}`, expect `{2}` but found `{3}`",
68+
table,
69+
field,
70+
expect,
71+
found
72+
)]
73+
DecodeField {
74+
table: String,
75+
field: Box<str>,
76+
expect: String,
77+
found: String,
78+
},
79+
#[error(transparent)]
80+
Bflatn(#[from] bflatn_to::Error),
81+
#[error(transparent)]
82+
Duplicate(#[from] table::DuplicateError),
83+
#[error(transparent)]
84+
ReadColTypeError(#[from] read_column::TypeError),
85+
}
86+
87+
#[derive(Error, Debug, PartialEq, Eq)]
88+
pub enum IndexError {
89+
#[error("Index not found: {0:?}")]
90+
NotFound(IndexId),
91+
#[error("Column not found: {0:?}")]
92+
ColumnNotFound(RawIndexDefV8),
93+
#[error(transparent)]
94+
UniqueConstraintViolation(#[from] UniqueConstraintViolation),
95+
#[error("Attempt to define a index with more than 1 auto_inc column: Table: {0:?}, Columns: {1:?}")]
96+
OneAutoInc(TableId, Vec<String>),
97+
#[error("Could not decode arguments to index scan")]
98+
Decode(DecodeError),
99+
#[error("Index was not unique: {0:?}")]
100+
NotUnique(IndexId),
101+
#[error("Key {1:?} was not found in index {0:?}")]
102+
KeyNotFound(IndexId, AlgebraicValue),
103+
}
104+
105+
#[derive(Error, Debug, PartialEq, Eq)]
106+
pub enum SequenceError {
107+
#[error("Sequence with name `{0}` already exists.")]
108+
Exist(String),
109+
#[error("Sequence `{0}`: The increment is 0, and this means the sequence can't advance.")]
110+
IncrementIsZero(String),
111+
#[error("Sequence `{0}`: The min_value {1} must < max_value {2}.")]
112+
MinMax(String, i128, i128),
113+
#[error("Sequence `{0}`: The start value {1} must be >= min_value {2}.")]
114+
MinStart(String, i128, i128),
115+
#[error("Sequence `{0}`: The start value {1} must be <= min_value {2}.")]
116+
MaxStart(String, i128, i128),
117+
#[error("Sequence `{0}` failed to decode value from Sled (not a u128).")]
118+
SequenceValue(String),
119+
#[error("Sequence ID `{0}` not found.")]
120+
NotFound(SequenceId),
121+
#[error("Sequence applied to a non-integer field. Column `{col}` is of type {{found.to_sats()}}.")]
122+
NotInteger { col: String, found: AlgebraicType },
123+
#[error("Sequence ID `{0}` still had no values left after allocation.")]
124+
UnableToAllocate(SequenceId),
125+
#[error("Autoinc constraint on table {0:?} spans more than one column: {1:?}")]
126+
MultiColumnAutoInc(TableId, ColList),
127+
}
128+
129+
impl From<InvalidFieldError> for DatastoreError {
130+
fn from(value: InvalidFieldError) -> Self {
131+
LibError::from(value).into()
132+
}
133+
}
134+
135+
impl From<spacetimedb_table::read_column::TypeError> for DatastoreError {
136+
fn from(err: spacetimedb_table::read_column::TypeError) -> Self {
137+
TableError::from(err).into()
138+
}
139+
}
140+
141+
impl From<table::InsertError> for DatastoreError {
142+
fn from(err: table::InsertError) -> Self {
143+
match err {
144+
table::InsertError::Duplicate(e) => TableError::from(e).into(),
145+
table::InsertError::Bflatn(e) => TableError::from(e).into(),
146+
table::InsertError::IndexError(e) => IndexError::from(e).into(),
147+
}
148+
}
149+
}
150+
151+
impl From<bflatn_to::Error> for DatastoreError {
152+
fn from(err: bflatn_to::Error) -> Self {
153+
Self::Table(err.into())
154+
}
155+
}
156+
157+
impl From<SnapshotError> for DatastoreError {
158+
fn from(e: SnapshotError) -> Self {
159+
DatastoreError::Snapshot(Box::new(e))
160+
}
161+
}

crates/core/src/db/datastore/locking_tx_datastore/committed_state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use super::{
99
use crate::{
1010
db::{
1111
datastore::{
12+
error::{IndexError, TableError},
1213
system_tables::{
1314
system_tables, StColumnRow, StConstraintData, StConstraintRow, StIndexRow, StSequenceRow,
1415
StTableFields, StTableRow, SystemTable, ST_CLIENT_ID, ST_CLIENT_IDX, ST_COLUMN_ID, ST_COLUMN_IDX,
@@ -21,7 +22,6 @@ use crate::{
2122
},
2223
db_metrics::DB_METRICS,
2324
},
24-
error::{IndexError, TableError},
2525
execution_context::ExecutionContext,
2626
};
2727
use anyhow::anyhow;

crates/core/src/db/datastore/locking_tx_datastore/datastore.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use super::{
77
tx_state::TxState,
88
};
99
use crate::db::datastore::{
10+
error::{DatastoreError, TableError},
1011
locking_tx_datastore::state_view::{IterByColRangeMutTx, IterMutTx, IterTx},
1112
traits::{InsertFlags, UpdateFlags},
1213
};
@@ -25,7 +26,6 @@ use crate::{
2526
},
2627
db_metrics::DB_METRICS,
2728
},
28-
error::{DBError, TableError},
2929
execution_context::ExecutionContext,
3030
};
3131
use anyhow::{anyhow, Context};
@@ -47,7 +47,7 @@ use std::sync::Arc;
4747
use std::time::{Duration, Instant};
4848
use thiserror::Error;
4949

50-
pub type Result<T> = std::result::Result<T, DBError>;
50+
pub type Result<T> = std::result::Result<T, DatastoreError>;
5151

5252
/// Struct contains various database states, each protected by
5353
/// their own lock. To avoid deadlocks, it is crucial to acquire these locks
@@ -634,7 +634,7 @@ impl MutTxDatastore for Locking {
634634
.map(|row| {
635635
let ptr = row.pointer();
636636
let row = StModuleRow::try_from(row)?;
637-
Ok::<_, DBError>((ptr, row))
637+
Ok::<_, DatastoreError>((ptr, row))
638638
})
639639
.transpose()?;
640640
match old {
@@ -893,7 +893,7 @@ pub enum ReplayError {
893893
#[error(transparent)]
894894
Decode(#[from] bsatn::DecodeError),
895895
#[error(transparent)]
896-
Db(#[from] DBError),
896+
Db(#[from] DatastoreError),
897897
#[error(transparent)]
898898
Any(#[from] anyhow::Error),
899899
}
@@ -1137,6 +1137,7 @@ fn metadata_from_row(row: RowRef<'_>) -> Result<Metadata> {
11371137
#[cfg(test)]
11381138
mod tests {
11391139
use super::*;
1140+
use crate::db::datastore::error::IndexError;
11401141
use crate::db::datastore::locking_tx_datastore::tx_state::PendingSchemaChange;
11411142
use crate::db::datastore::system_tables::{
11421143
system_tables, StColumnRow, StConstraintData, StConstraintFields, StConstraintRow, StIndexAlgorithm,
@@ -1148,7 +1149,6 @@ mod tests {
11481149
};
11491150
use crate::db::datastore::traits::{IsolationLevel, MutTx};
11501151
use crate::db::datastore::Result;
1151-
use crate::error::{DBError, IndexError};
11521152
use bsatn::to_vec;
11531153
use core::{fmt, mem};
11541154
use itertools::Itertools;
@@ -2034,7 +2034,7 @@ mod tests {
20342034
insert(&datastore, &mut tx, table_id, &row)?;
20352035
let result = insert(&datastore, &mut tx, table_id, &row);
20362036
match result {
2037-
Err(DBError::Index(IndexError::UniqueConstraintViolation(_))) => (),
2037+
Err(DatastoreError::Index(IndexError::UniqueConstraintViolation(_))) => (),
20382038
_ => panic!("Expected an unique constraint violation error."),
20392039
}
20402040
#[rustfmt::skip]
@@ -2051,7 +2051,7 @@ mod tests {
20512051
let mut tx = begin_mut_tx(&datastore);
20522052
let result = insert(&datastore, &mut tx, table_id, &row);
20532053
match result {
2054-
Err(DBError::Index(IndexError::UniqueConstraintViolation(_))) => (),
2054+
Err(DatastoreError::Index(IndexError::UniqueConstraintViolation(_))) => (),
20552055
_ => panic!("Expected an unique constraint violation error."),
20562056
}
20572057
#[rustfmt::skip]
@@ -2139,7 +2139,7 @@ mod tests {
21392139
let row = u32_str_u32(0, "Bar", 18); // 0 will be ignored.
21402140
let result = insert(&datastore, &mut tx, table_id, &row);
21412141
match result {
2142-
Err(DBError::Index(IndexError::UniqueConstraintViolation(_))) => (),
2142+
Err(DatastoreError::Index(IndexError::UniqueConstraintViolation(_))) => (),
21432143
e => panic!("Expected an unique constraint violation error but got {e:?}."),
21442144
}
21452145
#[rustfmt::skip]
@@ -2164,7 +2164,7 @@ mod tests {
21642164
let row = u32_str_u32(0, "Bar", 18); // 0 will be ignored.
21652165
let result = insert(&datastore, &mut tx, table_id, &row);
21662166
match result {
2167-
Err(DBError::Index(IndexError::UniqueConstraintViolation(_))) => (),
2167+
Err(DatastoreError::Index(IndexError::UniqueConstraintViolation(_))) => (),
21682168
_ => panic!("Expected an unique constraint violation error."),
21692169
}
21702170
#[rustfmt::skip]

crates/core/src/db/datastore/locking_tx_datastore/mut_tx.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@ use super::{
88
tx_state::{IndexIdMap, PendingSchemaChange, TxState, TxTableForInsertion},
99
SharedMutexGuard, SharedWriteGuard,
1010
};
11-
use crate::db::datastore::system_tables::{
12-
with_sys_table_buf, StClientFields, StClientRow, StColumnFields, StColumnRow, StConstraintFields, StConstraintRow,
13-
StFields as _, StIndexFields, StIndexRow, StRowLevelSecurityFields, StRowLevelSecurityRow, StScheduledFields,
14-
StScheduledRow, StSequenceFields, StSequenceRow, StTableFields, StTableRow, SystemTable, ST_CLIENT_ID,
15-
ST_COLUMN_ID, ST_CONSTRAINT_ID, ST_INDEX_ID, ST_ROW_LEVEL_SECURITY_ID, ST_SCHEDULED_ID, ST_SEQUENCE_ID,
16-
ST_TABLE_ID,
17-
};
1811
use crate::db::datastore::traits::{InsertFlags, RowTypeForTable, TxData, UpdateFlags};
19-
use crate::execution_context::Workload;
20-
use crate::{
12+
use crate::db::datastore::{
2113
error::{IndexError, SequenceError, TableError},
22-
execution_context::ExecutionContext,
14+
system_tables::{
15+
with_sys_table_buf, StClientFields, StClientRow, StColumnFields, StColumnRow, StConstraintFields,
16+
StConstraintRow, StFields as _, StIndexFields, StIndexRow, StRowLevelSecurityFields, StRowLevelSecurityRow,
17+
StScheduledFields, StScheduledRow, StSequenceFields, StSequenceRow, StTableFields, StTableRow, SystemTable,
18+
ST_CLIENT_ID, ST_COLUMN_ID, ST_CONSTRAINT_ID, ST_INDEX_ID, ST_ROW_LEVEL_SECURITY_ID, ST_SCHEDULED_ID,
19+
ST_SEQUENCE_ID, ST_TABLE_ID,
20+
},
2321
};
22+
use crate::execution_context::ExecutionContext;
23+
use crate::execution_context::Workload;
2424
use core::ops::RangeBounds;
2525
use core::{cell::RefCell, mem};
2626
use core::{iter, ops::Bound};

crates/core/src/db/datastore/locking_tx_datastore/state_view.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
use super::mut_tx::{FilterDeleted, IndexScanRanged};
22
use super::{committed_state::CommittedState, datastore::Result, tx_state::TxState};
3-
use crate::{
4-
db::datastore::system_tables::{
5-
StColumnFields, StColumnRow, StConstraintFields, StConstraintRow, StIndexFields, StIndexRow, StScheduledFields,
6-
StScheduledRow, StSequenceFields, StSequenceRow, StTableFields, StTableRow, SystemTable, ST_COLUMN_ID,
7-
ST_CONSTRAINT_ID, ST_INDEX_ID, ST_SCHEDULED_ID, ST_SEQUENCE_ID, ST_TABLE_ID,
8-
},
9-
error::TableError,
3+
use crate::db::datastore::error::TableError;
4+
use crate::db::datastore::system_tables::{
5+
StColumnFields, StColumnRow, StConstraintFields, StConstraintRow, StIndexFields, StIndexRow, StScheduledFields,
6+
StScheduledRow, StSequenceFields, StSequenceRow, StTableFields, StTableRow, SystemTable, ST_COLUMN_ID,
7+
ST_CONSTRAINT_ID, ST_INDEX_ID, ST_SCHEDULED_ID, ST_SEQUENCE_ID, ST_TABLE_ID,
108
};
119
use core::ops::RangeBounds;
1210
use spacetimedb_primitives::{ColList, TableId};
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
pub mod error;
12
pub mod locking_tx_datastore;
23
pub mod system_tables;
34
pub mod traits;
45

5-
use crate::error::DBError;
6+
use error::DatastoreError;
67

7-
pub type Result<T> = core::result::Result<T, DBError>;
8+
pub type Result<T> = core::result::Result<T, DatastoreError>;

0 commit comments

Comments
 (0)