lib

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

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