use std::future::Future;
use std::pin::Pin;
use crate::core::SqlValue;
pub type DeriveFuture<'a> = Pin<Box<dyn Future<Output = Result<(), String>> + Send + 'a>>;
pub type DeriveFn = for<'a> fn(
&'a mut Vec<(&'static str, SqlValue)>,
Option<&'a serde_json::Value>,
) -> DeriveFuture<'a>;
pub struct AdminDerivedField {
pub table: &'static str,
pub derive: DeriveFn,
}
inventory::collect!(AdminDerivedField);
pub(crate) async fn apply(
table: &str,
values: &mut Vec<(&'static str, SqlValue)>,
before: Option<&serde_json::Value>,
) -> Result<(), String> {
for entry in inventory::iter::<AdminDerivedField> {
if entry.table == table {
(entry.derive)(values, before).await?;
}
}
Ok(())
}
#[cfg_attr(not(feature = "sso"), allow(dead_code))]
pub(crate) fn text(
values: &[(&'static str, SqlValue)],
before: Option<&serde_json::Value>,
column: &str,
) -> Option<String> {
values
.iter()
.find(|(c, _)| *c == column)
.and_then(|(_, v)| match v {
SqlValue::String(s) => Some(s.clone()),
_ => None,
})
.or_else(|| before?.get(column)?.as_str().map(str::to_owned))
}
pub(crate) fn take_secret(
values: &mut Vec<(&'static str, SqlValue)>,
column: &str,
) -> Option<String> {
let i = values.iter().position(|(c, _)| *c == column)?;
match values.remove(i).1 {
SqlValue::String(s) => Some(s),
_ => None,
}
}