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 misdeclared tenant column (the mount refuses it first), a resource the request's panel does
23/// 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(
34 column.index,
35 toasty_core::stmt::Value::from(require_tenant(cx)?),
36 );
37 }
38 Some(Err(error)) => {
39 return Err(crate::error::declaration(
40 crate::DeclarationError::of::<R>(crate::Site::Tenancy, error).to_string(),
41 ));
42 }
43 None => {}
44 }
45 ex.exec(insert.into())
46 .await
47 .map_err(|error| -> topcoat::Error { error.into() })
48}
49
50/// The derived update: assign every named field and execute through `ex`.
51///
52/// A submission that names no field writes nothing. The instance update
53/// reloads `record`, so the returned row is the written one.
54///
55/// # Errors
56///
57/// The driver's error.
58pub async fn write_update<R: Resource>(
59 _cx: &Cx,
60 mut record: R::Model,
61 posted: Posted<R::Form>,
62 ex: &mut dyn Executor,
63) -> Result<R::Model> {
64 // Build the execution future before awaiting: the builder itself is not
65 // known to be `Send`, the future `exec_update` returns is.
66 {
67 let pending = posted
68 .into_update(&mut record)
69 .map(|update| <R::Form as RecordForm>::exec_update(update, &mut *ex));
70 if let Some(pending) = pending {
71 pending
72 .await
73 .map_err(|error| -> topcoat::Error { error.into() })?;
74 }
75 }
76 Ok(record)
77}