gcs_location.rs (9496B)
1 use radroots_replica_db_schema::gcs_location::{ 2 GcsLocation, GcsLocationFindManyRel, GcsLocationQueryBindValues, IGcsLocationCreate, 3 IGcsLocationCreateResolve, IGcsLocationDelete, IGcsLocationDeleteResolve, 4 IGcsLocationFieldsFilter, IGcsLocationFindMany, IGcsLocationFindManyResolve, 5 IGcsLocationFindOne, IGcsLocationFindOneResolve, IGcsLocationUpdate, IGcsLocationUpdateResolve, 6 }; 7 use radroots_sql_core::error::SqlError; 8 use radroots_sql_core::{SqlExecutor, utils}; 9 use radroots_types::types::{IError, IResult, IResultList}; 10 use serde_json::Value; 11 12 const TABLE_NAME: &str = "gcs_location"; 13 14 pub fn create( 15 exec: &dyn SqlExecutor, 16 opts: &IGcsLocationCreate, 17 ) -> Result<IGcsLocationCreateResolve, IError<SqlError>> { 18 let field_map = utils::to_object_map(opts).expect("serialize object map"); 19 let id = utils::uuidv4(); 20 let now = utils::time_created_on(); 21 let meta: [(&str, Value); 3] = [ 22 ("id", Value::from(id.clone())), 23 ("created_at", Value::from(now.clone())), 24 ("updated_at", Value::from(now.clone())), 25 ]; 26 let (sql, bind_values) = utils::build_insert_query_with_meta(TABLE_NAME, &meta, &field_map); 27 let params_json = utils::to_params_json(bind_values).expect("serialize bind params"); 28 let _ = exec.exec(&sql, ¶ms_json)?; 29 let on = GcsLocationQueryBindValues::Id { id: id.clone() }; 30 let result = find_one_by_on(exec, &on)?.ok_or(IError::from(SqlError::NotFound(id.clone())))?; 31 Ok(IResult { result }) 32 } 33 34 pub fn find_one( 35 exec: &dyn SqlExecutor, 36 opts: &IGcsLocationFindOne, 37 ) -> Result<IGcsLocationFindOneResolve, IError<SqlError>> { 38 let result = match opts { 39 IGcsLocationFindOne::On(args) => find_one_by_on(exec, &args.on)?, 40 IGcsLocationFindOne::Rel(args) => find_one_by_rel(exec, &args.rel)?, 41 }; 42 Ok(IResult { result }) 43 } 44 45 pub fn find_many( 46 exec: &dyn SqlExecutor, 47 opts: &IGcsLocationFindMany, 48 ) -> Result<IGcsLocationFindManyResolve, IError<SqlError>> { 49 let results = match opts { 50 IGcsLocationFindMany::Filter { filter } => find_many_filter(exec, filter)?, 51 IGcsLocationFindMany::Rel { rel } => find_many_by_rel(exec, rel)?, 52 }; 53 Ok(IResultList { results }) 54 } 55 56 fn find_many_filter( 57 exec: &dyn SqlExecutor, 58 filter: &Option<IGcsLocationFieldsFilter>, 59 ) -> Result<Vec<GcsLocation>, IError<SqlError>> { 60 let (sql, bind_values) = utils::build_select_query_with_meta(TABLE_NAME, filter.as_ref()); 61 let params_json = utils::to_params_json(bind_values).expect("serialize bind params"); 62 let json = exec.query_raw(&sql, ¶ms_json)?; 63 let rows: Vec<GcsLocation> = utils::parse_json(&json)?; 64 Ok(rows) 65 } 66 67 fn find_one_by_on( 68 exec: &dyn SqlExecutor, 69 on: &GcsLocationQueryBindValues, 70 ) -> Result<Option<GcsLocation>, IError<SqlError>> { 71 let (column, value) = on.to_filter_param(); 72 let sql = format!("SELECT * FROM {TABLE_NAME} WHERE {column} = ? LIMIT 1;"); 73 let params_json = utils::to_params_json(vec![value]).expect("serialize bind params"); 74 let json = exec.query_raw(&sql, ¶ms_json)?; 75 let mut rows: Vec<GcsLocation> = utils::parse_json(&json)?; 76 Ok(rows.pop()) 77 } 78 79 fn rel_query(rel: &GcsLocationFindManyRel) -> (&'static str, Vec<Value>) { 80 match rel { 81 GcsLocationFindManyRel::OnTradeProduct(args) => ( 82 "SELECT gl.* FROM gcs_location gl JOIN trade_product_location tp_gl ON gl.id = tp_gl.tb_gl WHERE tp_gl.tb_tp = ?", 83 vec![Value::from(args.id.clone())], 84 ), 85 GcsLocationFindManyRel::OffTradeProduct(args) => ( 86 "SELECT gl.* FROM gcs_location gl WHERE NOT EXISTS (SELECT 1 FROM trade_product_location tp_gl WHERE tp_gl.tb_gl = gl.id AND tp_gl.tb_tp = ?)", 87 vec![Value::from(args.id.clone())], 88 ), 89 GcsLocationFindManyRel::OnFarm(args) => ( 90 "SELECT gl.* FROM gcs_location gl JOIN farm_gcs_location fgcs ON gl.id = fgcs.gcs_location_id WHERE fgcs.farm_id = ?", 91 vec![Value::from(args.id.clone())], 92 ), 93 GcsLocationFindManyRel::OffFarm(args) => ( 94 "SELECT gl.* FROM gcs_location gl WHERE NOT EXISTS (SELECT 1 FROM farm_gcs_location fgcs WHERE fgcs.gcs_location_id = gl.id AND fgcs.farm_id = ?)", 95 vec![Value::from(args.id.clone())], 96 ), 97 GcsLocationFindManyRel::OnPlot(args) => ( 98 "SELECT gl.* FROM gcs_location gl JOIN plot_gcs_location pgcs ON gl.id = pgcs.gcs_location_id WHERE pgcs.plot_id = ?", 99 vec![Value::from(args.id.clone())], 100 ), 101 GcsLocationFindManyRel::OffPlot(args) => ( 102 "SELECT gl.* FROM gcs_location gl WHERE NOT EXISTS (SELECT 1 FROM plot_gcs_location pgcs WHERE pgcs.gcs_location_id = gl.id AND pgcs.plot_id = ?)", 103 vec![Value::from(args.id.clone())], 104 ), 105 } 106 } 107 108 fn find_one_by_rel( 109 exec: &dyn SqlExecutor, 110 rel: &GcsLocationFindManyRel, 111 ) -> Result<Option<GcsLocation>, IError<SqlError>> { 112 let (sql, bind_values) = rel_query(rel); 113 let params_json = utils::to_params_json(bind_values).expect("serialize bind params"); 114 let sql = format!("{sql} LIMIT 1;"); 115 let json = exec.query_raw(&sql, ¶ms_json)?; 116 let mut rows: Vec<GcsLocation> = utils::parse_json(&json)?; 117 Ok(rows.pop()) 118 } 119 120 fn find_many_by_rel( 121 exec: &dyn SqlExecutor, 122 rel: &GcsLocationFindManyRel, 123 ) -> Result<Vec<GcsLocation>, IError<SqlError>> { 124 let (sql, bind_values) = rel_query(rel); 125 let params_json = utils::to_params_json(bind_values).expect("serialize bind params"); 126 let sql = format!("{sql};"); 127 let json = exec.query_raw(&sql, ¶ms_json)?; 128 let rows: Vec<GcsLocation> = utils::parse_json(&json)?; 129 Ok(rows) 130 } 131 132 fn select_by_id(exec: &dyn SqlExecutor, id: &str) -> Result<GcsLocation, IError<SqlError>> { 133 let params_json = 134 utils::to_params_json(vec![Value::from(id.to_owned())]).expect("serialize bind params"); 135 let sql = format!("SELECT * FROM {TABLE_NAME} WHERE id = ?;"); 136 let json = exec.query_raw(&sql, ¶ms_json)?; 137 let mut rows: Vec<GcsLocation> = utils::parse_json(&json)?; 138 rows.pop() 139 .ok_or(IError::from(SqlError::NotFound(id.to_owned()))) 140 } 141 142 pub fn update( 143 exec: &dyn SqlExecutor, 144 opts: &IGcsLocationUpdate, 145 ) -> Result<IGcsLocationUpdateResolve, IError<SqlError>> { 146 let mut updates = 147 utils::to_partial_object_map(&opts.fields).expect("serialize partial object map"); 148 if updates.is_empty() { 149 return Err(IError::from(SqlError::InvalidArgument(String::from( 150 "no fields to update", 151 )))); 152 } 153 updates.insert( 154 String::from("updated_at"), 155 Value::from(utils::time_created_on()), 156 ); 157 let mut set_parts = Vec::with_capacity(updates.len()); 158 let mut bind_values = Vec::with_capacity(updates.len() + 1); 159 for (column, value) in updates { 160 set_parts.push(format!("{column} = ?")); 161 bind_values.push(utils::to_db_bind_value(&value)); 162 } 163 let id_for_lookup = match opts.on.primary_key() { 164 Some(id) => id, 165 None => { 166 let found = find_one_by_on(exec, &opts.on)?; 167 let model = found.ok_or(IError::from(SqlError::NotFound(opts.on.lookup_key())))?; 168 model.id 169 } 170 }; 171 bind_values.push(Value::from(id_for_lookup.clone())); 172 let sql = format!( 173 "UPDATE {TABLE_NAME} SET {} WHERE id = ?;", 174 set_parts.join(", ") 175 ); 176 let params_json = utils::to_params_json(bind_values).expect("serialize bind params"); 177 let _ = exec.exec(&sql, ¶ms_json)?; 178 let updated = select_by_id(exec, &id_for_lookup)?; 179 Ok(IResult { result: updated }) 180 } 181 182 pub fn delete( 183 exec: &dyn SqlExecutor, 184 opts: &IGcsLocationDelete, 185 ) -> Result<IGcsLocationDeleteResolve, IError<SqlError>> { 186 let id_for_lookup = match opts { 187 IGcsLocationDelete::On(args) => match args.on.primary_key() { 188 Some(id) => id, 189 None => { 190 let found = find_one_by_on(exec, &args.on)?; 191 let model = found.ok_or(IError::from(SqlError::NotFound(args.on.lookup_key())))?; 192 model.id 193 } 194 }, 195 IGcsLocationDelete::Rel(args) => { 196 let found = find_one_by_rel(exec, &args.rel)?; 197 let model = found.ok_or(IError::from(SqlError::NotFound(rel_lookup_key(&args.rel))))?; 198 model.id 199 } 200 }; 201 let params_json = utils::to_params_json(vec![Value::from(id_for_lookup.clone())]) 202 .expect("serialize bind params"); 203 let sql = format!("DELETE FROM {TABLE_NAME} WHERE id = ?;"); 204 let outcome = exec.exec(&sql, ¶ms_json)?; 205 if outcome.changes == 0 { 206 return Err(IError::from(SqlError::NotFound(id_for_lookup.clone()))); 207 } 208 Ok(IResult { 209 result: id_for_lookup, 210 }) 211 } 212 213 fn rel_lookup_key(rel: &GcsLocationFindManyRel) -> String { 214 match rel { 215 GcsLocationFindManyRel::OnTradeProduct(args) => { 216 format!("on_trade_product:{}", args.id.as_str()) 217 } 218 GcsLocationFindManyRel::OffTradeProduct(args) => { 219 format!("off_trade_product:{}", args.id.as_str()) 220 } 221 GcsLocationFindManyRel::OnFarm(args) => format!("on_farm:{}", args.id.as_str()), 222 GcsLocationFindManyRel::OffFarm(args) => format!("off_farm:{}", args.id.as_str()), 223 GcsLocationFindManyRel::OnPlot(args) => format!("on_plot:{}", args.id.as_str()), 224 GcsLocationFindManyRel::OffPlot(args) => format!("off_plot:{}", args.id.as_str()), 225 } 226 }