use crate::api_request::QualifiedIdentifier;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Routine {
pub schema: String,
pub name: String,
pub description: Option<String>,
pub params: Vec<RoutineParam>,
pub return_type: RetType,
pub volatility: FuncVolatility,
pub has_variadic: bool,
pub isolation_level: Option<String>,
pub settings: Vec<(String, String)>,
pub is_procedure: bool,
}
impl Routine {
pub fn qualified_identifier(&self) -> QualifiedIdentifier {
QualifiedIdentifier::new(&self.schema, &self.name)
}
pub fn is_safe_for_get(&self) -> bool {
matches!(self.volatility, FuncVolatility::Immutable | FuncVolatility::Stable)
}
pub fn required_params(&self) -> impl Iterator<Item = &RoutineParam> {
self.params.iter().filter(|p| p.required)
}
pub fn find_param(&self, name: &str) -> Option<&RoutineParam> {
self.params.iter().find(|p| p.name == name)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RoutineParam {
pub name: String,
pub param_type: String,
pub type_max_length: String,
pub required: bool,
pub variadic: bool,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum RetType {
Single(String),
SetOf(String),
Table(Vec<(String, String)>),
Void,
}
impl RetType {
pub fn is_set_returning(&self) -> bool {
matches!(self, Self::SetOf(_) | Self::Table(_))
}
pub fn type_name(&self) -> Option<&str> {
match self {
Self::Single(t) => Some(t),
Self::SetOf(t) => Some(t),
Self::Table(_) => None,
Self::Void => None,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum FuncVolatility {
Immutable,
Stable,
Volatile,
}
impl FuncVolatility {
pub fn from_char(c: char) -> Self {
match c {
'i' => Self::Immutable,
's' => Self::Stable,
_ => Self::Volatile,
}
}
}
pub type RoutineMap = HashMap<QualifiedIdentifier, Vec<Routine>>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_routine_is_safe_for_get() {
let mut routine = Routine {
schema: "public".into(),
name: "get_users".into(),
description: None,
params: vec![],
return_type: RetType::SetOf("users".into()),
volatility: FuncVolatility::Stable,
has_variadic: false,
isolation_level: None,
settings: vec![],
is_procedure: false,
};
assert!(routine.is_safe_for_get());
routine.volatility = FuncVolatility::Volatile;
assert!(!routine.is_safe_for_get());
}
#[test]
fn test_ret_type_is_set_returning() {
assert!(!RetType::Single("text".into()).is_set_returning());
assert!(RetType::SetOf("users".into()).is_set_returning());
assert!(RetType::Table(vec![("id".into(), "int".into())]).is_set_returning());
assert!(!RetType::Void.is_set_returning());
}
#[test]
fn test_func_volatility_from_char() {
assert_eq!(FuncVolatility::from_char('i'), FuncVolatility::Immutable);
assert_eq!(FuncVolatility::from_char('s'), FuncVolatility::Stable);
assert_eq!(FuncVolatility::from_char('v'), FuncVolatility::Volatile);
assert_eq!(FuncVolatility::from_char('x'), FuncVolatility::Volatile);
}
}