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