use selene_core::{DbString, NodeId, Value};
use super::error::invalid_argument;
use crate::ProcedureError;
pub(super) fn expect_arity(
procedure: &'static str,
args: &[Value],
expected: usize,
) -> Result<(), ProcedureError> {
if args.len() == expected {
return Ok(());
}
Err(invalid_argument(format!(
"{procedure} expected {expected} arguments, got {}",
args.len()
)))
}
pub(super) fn required_string(
procedure: &'static str,
args: &[Value],
index: usize,
name: &'static str,
) -> Result<String, ProcedureError> {
match &args[index] {
Value::String(value) => Ok(value.as_str().to_owned()),
other => Err(invalid_argument(format!(
"{procedure} expected {name} to be STRING, got {other:?}"
))),
}
}
pub(super) fn required_node_ref(
procedure: &'static str,
args: &[Value],
index: usize,
name: &'static str,
) -> Result<NodeId, ProcedureError> {
match &args[index] {
Value::NodeRef(value) => Ok(*value),
other => Err(invalid_argument(format!(
"{procedure}: expected {name} to be NODE, got {other:?}"
))),
}
}
pub(super) fn nullable_db_string(
procedure: &'static str,
args: &[Value],
index: usize,
name: &'static str,
) -> Result<Option<DbString>, ProcedureError> {
match &args[index] {
Value::Null => Ok(None),
Value::String(value) => Ok(Some(value.clone())),
other => Err(invalid_argument(format!(
"{procedure} expected {name} to be STRING or NULL, got {other:?}"
))),
}
}
pub(super) fn nullable_db_string_list(
procedure: &'static str,
args: &[Value],
index: usize,
name: &'static str,
) -> Result<Vec<DbString>, ProcedureError> {
match &args[index] {
Value::Null => Ok(Vec::new()),
Value::List(values) => values
.iter()
.enumerate()
.map(|(item_index, value)| match value {
Value::String(value) => Ok(value.clone()),
other => Err(invalid_argument(format!(
"{procedure} expected {name}[{item_index}] to be STRING, got {other:?}"
))),
})
.collect(),
other => Err(invalid_argument(format!(
"{procedure} expected {name} to be LIST<STRING> or NULL, got {other:?}"
))),
}
}
pub(super) fn nullable_f64(
procedure: &'static str,
args: &[Value],
index: usize,
name: &'static str,
default: f64,
) -> Result<f64, ProcedureError> {
match &args[index] {
Value::Null => Ok(default),
Value::Float(value) => Ok(*value),
Value::Float32(value) => Ok(f64::from(*value)),
Value::Int(value) => Ok(*value as f64),
Value::Uint(value) => Ok(*value as f64),
other => Err(invalid_argument(format!(
"{procedure} expected {name} to be FLOAT or NULL, got {other:?}"
))),
}
}
pub(super) fn nullable_usize(
procedure: &'static str,
args: &[Value],
index: usize,
name: &'static str,
default: usize,
) -> Result<usize, ProcedureError> {
match &args[index] {
Value::Null => Ok(default),
Value::Int(value) if *value >= 0 => usize::try_from(*value)
.map_err(|_| invalid_argument(format!("{procedure} {name} is too large"))),
Value::Int(_) => Err(invalid_argument(format!(
"{procedure} {name} must be non-negative"
))),
Value::Uint(value) => usize::try_from(*value)
.map_err(|_| invalid_argument(format!("{procedure} {name} is too large"))),
other => Err(invalid_argument(format!(
"{procedure} expected {name} to be INTEGER or NULL, got {other:?}"
))),
}
}
pub(super) fn nullable_option_usize(
procedure: &'static str,
args: &[Value],
index: usize,
name: &'static str,
) -> Result<Option<usize>, ProcedureError> {
match &args[index] {
Value::Null => Ok(None),
Value::Int(value) if *value >= 0 => usize::try_from(*value)
.map(Some)
.map_err(|_| invalid_argument(format!("{procedure}: {name} is too large"))),
Value::Int(_) => Err(invalid_argument(format!(
"{procedure}: {name} must be non-negative"
))),
Value::Uint(value) => usize::try_from(*value)
.map(Some)
.map_err(|_| invalid_argument(format!("{procedure}: {name} is too large"))),
other => Err(invalid_argument(format!(
"{procedure}: expected {name} to be INTEGER or NULL, got {other:?}"
))),
}
}
pub(super) fn required_nonnegative_usize(
procedure: &'static str,
args: &[Value],
index: usize,
name: &'static str,
) -> Result<usize, ProcedureError> {
match &args[index] {
Value::Int(value) if *value >= 0 => usize::try_from(*value)
.map_err(|_| invalid_argument(format!("{procedure}: {name} is too large"))),
Value::Int(_) => Err(invalid_argument(format!(
"{procedure}: {name} must be non-negative"
))),
Value::Uint(value) => usize::try_from(*value)
.map_err(|_| invalid_argument(format!("{procedure}: {name} is too large"))),
other => Err(invalid_argument(format!(
"{procedure}: expected {name} to be INTEGER, got {other:?}"
))),
}
}