spacetimedsl 0.21.1

The SpacetimeDB Rust Server Module meta-framework
Documentation
use std::{error::Error, fmt::Display};

use crate::{DeletionResult, delete::OnDeleteStrategy};

#[derive(Debug)]
pub enum SpacetimeDSLError {
    Error(String),
    NotFoundError {
        table_name: Box<str>,
        column_names_and_row_values: Box<str>,
    },
    UniqueConstraintViolation {
        table_name: Box<str>,
        action: Action,
        error_from: ErrorFrom,
        one_or_multiple: OneOrMultiple,
        column_names_and_row_values: Box<str>,
    },
    AutoIncOverflow {
        table_name: Box<str>,
    },
    ReferenceIntegrityViolation(ReferenceIntegrityViolationError),
}

#[derive(Debug)]
pub enum ReferenceIntegrityViolationError {
    OnCreateOrUpdate {
        table_name: Box<str>,
        create_or_update: Action,
        column_names_and_row_values: Box<str>,
    },
    OnDelete(DeletionResult),
}

#[derive(Debug)]
pub enum Action {
    Create,
    Get,
    Update,
    Delete,
}

impl Display for Action {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Action::Create => write!(f, "create"),
            Action::Get => write!(f, "get"),
            Action::Update => write!(f, "update"),
            Action::Delete => write!(f, "delete"),
        }
    }
}

#[derive(Debug)]
pub enum ErrorFrom {
    SpacetimeDB,
    SpacetimeDSL,
}

#[derive(Debug)]
pub enum OneOrMultiple {
    One,
    Multiple,
}

impl Display for OnDeleteStrategy {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            OnDeleteStrategy::Error => write!(f, "Error"),
            OnDeleteStrategy::Delete => write!(f, "Delete"),
            OnDeleteStrategy::SetZero => write!(f, "SetZero"),
            OnDeleteStrategy::Ignore => write!(f, "Ignore"),
        }
    }
}

impl Display for SpacetimeDSLError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut message: String = String::new();

        let dig_spacetimedb = "Unfortunately SpacetimeDB doesn't provide more information";

        message.push_str(&match self {
            SpacetimeDSLError::Error(error) => error.into(),
            SpacetimeDSLError::NotFoundError {
                table_name,
                column_names_and_row_values
            } => format!("Not Found Error while trying to find a row in the `{table_name}` table with `{column_names_and_row_values}`!"),
            SpacetimeDSLError::UniqueConstraintViolation {
                table_name,
                action,
                error_from,
                one_or_multiple,
                column_names_and_row_values,
            } => {
                let column_names_and_row_values = match error_from {
                    ErrorFrom::SpacetimeDB => format!("! {dig_spacetimedb}, so here are all columns and their values: `{column_names_and_row_values}`."),
                    ErrorFrom::SpacetimeDSL => {
                        let one_or_multiple = match one_or_multiple {
                            OneOrMultiple::One => "",
                            OneOrMultiple::Multiple => " There can be two reasons for this: You are inserting or updating somewhere using spacetimedb::ReducerContext instead of spacetimedsl::DSL or the unique multi-column index feature of SpacetimeDSL is broken.",
                        };
                        format!(" because of `{column_names_and_row_values}`!{one_or_multiple}")
                    },
                };

                format!("Unique Constraint Violation Error while trying to {action} a row in the `{table_name}` table{column_names_and_row_values}")
            }
            SpacetimeDSLError::AutoIncOverflow { table_name } => {
                format!("Auto Inc Overflow Error on the `{table_name}` table! {dig_spacetimedb}.")
            }
            SpacetimeDSLError::ReferenceIntegrityViolation(error) => {
                match error {
                    ReferenceIntegrityViolationError::OnCreateOrUpdate {
                        table_name,
                        create_or_update,
                        column_names_and_row_values
                    } => {
                        let create_or_update = match create_or_update {
                            Action::Get | Action::Delete => panic!("Reference Integrity Violation Error On Create Or Update only allowed while creating or updating a row."),
                            action => action.to_string()
                        };

                        format!("Reference Integrity Violation Error while trying to {create_or_update} a row in the `{table_name}` table because of `{column_names_and_row_values}`!")
                    },
                    ReferenceIntegrityViolationError::OnDelete(deletion_result) => {
                        let one_or_multiple_rows = match deletion_result.one_or_multiple {
                            OneOrMultiple::One => "a row",
                            OneOrMultiple::Multiple => "multiple rows",
                        };

                        format!("Reference Integrity Violation Error while trying to delete {one_or_multiple_rows} in the `{}` table because of:\n\n{}", &deletion_result.table_name, deletion_result.to_csv())
                    },
                }
            }
        });

        write!(f, "{message}")
    }
}

impl Error for SpacetimeDSLError {}

impl From<SpacetimeDSLError> for String {
    fn from(value: SpacetimeDSLError) -> Self {
        value.to_string()
    }
}