plot.rs (5544B)
1 use radroots_replica_db_schema::plot::{ 2 IPlotCreate, IPlotCreateResolve, IPlotDelete, IPlotDeleteResolve, IPlotFieldsFilter, 3 IPlotFindMany, IPlotFindManyResolve, IPlotFindOne, IPlotFindOneResolve, IPlotUpdate, 4 IPlotUpdateResolve, Plot, PlotQueryBindValues, 5 }; 6 use radroots_sql_core::error::SqlError; 7 use radroots_sql_core::{SqlExecutor, utils}; 8 use radroots_types::types::{IError, IResult, IResultList}; 9 use serde_json::Value; 10 11 const TABLE_NAME: &str = "plot"; 12 13 pub fn create( 14 exec: &dyn SqlExecutor, 15 opts: &IPlotCreate, 16 ) -> Result<IPlotCreateResolve, IError<SqlError>> { 17 let field_map = utils::to_object_map(opts).expect("serialize object map"); 18 let id = utils::uuidv4(); 19 let now = utils::time_created_on(); 20 let meta: [(&str, Value); 3] = [ 21 ("id", Value::from(id.clone())), 22 ("created_at", Value::from(now.clone())), 23 ("updated_at", Value::from(now.clone())), 24 ]; 25 let (sql, bind_values) = utils::build_insert_query_with_meta(TABLE_NAME, &meta, &field_map); 26 let params_json = utils::to_params_json(bind_values).expect("serialize bind params"); 27 let _ = exec.exec(&sql, ¶ms_json)?; 28 let on = PlotQueryBindValues::Id { id: id.clone() }; 29 let result = find_one_by_on(exec, &on)?.ok_or(IError::from(SqlError::NotFound(id.clone())))?; 30 Ok(IResult { result }) 31 } 32 33 pub fn find_one( 34 exec: &dyn SqlExecutor, 35 opts: &IPlotFindOne, 36 ) -> Result<IPlotFindOneResolve, IError<SqlError>> { 37 let result = match opts { 38 IPlotFindOne::On(args) => find_one_by_on(exec, &args.on)?, 39 }; 40 Ok(IResult { result }) 41 } 42 43 pub fn find_many( 44 exec: &dyn SqlExecutor, 45 opts: &IPlotFindMany, 46 ) -> Result<IPlotFindManyResolve, IError<SqlError>> { 47 let results = find_many_filter(exec, &opts.filter)?; 48 Ok(IResultList { results }) 49 } 50 51 fn find_many_filter( 52 exec: &dyn SqlExecutor, 53 filter: &Option<IPlotFieldsFilter>, 54 ) -> Result<Vec<Plot>, IError<SqlError>> { 55 let (sql, bind_values) = utils::build_select_query_with_meta(TABLE_NAME, filter.as_ref()); 56 let params_json = utils::to_params_json(bind_values).expect("serialize bind params"); 57 let json = exec.query_raw(&sql, ¶ms_json)?; 58 let rows: Vec<Plot> = utils::parse_json(&json)?; 59 Ok(rows) 60 } 61 62 fn find_one_by_on( 63 exec: &dyn SqlExecutor, 64 on: &PlotQueryBindValues, 65 ) -> Result<Option<Plot>, IError<SqlError>> { 66 let (column, value) = on.to_filter_param(); 67 let sql = format!("SELECT * FROM {TABLE_NAME} WHERE {column} = ? LIMIT 1;"); 68 let params_json = utils::to_params_json(vec![value]).expect("serialize bind params"); 69 let json = exec.query_raw(&sql, ¶ms_json)?; 70 let mut rows: Vec<Plot> = utils::parse_json(&json)?; 71 Ok(rows.pop()) 72 } 73 74 fn select_by_id(exec: &dyn SqlExecutor, id: &str) -> Result<Plot, IError<SqlError>> { 75 let params_json = 76 utils::to_params_json(vec![Value::from(id.to_owned())]).expect("serialize bind params"); 77 let sql = format!("SELECT * FROM {TABLE_NAME} WHERE id = ?;"); 78 let json = exec.query_raw(&sql, ¶ms_json)?; 79 let mut rows: Vec<Plot> = utils::parse_json(&json)?; 80 rows.pop() 81 .ok_or(IError::from(SqlError::NotFound(id.to_owned()))) 82 } 83 84 pub fn update( 85 exec: &dyn SqlExecutor, 86 opts: &IPlotUpdate, 87 ) -> Result<IPlotUpdateResolve, IError<SqlError>> { 88 let mut updates = 89 utils::to_partial_object_map(&opts.fields).expect("serialize partial object map"); 90 if updates.is_empty() { 91 return Err(IError::from(SqlError::InvalidArgument(String::from( 92 "no fields to update", 93 )))); 94 } 95 updates.insert( 96 String::from("updated_at"), 97 Value::from(utils::time_created_on()), 98 ); 99 let mut set_parts = Vec::with_capacity(updates.len()); 100 let mut bind_values = Vec::with_capacity(updates.len() + 1); 101 for (column, value) in updates { 102 set_parts.push(format!("{column} = ?")); 103 bind_values.push(utils::to_db_bind_value(&value)); 104 } 105 let id_for_lookup = match opts.on.primary_key() { 106 Some(id) => id, 107 None => { 108 let found = find_one_by_on(exec, &opts.on)?; 109 let model = found.ok_or(IError::from(SqlError::NotFound(opts.on.lookup_key())))?; 110 model.id 111 } 112 }; 113 bind_values.push(Value::from(id_for_lookup.clone())); 114 let sql = format!( 115 "UPDATE {TABLE_NAME} SET {} WHERE id = ?;", 116 set_parts.join(", ") 117 ); 118 let params_json = utils::to_params_json(bind_values).expect("serialize bind params"); 119 let _ = exec.exec(&sql, ¶ms_json)?; 120 let updated = select_by_id(exec, &id_for_lookup)?; 121 Ok(IResult { result: updated }) 122 } 123 124 pub fn delete( 125 exec: &dyn SqlExecutor, 126 opts: &IPlotDelete, 127 ) -> Result<IPlotDeleteResolve, IError<SqlError>> { 128 let id_for_lookup = match opts { 129 IPlotDelete::On(args) => match args.on.primary_key() { 130 Some(id) => id, 131 None => { 132 let found = find_one_by_on(exec, &args.on)?; 133 let model = found.ok_or(IError::from(SqlError::NotFound(args.on.lookup_key())))?; 134 model.id 135 } 136 }, 137 }; 138 let params_json = utils::to_params_json(vec![Value::from(id_for_lookup.clone())]) 139 .expect("serialize bind params"); 140 let sql = format!("DELETE FROM {TABLE_NAME} WHERE id = ?;"); 141 let outcome = exec.exec(&sql, ¶ms_json)?; 142 if outcome.changes == 0 { 143 return Err(IError::from(SqlError::NotFound(id_for_lookup.clone()))); 144 } 145 Ok(IResult { 146 result: id_for_lookup, 147 }) 148 }