jankenstore/action/
update_op.rs

1use super::{
2    get_parent_info, get_pk_vals,
3    payload::{ParentHood, ParsableOp, ReadSrc, SrcAndKeys},
4};
5use crate::sqlite::{
6    input_utils::json_to_val_map_by_schema, schema::SchemaFamily, shift::RecordOwned, update,
7};
8
9use anyhow::Result;
10use rusqlite::Connection;
11use serde::{Deserialize, Serialize};
12use serde_json::Value as JsonValue;
13
14///
15/// Providing generic update operations using JSON-compatible parameters
16#[derive(Debug, Serialize, Deserialize)]
17pub enum UpdateOp {
18    ///
19    /// Update record in a table by their primary keys
20    /// # Arguments
21    /// * `SrcAndValues` - The primary key values of the record to update from the specified table
22    /// * `JsonValue` - The payload for updating the specified records
23    Update(SrcAndKeys, JsonValue),
24
25    ///
26    /// Update all records in a table that are children of specified parent records in another table
27    /// # Arguments
28    /// * `ParentHood` - The table where the records will be updated and the parent table and the parent record's primary key values
29    /// * `JsonValue` - The payload for updating the specified records
30    UpdateChildren(ParentHood, JsonValue),
31}
32
33impl UpdateOp {
34    ///
35    /// Execute the operation on the database
36    /// # Arguments
37    /// * `conn` - A connection to the database
38    /// * `schema_family` - The schema family of the database
39    pub fn run(&self, conn: &Connection, schema_family: &SchemaFamily) -> Result<()> {
40        let get_payload_map = |data_src: &str, payload| -> Result<RecordOwned> {
41            json_to_val_map_by_schema(schema_family, data_src, payload)
42        };
43        match self {
44            Self::Update(SrcAndKeys { src, keys }, payload) => {
45                let keys = get_pk_vals(schema_family, src, keys)?;
46                let payload = get_payload_map(src, payload)?;
47                update::update_by_pk(conn, schema_family, src, &payload, &keys, None, true)?;
48            }
49            Self::UpdateChildren(ParentHood { src, parents }, payload) => {
50                let parents = get_parent_info(schema_family, src, parents)?;
51                let payload = get_payload_map(src, payload)?;
52                update::update_children_of(
53                    conn,
54                    schema_family,
55                    src,
56                    &parents,
57                    &payload,
58                    None,
59                    true,
60                )?;
61            }
62        }
63        Ok(())
64    }
65
66    ///
67    /// Execute the operation on the database with a map function
68    /// that modifies the input that received from the payload.
69    /// For example, it might be useful for internal data processing like password hashing, uuid generation, etc.
70    /// # Arguments
71    /// * `conn` - A connection to the database
72    /// * `schema_family` - The schema family of the database
73    /// * `map_input` - The function that modifies the input record
74    pub fn run_map<T>(
75        &self,
76        conn: &Connection,
77        schema_family: &SchemaFamily,
78        map_input: T,
79    ) -> Result<()>
80    where
81        T: FnOnce(&RecordOwned, &str) -> Result<RecordOwned>,
82    {
83        let get_payload_map = |data_src: &str, payload| -> Result<RecordOwned> {
84            let fresh_map = json_to_val_map_by_schema(schema_family, data_src, payload);
85            fresh_map.map(|input| map_input(&input, data_src))?
86        };
87        match self {
88            Self::Update(SrcAndKeys { src, keys }, payload) => {
89                update::update_by_pk(
90                    conn,
91                    schema_family,
92                    src,
93                    &get_payload_map(src, payload)?,
94                    get_pk_vals(schema_family, src, keys)?.as_slice(),
95                    None,
96                    true,
97                )?;
98            }
99            Self::UpdateChildren(ParentHood { src, parents }, payload) => {
100                update::update_children_of(
101                    conn,
102                    schema_family,
103                    src,
104                    &get_parent_info(schema_family, src, parents)?,
105                    &get_payload_map(src, payload)?,
106                    None,
107                    true,
108                )?;
109            }
110        }
111        Ok(())
112    }
113}
114
115impl ParsableOp<'_> for UpdateOp {}
116impl ReadSrc for UpdateOp {
117    fn src(&self) -> &str {
118        match self {
119            Self::Update(SrcAndKeys { src, .. }, _) => src,
120            Self::UpdateChildren(ParentHood { src, .. }, _) => src,
121        }
122    }
123}