lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

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, &params_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, &params_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, &params_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, &params_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, &params_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, &params_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, &params_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, &params_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 }