lib

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

nostr_relay.rs (8131B)


      1 use radroots_replica_db_schema::nostr_relay::{
      2     INostrRelayCreate, INostrRelayCreateResolve, INostrRelayDelete, INostrRelayDeleteResolve,
      3     INostrRelayFieldsFilter, INostrRelayFindMany, INostrRelayFindManyResolve, INostrRelayFindOne,
      4     INostrRelayFindOneResolve, INostrRelayUpdate, INostrRelayUpdateResolve, NostrRelay,
      5     NostrRelayFindManyRel, NostrRelayQueryBindValues,
      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 = "nostr_relay";
     13 
     14 pub fn create(
     15     exec: &dyn SqlExecutor,
     16     opts: &INostrRelayCreate,
     17 ) -> Result<INostrRelayCreateResolve, 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 = NostrRelayQueryBindValues::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: &INostrRelayFindOne,
     37 ) -> Result<INostrRelayFindOneResolve, IError<SqlError>> {
     38     let result = match opts {
     39         INostrRelayFindOne::On(args) => find_one_by_on(exec, &args.on)?,
     40         INostrRelayFindOne::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: &INostrRelayFindMany,
     48 ) -> Result<INostrRelayFindManyResolve, IError<SqlError>> {
     49     let results = match opts {
     50         INostrRelayFindMany::Filter { filter } => find_many_filter(exec, filter)?,
     51         INostrRelayFindMany::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<INostrRelayFieldsFilter>,
     59 ) -> Result<Vec<NostrRelay>, 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<NostrRelay> = utils::parse_json(&json)?;
     64     Ok(rows)
     65 }
     66 
     67 fn find_one_by_on(
     68     exec: &dyn SqlExecutor,
     69     on: &NostrRelayQueryBindValues,
     70 ) -> Result<Option<NostrRelay>, 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<NostrRelay> = utils::parse_json(&json)?;
     76     Ok(rows.pop())
     77 }
     78 
     79 fn rel_query(rel: &NostrRelayFindManyRel) -> (&'static str, Vec<Value>) {
     80     match rel {
     81         NostrRelayFindManyRel::OnProfile(args) => (
     82             "SELECT rl.* FROM nostr_relay rl JOIN nostr_profile_relay pr_rl ON rl.id = pr_rl.tb_rl JOIN nostr_profile pr ON pr.id = pr_rl.tb_pr WHERE pr.public_key = ?",
     83             vec![Value::from(args.public_key.clone())],
     84         ),
     85         NostrRelayFindManyRel::OffProfile(args) => (
     86             "SELECT rl.* FROM nostr_relay rl LEFT JOIN nostr_profile_relay pr_rl ON rl.id = pr_rl.tb_rl LEFT JOIN nostr_profile pr ON pr.id = pr_rl.tb_pr WHERE pr.public_key <> ?",
     87             vec![Value::from(args.public_key.clone())],
     88         ),
     89     }
     90 }
     91 
     92 fn find_one_by_rel(
     93     exec: &dyn SqlExecutor,
     94     rel: &NostrRelayFindManyRel,
     95 ) -> Result<Option<NostrRelay>, IError<SqlError>> {
     96     let (sql, bind_values) = rel_query(rel);
     97     let params_json = utils::to_params_json(bind_values).expect("serialize bind params");
     98     let sql = format!("{sql} LIMIT 1;");
     99     let json = exec.query_raw(&sql, &params_json)?;
    100     let mut rows: Vec<NostrRelay> = utils::parse_json(&json)?;
    101     Ok(rows.pop())
    102 }
    103 
    104 fn find_many_by_rel(
    105     exec: &dyn SqlExecutor,
    106     rel: &NostrRelayFindManyRel,
    107 ) -> Result<Vec<NostrRelay>, IError<SqlError>> {
    108     let (sql, bind_values) = rel_query(rel);
    109     let params_json = utils::to_params_json(bind_values).expect("serialize bind params");
    110     let sql = format!("{sql};");
    111     let json = exec.query_raw(&sql, &params_json)?;
    112     let rows: Vec<NostrRelay> = utils::parse_json(&json)?;
    113     Ok(rows)
    114 }
    115 
    116 fn select_by_id(exec: &dyn SqlExecutor, id: &str) -> Result<NostrRelay, IError<SqlError>> {
    117     let params_json =
    118         utils::to_params_json(vec![Value::from(id.to_owned())]).expect("serialize bind params");
    119     let sql = format!("SELECT * FROM {TABLE_NAME} WHERE id = ?;");
    120     let json = exec.query_raw(&sql, &params_json)?;
    121     let mut rows: Vec<NostrRelay> = utils::parse_json(&json)?;
    122     rows.pop()
    123         .ok_or(IError::from(SqlError::NotFound(id.to_owned())))
    124 }
    125 
    126 pub fn update(
    127     exec: &dyn SqlExecutor,
    128     opts: &INostrRelayUpdate,
    129 ) -> Result<INostrRelayUpdateResolve, IError<SqlError>> {
    130     let mut updates =
    131         utils::to_partial_object_map(&opts.fields).expect("serialize partial object map");
    132     if updates.is_empty() {
    133         return Err(IError::from(SqlError::InvalidArgument(String::from(
    134             "no fields to update",
    135         ))));
    136     }
    137     updates.insert(
    138         String::from("updated_at"),
    139         Value::from(utils::time_created_on()),
    140     );
    141     let mut set_parts = Vec::with_capacity(updates.len());
    142     let mut bind_values = Vec::with_capacity(updates.len() + 1);
    143     for (column, value) in updates {
    144         set_parts.push(format!("{column} = ?"));
    145         bind_values.push(utils::to_db_bind_value(&value));
    146     }
    147     let id_for_lookup = match opts.on.primary_key() {
    148         Some(id) => id,
    149         None => {
    150             let found = find_one_by_on(exec, &opts.on)?;
    151             let model = found.ok_or(IError::from(SqlError::NotFound(opts.on.lookup_key())))?;
    152             model.id
    153         }
    154     };
    155     bind_values.push(Value::from(id_for_lookup.clone()));
    156     let sql = format!(
    157         "UPDATE {TABLE_NAME} SET {} WHERE id = ?;",
    158         set_parts.join(", ")
    159     );
    160     let params_json = utils::to_params_json(bind_values).expect("serialize bind params");
    161     let _ = exec.exec(&sql, &params_json)?;
    162     let updated = select_by_id(exec, &id_for_lookup)?;
    163     Ok(IResult { result: updated })
    164 }
    165 
    166 pub fn delete(
    167     exec: &dyn SqlExecutor,
    168     opts: &INostrRelayDelete,
    169 ) -> Result<INostrRelayDeleteResolve, IError<SqlError>> {
    170     let id_for_lookup = match opts {
    171         INostrRelayDelete::On(args) => match args.on.primary_key() {
    172             Some(id) => id,
    173             None => {
    174                 let found = find_one_by_on(exec, &args.on)?;
    175                 let model = found.ok_or(IError::from(SqlError::NotFound(args.on.lookup_key())))?;
    176                 model.id
    177             }
    178         },
    179         INostrRelayDelete::Rel(args) => {
    180             let found = find_one_by_rel(exec, &args.rel)?;
    181             let model = found.ok_or(IError::from(SqlError::NotFound(rel_lookup_key(&args.rel))))?;
    182             model.id
    183         }
    184     };
    185     let params_json = utils::to_params_json(vec![Value::from(id_for_lookup.clone())])
    186         .expect("serialize bind params");
    187     let sql = format!("DELETE FROM {TABLE_NAME} WHERE id = ?;");
    188     let outcome = exec.exec(&sql, &params_json)?;
    189     if outcome.changes == 0 {
    190         return Err(IError::from(SqlError::NotFound(id_for_lookup.clone())));
    191     }
    192     Ok(IResult {
    193         result: id_for_lookup,
    194     })
    195 }
    196 
    197 fn rel_lookup_key(rel: &NostrRelayFindManyRel) -> String {
    198     match rel {
    199         NostrRelayFindManyRel::OnProfile(args) => {
    200             format!("on_profile:{}", args.public_key.as_str())
    201         }
    202         NostrRelayFindManyRel::OffProfile(args) => {
    203             format!("off_profile:{}", args.public_key.as_str())
    204         }
    205     }
    206 }