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