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}