cms_for_rust/operations/
insert_one.rs1use std::ops::Not;
2
3use axum::{
4 body::Body,
5 extract::State,
6 http::{Response, StatusCode},
7 response::IntoResponse,
8 Json,
9};
10use case::CaseExt;
11use inventory::Collect;
12use queries_for_sqlx::{execute_no_cache::ExecuteNoCache, InitStatement};
13use queries_for_sqlx::{
14 impl_into_mut_arguments_prelude::Type, prelude::stmt,
15 IntoMutArguments, SupportNamedBind, SupportReturning,
16};
17use serde::{Deserialize, Serialize};
18use serde_json::{json, Map, Value};
19use sqlx::Row;
20use sqlx::{
21 ColumnIndex, Database, Decode, Encode, Executor, Pool,
22};
23use tracing::warn;
24
25use crate::{
26 axum_router::{error, MyError},
27 entities::Entity,
28 relations::get_relation,
29};
30
31#[derive(Debug, Deserialize)]
32#[serde(deny_unknown_fields)]
33pub struct InsertInput<E, D, R> {
34 #[serde(skip)]
35 pub entity: E,
36 pub data: D,
37 pub attributes: bool,
38 pub relations: R,
39}
40
41pub async fn insert_one<S, T>(
42 pool: State<Pool<S>>,
43 Json(input): Json<InsertInput<(), T, Map<String, Value>>>,
44) -> Result<Response<Body>, MyError>
45where
46 S: Database,
47 T: Entity<S>
48 + Serialize
49 + Send
50 + for<'d> Deserialize<'d>
51 + Clone
52 + for<'q> IntoMutArguments<'q, S>,
53 S: SupportNamedBind + SupportReturning,
54 for<'c> &'c mut S::Connection: Executor<'c, Database = S>,
55 for<'r> &'r str: ColumnIndex<S::Row>,
56 i64: Type<S> + for<'d> Decode<'d, S> + for<'d> Encode<'d, S>,
57 crate::relations::Submitable<S>: Collect,
58{
59 if input.attributes.not() {
60 panic!(
61 "not returning attributes is not supported for now"
62 );
63 }
64
65 let mut rels = match get_relation::<S>(
66 T::table_name().to_snake().as_str(),
67 "from_insert_one",
68 input.relations,
69 ) {
70 Ok(e) => e,
71 Err(e) => {
72 return Err(error(StatusCode::BAD_REQUEST).for_dev(
73 format!(
74 "following relations ({}) are not related to {}",
75 e.join(", "),
76 T::table_name()
77 ),
78 ));
79 }
80 };
81
82 let mut st = stmt::InsertStOne::init(T::table_name());
83
84 input.data.clone().insert_st(&mut st);
85
86 for rel in rels.iter_mut() {
87 rel.on_insert(&mut st);
88 }
89
90 let res = st
92 .returning(vec!["id"])
93 .fetch_one(&pool.0, |r| {
94 let id: i64 = r.get("id");
95 warn!("refactor: from_row and take should not exist in insert_one");
96 Ok(id)
97 })
98 .await
99 .unwrap();
100
101 for rel in rels.iter_mut() {
102 rel.sub_op2(pool.0.clone(), res).await;
103 }
104
105 let mut relation = serde_json::Map::default();
106 for rel in rels.iter_mut() {
107 warn!("refactor: take2 should not take any id on insert_one");
108 if let Some(value) = rel.take2(Default::default()) {
109 relation.entry(rel.schema_key()).or_insert(value);
110 }
111 }
112
113 Ok((
114 StatusCode::CREATED,
115 Json(json!({
116 "id": res,
117 "attributes": input.data,
118 "relations": relation,
119 })),
120 )
121 .into_response())
122}
123
124#[cfg(test)]
125mod test_insert_one {
126 fn main() {
127 panic!("test not implemented");
128 }
129}