use crate::types::{DynIden, IntoIden};
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct FunctionDef {
pub(crate) name: DynIden,
pub(crate) or_replace: bool,
pub(crate) parameters: Vec<FunctionParameter>,
pub(crate) returns: Option<String>,
pub(crate) language: Option<FunctionLanguage>,
pub(crate) behavior: Option<FunctionBehavior>,
pub(crate) security: Option<FunctionSecurity>,
pub(crate) body: Option<String>,
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct FunctionParameter {
pub(crate) name: Option<DynIden>,
pub(crate) param_type: Option<String>,
pub(crate) mode: Option<ParameterMode>,
pub(crate) default_value: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(dead_code)]
pub enum ParameterMode {
In,
Out,
InOut,
Variadic,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(dead_code)]
pub enum FunctionLanguage {
Sql,
PlPgSql,
C,
Custom(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(dead_code)]
pub enum FunctionBehavior {
Immutable,
Stable,
Volatile,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(dead_code)]
pub enum FunctionSecurity {
Definer,
Invoker,
}
impl FunctionDef {
pub fn new<N: IntoIden>(name: N) -> Self {
Self {
name: name.into_iden(),
or_replace: false,
parameters: Vec::new(),
returns: None,
language: None,
behavior: None,
security: None,
body: None,
}
}
pub fn or_replace(mut self, or_replace: bool) -> Self {
self.or_replace = or_replace;
self
}
pub fn add_parameter<N: IntoIden, T: Into<String>>(mut self, name: N, param_type: T) -> Self {
self.parameters.push(FunctionParameter {
name: Some(name.into_iden()),
param_type: Some(param_type.into()),
mode: None,
default_value: None,
});
self
}
pub fn add_parameter_spec(mut self, param: FunctionParameter) -> Self {
self.parameters.push(param);
self
}
pub fn returns<T: Into<String>>(mut self, returns: T) -> Self {
self.returns = Some(returns.into());
self
}
pub fn language(mut self, language: FunctionLanguage) -> Self {
self.language = Some(language);
self
}
pub fn behavior(mut self, behavior: FunctionBehavior) -> Self {
self.behavior = Some(behavior);
self
}
pub fn security(mut self, security: FunctionSecurity) -> Self {
self.security = Some(security);
self
}
pub fn body<B: Into<String>>(mut self, body: B) -> Self {
self.body = Some(body.into());
self
}
}
impl FunctionParameter {
pub fn new() -> Self {
Self {
name: None,
param_type: None,
mode: None,
default_value: None,
}
}
pub fn name<N: IntoIden>(mut self, name: N) -> Self {
self.name = Some(name.into_iden());
self
}
pub fn param_type<T: Into<String>>(mut self, param_type: T) -> Self {
self.param_type = Some(param_type.into());
self
}
pub fn mode(mut self, mode: ParameterMode) -> Self {
self.mode = Some(mode);
self
}
pub fn default_value<V: Into<String>>(mut self, value: V) -> Self {
self.default_value = Some(value.into());
self
}
}
impl Default for FunctionParameter {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::*;
#[rstest]
fn test_function_def_basic() {
let func = FunctionDef::new("my_func");
assert_eq!(func.name.to_string(), "my_func");
assert!(!func.or_replace);
assert!(func.parameters.is_empty());
assert!(func.returns.is_none());
assert!(func.language.is_none());
assert!(func.behavior.is_none());
assert!(func.security.is_none());
assert!(func.body.is_none());
}
#[rstest]
fn test_function_def_or_replace() {
let func = FunctionDef::new("my_func").or_replace(true);
assert_eq!(func.name.to_string(), "my_func");
assert!(func.or_replace);
}
#[rstest]
fn test_function_def_add_parameter() {
let func = FunctionDef::new("my_func").add_parameter("param1", "integer");
assert_eq!(func.parameters.len(), 1);
assert_eq!(
func.parameters[0].name.as_ref().unwrap().to_string(),
"param1"
);
assert_eq!(func.parameters[0].param_type.as_ref().unwrap(), "integer");
}
#[rstest]
fn test_function_def_multiple_parameters() {
let func = FunctionDef::new("my_func")
.add_parameter("param1", "integer")
.add_parameter("param2", "text");
assert_eq!(func.parameters.len(), 2);
assert_eq!(
func.parameters[0].name.as_ref().unwrap().to_string(),
"param1"
);
assert_eq!(func.parameters[0].param_type.as_ref().unwrap(), "integer");
assert_eq!(
func.parameters[1].name.as_ref().unwrap().to_string(),
"param2"
);
assert_eq!(func.parameters[1].param_type.as_ref().unwrap(), "text");
}
#[rstest]
fn test_function_def_returns() {
let func = FunctionDef::new("my_func").returns("integer");
assert_eq!(func.returns.as_ref().unwrap(), "integer");
}
#[rstest]
fn test_function_def_language_sql() {
let func = FunctionDef::new("my_func").language(FunctionLanguage::Sql);
assert_eq!(func.language, Some(FunctionLanguage::Sql));
}
#[rstest]
fn test_function_def_language_plpgsql() {
let func = FunctionDef::new("my_func").language(FunctionLanguage::PlPgSql);
assert_eq!(func.language, Some(FunctionLanguage::PlPgSql));
}
#[rstest]
fn test_function_def_behavior_immutable() {
let func = FunctionDef::new("my_func").behavior(FunctionBehavior::Immutable);
assert_eq!(func.behavior, Some(FunctionBehavior::Immutable));
}
#[rstest]
fn test_function_def_behavior_stable() {
let func = FunctionDef::new("my_func").behavior(FunctionBehavior::Stable);
assert_eq!(func.behavior, Some(FunctionBehavior::Stable));
}
#[rstest]
fn test_function_def_behavior_volatile() {
let func = FunctionDef::new("my_func").behavior(FunctionBehavior::Volatile);
assert_eq!(func.behavior, Some(FunctionBehavior::Volatile));
}
#[rstest]
fn test_function_def_security_definer() {
let func = FunctionDef::new("my_func").security(FunctionSecurity::Definer);
assert_eq!(func.security, Some(FunctionSecurity::Definer));
}
#[rstest]
fn test_function_def_security_invoker() {
let func = FunctionDef::new("my_func").security(FunctionSecurity::Invoker);
assert_eq!(func.security, Some(FunctionSecurity::Invoker));
}
#[rstest]
fn test_function_def_body() {
let func = FunctionDef::new("my_func").body("SELECT 1");
assert_eq!(func.body.as_ref().unwrap(), "SELECT 1");
}
#[rstest]
fn test_function_def_all_options() {
let func = FunctionDef::new("my_func")
.or_replace(true)
.add_parameter("a", "integer")
.add_parameter("b", "text")
.returns("integer")
.language(FunctionLanguage::PlPgSql)
.behavior(FunctionBehavior::Immutable)
.security(FunctionSecurity::Definer)
.body("BEGIN RETURN a + LENGTH(b); END;");
assert_eq!(func.name.to_string(), "my_func");
assert!(func.or_replace);
assert_eq!(func.parameters.len(), 2);
assert_eq!(func.returns.as_ref().unwrap(), "integer");
assert_eq!(func.language, Some(FunctionLanguage::PlPgSql));
assert_eq!(func.behavior, Some(FunctionBehavior::Immutable));
assert_eq!(func.security, Some(FunctionSecurity::Definer));
assert_eq!(
func.body.as_ref().unwrap(),
"BEGIN RETURN a + LENGTH(b); END;"
);
}
#[rstest]
fn test_function_parameter_basic() {
let param = FunctionParameter::new();
assert!(param.name.is_none());
assert!(param.param_type.is_none());
assert!(param.mode.is_none());
assert!(param.default_value.is_none());
}
#[rstest]
fn test_function_parameter_name() {
let param = FunctionParameter::new().name("my_param");
assert_eq!(param.name.as_ref().unwrap().to_string(), "my_param");
}
#[rstest]
fn test_function_parameter_type() {
let param = FunctionParameter::new().param_type("integer");
assert_eq!(param.param_type.as_ref().unwrap(), "integer");
}
#[rstest]
fn test_function_parameter_mode_in() {
let param = FunctionParameter::new().mode(ParameterMode::In);
assert_eq!(param.mode, Some(ParameterMode::In));
}
#[rstest]
fn test_function_parameter_mode_out() {
let param = FunctionParameter::new().mode(ParameterMode::Out);
assert_eq!(param.mode, Some(ParameterMode::Out));
}
#[rstest]
fn test_function_parameter_mode_inout() {
let param = FunctionParameter::new().mode(ParameterMode::InOut);
assert_eq!(param.mode, Some(ParameterMode::InOut));
}
#[rstest]
fn test_function_parameter_mode_variadic() {
let param = FunctionParameter::new().mode(ParameterMode::Variadic);
assert_eq!(param.mode, Some(ParameterMode::Variadic));
}
#[rstest]
fn test_function_parameter_default_value() {
let param = FunctionParameter::new().default_value("42");
assert_eq!(param.default_value.as_ref().unwrap(), "42");
}
#[rstest]
fn test_function_parameter_all_options() {
let param = FunctionParameter::new()
.name("my_param")
.param_type("integer")
.mode(ParameterMode::InOut)
.default_value("42");
assert_eq!(param.name.as_ref().unwrap().to_string(), "my_param");
assert_eq!(param.param_type.as_ref().unwrap(), "integer");
assert_eq!(param.mode, Some(ParameterMode::InOut));
assert_eq!(param.default_value.as_ref().unwrap(), "42");
}
#[rstest]
fn test_function_def_add_parameter_spec() {
let param = FunctionParameter::new()
.name("my_param")
.param_type("integer")
.mode(ParameterMode::Out);
let func = FunctionDef::new("my_func").add_parameter_spec(param);
assert_eq!(func.parameters.len(), 1);
assert_eq!(
func.parameters[0].name.as_ref().unwrap().to_string(),
"my_param"
);
assert_eq!(func.parameters[0].param_type.as_ref().unwrap(), "integer");
assert_eq!(func.parameters[0].mode, Some(ParameterMode::Out));
}
#[rstest]
fn test_function_language_custom() {
let lang = FunctionLanguage::Custom("plpython3u".to_string());
assert_eq!(lang, FunctionLanguage::Custom("plpython3u".to_string()));
}
}