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