Skip to main content

WriteError

Enum WriteError 

Source
#[non_exhaustive]
pub enum WriteError<K = String> { Refused(FieldErrors<K>), Declined(Text), Failed(Error), }
Expand description

Why a record fn or an action’s run wrote nothing: a refusal the page shows, or a failure.

Either way the handler rolls the transaction back, so whatever the fn wrote before it returned is undone.

  • Refused renders the form again with status 200, each error under the control of the field it names, as a validate_record error does. A record fn keys its errors by the record form’s field enum, an action’s run by its input’s, so a renamed field fails to compile rather than render no message.
  • Declined refuses with a message that belongs to no field: a paid invoice that cannot be deleted. A record form renders again with the message above its fields; a delete, a restore or an action flashes it and lands back where it started.
  • Failed answers as a failed write does: a record fn’s collision on a unique index renders under the field’s control, a save another save overtook renders the stale form, and any other error flashes the failure toast and answers with the error.

A refusal is the answer to a rule that reads the database: a stock level, a quota, a uniqueness no index models. A rule the write itself enforces holds against concurrent writes: an update filtered on the stock it needs that matches no row refuses the very write it would have made.

? turns any error a topcoat::Error takes into Failed, and a FieldErrors into Refused:

use tablo_core::{FieldErrors, RecordForm, Resource, WriteError, write_create};
use topcoat::context::Cx;

impl Resource for OrderResource {
    type Model = Order;
    type Form = OrderForm;

    async fn create_record(
        cx: &Cx,
        form: OrderForm,
        ex: &mut dyn toasty::Executor,
    ) -> Result<Order, WriteError<OrderFormField>> {
        let stock = Stock::filter_by_sku(&form.sku)
            .first()
            .exec(&mut *ex)
            .await?;
        if stock.is_none_or(|stock| stock.level < form.quantity) {
            let mut errors = FieldErrors::new();
            errors.add(OrderFormField::Quantity, "Not enough in stock");
            return Err(errors.into());
        }
        write_create::<Self>(cx, form, ex).await
    }
}

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

Refused(FieldErrors<K>)

The submission cannot stand: render the form again with these errors.

§

Declined(Text)

The write cannot stand, for a reason that names no field: show this message.

§

Failed(Error)

The write failed: answer with this error and the failure toast.

Implementations§

Source§

impl<K> WriteError<K>

Source

pub fn field(key: impl Into<K>, message: impl Into<Text>) -> Self

Refuse the submission with message under key.

Source

pub fn declined(message: impl Into<Text>) -> Self

Decline the write with message, which names no field.

Trait Implementations§

Source§

impl<K: Debug> Debug for WriteError<K>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<K, E: Into<Error>> From<E> for WriteError<K>

Source§

fn from(error: E) -> Self

Converts to this type from the input type.
Source§

impl<K> From<FieldErrors<K>> for WriteError<K>

Source§

fn from(errors: FieldErrors<K>) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl<K = String> !RefUnwindSafe for WriteError<K>

§

impl<K = String> !UnwindSafe for WriteError<K>

§

impl<K> Forget for WriteError<K>

§

impl<K> Freeze for WriteError<K>
where FieldErrors<K>: Freeze,

§

impl<K> Move for WriteError<K>

§

impl<K> Send for WriteError<K>
where FieldErrors<K>: Send,

§

impl<K> Sync for WriteError<K>
where FieldErrors<K>: Sync,

§

impl<K> Unpin for WriteError<K>
where FieldErrors<K>: Unpin,

§

impl<K> UnsafeUnpin for WriteError<K>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more