Skip to main content

tablo_core/resource/
write.rs

1//! The derived record writes a resource's create and update default to.
2
3use toasty::{Executor, stmt::IntoInsert};
4use topcoat::{Result, context::Cx};
5
6use super::{Resource, require_mounted};
7use crate::{
8    form::{Posted, RecordForm},
9    tenancy::require_tenant,
10};
11
12/// The derived create: the form's builder, the request tenant stamped on the
13/// resource's [`Tenancy::column`](crate::Tenancy::column), executed through
14/// `ex`.
15///
16/// A resource whose tenant is inherited ([`Tenancy::via`](crate::Tenancy::via))
17/// has nothing to stamp.
18///
19/// # Errors
20///
21/// A tenantless request on a tenant-scoped resource (the handler answers 403 first),
22/// a `column` tenancy whose lens names no field of the model (the mount refuses it first), a
23/// resource the context's panel does not mount, or the driver's error.
24pub async fn write_create<R: Resource>(
25    cx: &Cx,
26    form: R::Form,
27    ex: &mut dyn Executor,
28) -> Result<R::Model> {
29    let resource = require_mounted::<R>(cx)?;
30    let mut insert = form.into_create().into_insert();
31    match resource.tenancy.column_field() {
32        Some(Ok(column)) => {
33            insert.set(column.index, toasty::stmt::Value::from(require_tenant(cx)?));
34        }
35        Some(Err(error)) => {
36            return Err(crate::error::declaration(
37                crate::DeclarationError::of::<R>(crate::Site::Tenancy, error).to_string(),
38            ));
39        }
40        None => {}
41    }
42    ex.exec(insert.into())
43        .await
44        .map_err(|error| -> topcoat::Error { error.into() })
45}
46
47/// The derived update: assign every named field and execute through `ex`.
48///
49/// A submission that names no field writes nothing. The instance update
50/// reloads `record`, so the returned row is the written one.
51///
52/// # Errors
53///
54/// The driver's error.
55pub async fn write_update<R: Resource>(
56    _cx: &Cx,
57    mut record: R::Model,
58    posted: Posted<R::Form>,
59    ex: &mut dyn Executor,
60) -> Result<R::Model> {
61    // Build the execution future before awaiting: the builder itself is not
62    // known to be `Send`, the future `exec_update` returns is.
63    {
64        let pending = posted
65            .into_update(&mut record)
66            .map(|update| <R::Form as RecordForm>::exec_update(update, &mut *ex));
67        if let Some(pending) = pending {
68            pending
69                .await
70                .map_err(|error| -> topcoat::Error { error.into() })?;
71        }
72    }
73    Ok(record)
74}