use compact_str::CompactString;
use std::collections::HashMap;
use crate::api_request::types::FieldName;
use crate::schema_cache::routine::{Routine, RoutineParam};
use crate::types::identifiers::QualifiedIdentifier;
use super::types::CoercibleSelectField;
#[derive(Debug, Clone)]
pub struct CallPlan {
pub qi: QualifiedIdentifier,
pub params: CallParams,
pub args: CallArgs,
pub scalar: bool,
pub set_of_scalar: bool,
pub filter_fields: Vec<FieldName>,
pub returning: Vec<CoercibleSelectField>,
}
#[derive(Debug, Clone)]
pub enum CallParams {
KeyParams(Vec<RoutineParam>),
OnePosParam(RoutineParam),
}
impl CallParams {
pub fn params(&self) -> &[RoutineParam] {
match self {
CallParams::KeyParams(params) => params,
CallParams::OnePosParam(param) => std::slice::from_ref(param),
}
}
}
#[derive(Debug, Clone)]
pub enum CallArgs {
DirectArgs(HashMap<CompactString, RpcParamValue>),
JsonArgs(Option<bytes::Bytes>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RpcParamValue {
Fixed(CompactString),
Variadic(Vec<CompactString>),
}
pub fn to_rpc_params(
routine: &Routine,
params: &[(CompactString, CompactString)],
) -> HashMap<CompactString, RpcParamValue> {
let mut result = HashMap::new();
for (key, value) in params {
if let Some(rp) = routine.get_param(key) {
if rp.is_variadic {
let values: Vec<CompactString> = value
.split(',')
.map(|v| CompactString::from(v.trim()))
.collect();
result.insert(key.clone(), RpcParamValue::Variadic(values));
} else {
result.insert(key.clone(), RpcParamValue::Fixed(value.clone()));
}
} else {
result.insert(key.clone(), RpcParamValue::Fixed(value.clone()));
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_helpers::*;
#[test]
fn test_to_rpc_params_fixed() {
let routine = test_routine()
.param(test_param().name("id").pg_type("integer").build())
.param(test_param().name("name").pg_type("text").build())
.build();
let params = vec![("id".into(), "42".into()), ("name".into(), "alice".into())];
let rpc_params = to_rpc_params(&routine, ¶ms);
assert_eq!(
rpc_params.get("id"),
Some(&RpcParamValue::Fixed("42".into()))
);
assert_eq!(
rpc_params.get("name"),
Some(&RpcParamValue::Fixed("alice".into()))
);
}
#[test]
fn test_to_rpc_params_variadic() {
let routine = test_routine()
.param(
test_param()
.name("ids")
.pg_type("integer")
.is_variadic(true)
.build(),
)
.is_variadic(true)
.build();
let params = vec![("ids".into(), "1,2,3".into())];
let rpc_params = to_rpc_params(&routine, ¶ms);
assert_eq!(
rpc_params.get("ids"),
Some(&RpcParamValue::Variadic(vec![
"1".into(),
"2".into(),
"3".into()
]))
);
}
#[test]
fn test_to_rpc_params_unknown_param() {
let routine = test_routine()
.param(test_param().name("id").build())
.build();
let params = vec![("unknown_key".into(), "value".into())];
let rpc_params = to_rpc_params(&routine, ¶ms);
assert_eq!(
rpc_params.get("unknown_key"),
Some(&RpcParamValue::Fixed("value".into()))
);
}
#[test]
fn test_call_params_key_params() {
let p = test_param().name("x").build();
let cp = CallParams::KeyParams(vec![p]);
assert_eq!(cp.params().len(), 1);
}
#[test]
fn test_call_params_one_pos() {
let p = test_param().name("body").pg_type("json").build();
let cp = CallParams::OnePosParam(p);
assert_eq!(cp.params().len(), 1);
assert_eq!(cp.params()[0].name.as_str(), "body");
}
}