dbui-database 0.0.64

Database access and schema introspection for dbui
Documentation
use anyhow::Result;
use dbui_core::field_type::FieldType;
use tokio_postgres::types::FromSql;
use uuid::Uuid;

pub(crate) fn to_string(row: &postgres::row::Row, idx: usize, ft: &FieldType) -> Result<Option<String>> {
  match ft {
    FieldType::Unit => Ok(Some("{unit}".into())),
    FieldType::String => get_opt::<String>(row, idx),
    FieldType::EncryptedString => get_opt::<String>(row, idx),

    FieldType::Boolean => Ok(get_opt::<bool>(row, idx)?.map(|b| b.to_string())),
    FieldType::Char => Ok(get_opt::<i8>(row, idx)?.map(|u| ((u as u8) as char).to_string())),
    FieldType::I16 => Ok(get_opt::<i16>(row, idx)?.map(|i| i.to_string())),
    FieldType::I32 => Ok(get_opt::<i32>(row, idx)?.map(|i| i.to_string())),
    FieldType::U32 => Ok(get_opt::<u32>(row, idx)?.map(|u| u.to_string())),
    FieldType::I64 => Ok(get_opt::<i64>(row, idx)?.map(|i| i.to_string())),
    FieldType::F32 => Ok(get_opt::<f32>(row, idx)?.map(|f| f.to_string())),
    FieldType::F64 => Ok(get_opt::<f64>(row, idx)?.map(|f| f.to_string())),
    FieldType::Numeric => Ok(Some("{numeric}".into())),

    FieldType::Date => Ok(get_opt::<chrono::NaiveDate>(row, idx)?.map(|t| t.to_string())),
    FieldType::Time => Ok(get_opt::<chrono::NaiveTime>(row, idx)?.map(|t| t.to_string())),
    FieldType::TimeZoned => Ok(Some("{timetz}".into())),
    FieldType::Timestamp => Ok(get_opt::<chrono::NaiveDateTime>(row, idx)?.map(|t| t.to_string())),
    FieldType::TimestampZoned => Ok(get_opt::<chrono::DateTime<chrono::Utc>>(row, idx)?.map(|t| t.to_string())),
    FieldType::Interval => Ok(Some("{interval}".into())),

    FieldType::Uuid => Ok(get_opt::<Uuid>(row, idx)?.map(|u| u.to_string())),
    FieldType::Json => Ok(
      get_opt::<serde_json::Value>(row, idx)?.map(|j| match serde_json::to_string_pretty(&j) {
        Ok(s) => s,
        Err(e) => format!("Error writing json: [{}]", e)
      })
    ),
    FieldType::Xml => Ok(Some("{xml}".into())),
    FieldType::StringMap => Ok(get_opt::<std::collections::HashMap<String, Option<String>>>(row, idx)?.map(|m| {
      let mut vec: Vec<String> = m
        .iter()
        .map(|e| format!("{}: {}", e.0, e.1.as_ref().unwrap_or(&"∅".to_string())))
        .collect();
      vec.sort();
      format!("{{ {} }}", vec.join(", "))
    })),

    FieldType::ByteArray => Ok(get_opt::<Vec<u8>>(row, idx)?.map(|b| format!("{:?}", b))),
    FieldType::BitArray => Ok(get_opt::<bit_vec::BitVec>(row, idx)?.map(|b| format!("{:?}", b))),

    FieldType::Cidr => Ok(Some("{cidr}".into())),
    FieldType::InetAddr => Ok(Some("{inet}".into())),
    FieldType::MacAddr => Ok(get_opt::<eui48::MacAddress>(row, idx)?.map(|u| u.to_string(eui48::MacAddressFormat::HexString))),

    FieldType::Box => Ok(Some("{box}".into())),
    FieldType::Circle => Ok(Some("{circle}".into())),
    FieldType::Path => Ok(Some("{path}".into())),
    FieldType::Point => Ok(get_opt::<geo_types::Point<f64>>(row, idx)?.map(|p| format!("({},{})", p.0.x, p.0.y))),
    FieldType::Polygon => Ok(Some("{polygon}".into())),

    FieldType::TsQuery => Ok(Some("{tsquery}".into())),
    FieldType::TsVector => Ok(Some("{tsvector}".into())),

    FieldType::List { t } => crate::results::array_to_string::array_to_string(row, idx, t),
    FieldType::Set { t } => Ok(Some(format!("Set[{:?}]", t))),
    FieldType::Map { k, v } => Ok(Some(format!("Map[{:?}, {:?}]", k, v))),

    FieldType::Range { t } => Ok(Some(format!("Range[{:?}]", t))),
    FieldType::Domain { t } => Ok(Some(format!("Domain[{:?}]", t))),

    FieldType::Enum { key } => Ok(Some(format!("Enum({})", key))),
    FieldType::Struct { key } => Ok(Some(format!("Struct({})", key))),
    FieldType::Object { key, fields } => Ok(Some(format!("Object({})[{:?}]", key, fields))),
    FieldType::Intersection { key, types } => Ok(Some(format!("Intersection({})[{:?}]", key, types))),
    FieldType::Union { key, types } => Ok(Some(format!("Union({})[{:?}]", key, types))),
    FieldType::Method { params, ret } => Ok(Some(format!("Method({:?}): {:?}", params, ret))),

    FieldType::Unknown { t } => Ok(Some(format!("Unknown[{}]", t)))
  }
}

fn get_opt<'a, T: FromSql<'a>>(row: &'a postgres::row::Row, idx: usize) -> Result<Option<T>> {
  let o: Result<Option<T>> = crate::get_idx(row, idx);
  o
}