1use crate::types::{DynIden, IntoIden};
35
36#[derive(Debug, Clone)]
53#[allow(dead_code)]
55pub struct FunctionDef {
56 pub(crate) name: DynIden,
57 pub(crate) or_replace: bool,
58 pub(crate) parameters: Vec<FunctionParameter>,
59 pub(crate) returns: Option<String>,
60 pub(crate) language: Option<FunctionLanguage>,
61 pub(crate) behavior: Option<FunctionBehavior>,
62 pub(crate) security: Option<FunctionSecurity>,
63 pub(crate) body: Option<String>,
64}
65
66#[derive(Debug, Clone)]
87#[allow(dead_code)]
89pub struct FunctionParameter {
90 pub(crate) name: Option<DynIden>,
91 pub(crate) param_type: Option<String>,
92 pub(crate) mode: Option<ParameterMode>,
93 pub(crate) default_value: Option<String>,
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
100#[allow(dead_code)]
102pub enum ParameterMode {
103 In,
105 Out,
107 InOut,
109 Variadic,
111}
112
113#[derive(Debug, Clone, PartialEq, Eq)]
128#[allow(dead_code)]
130pub enum FunctionLanguage {
131 Sql,
133 PlPgSql,
135 C,
137 Custom(String),
143}
144
145#[derive(Debug, Clone, PartialEq, Eq)]
159#[allow(dead_code)]
161pub enum FunctionBehavior {
162 Immutable,
164 Stable,
166 Volatile,
168}
169
170#[derive(Debug, Clone, PartialEq, Eq)]
183#[allow(dead_code)]
185pub enum FunctionSecurity {
186 Definer,
188 Invoker,
190}
191
192impl FunctionDef {
193 pub fn new<N: IntoIden>(name: N) -> Self {
203 Self {
204 name: name.into_iden(),
205 or_replace: false,
206 parameters: Vec::new(),
207 returns: None,
208 language: None,
209 behavior: None,
210 security: None,
211 body: None,
212 }
213 }
214
215 pub fn or_replace(mut self, or_replace: bool) -> Self {
226 self.or_replace = or_replace;
227 self
228 }
229
230 pub fn add_parameter<N: IntoIden, T: Into<String>>(mut self, name: N, param_type: T) -> Self {
242 self.parameters.push(FunctionParameter {
243 name: Some(name.into_iden()),
244 param_type: Some(param_type.into()),
245 mode: None,
246 default_value: None,
247 });
248 self
249 }
250
251 pub fn add_parameter_spec(mut self, param: FunctionParameter) -> Self {
267 self.parameters.push(param);
268 self
269 }
270
271 pub fn returns<T: Into<String>>(mut self, returns: T) -> Self {
282 self.returns = Some(returns.into());
283 self
284 }
285
286 pub fn language(mut self, language: FunctionLanguage) -> Self {
297 self.language = Some(language);
298 self
299 }
300
301 pub fn behavior(mut self, behavior: FunctionBehavior) -> Self {
312 self.behavior = Some(behavior);
313 self
314 }
315
316 pub fn security(mut self, security: FunctionSecurity) -> Self {
327 self.security = Some(security);
328 self
329 }
330
331 pub fn body<B: Into<String>>(mut self, body: B) -> Self {
342 self.body = Some(body.into());
343 self
344 }
345}
346
347impl FunctionParameter {
348 pub fn new() -> Self {
358 Self {
359 name: None,
360 param_type: None,
361 mode: None,
362 default_value: None,
363 }
364 }
365
366 pub fn name<N: IntoIden>(mut self, name: N) -> Self {
377 self.name = Some(name.into_iden());
378 self
379 }
380
381 pub fn param_type<T: Into<String>>(mut self, param_type: T) -> Self {
392 self.param_type = Some(param_type.into());
393 self
394 }
395
396 pub fn mode(mut self, mode: ParameterMode) -> Self {
407 self.mode = Some(mode);
408 self
409 }
410
411 pub fn default_value<V: Into<String>>(mut self, value: V) -> Self {
422 self.default_value = Some(value.into());
423 self
424 }
425}
426
427impl Default for FunctionParameter {
428 fn default() -> Self {
429 Self::new()
430 }
431}
432
433#[cfg(test)]
434mod tests {
435 use super::*;
436 use rstest::*;
437
438 #[rstest]
440 fn test_function_def_basic() {
441 let func = FunctionDef::new("my_func");
442 assert_eq!(func.name.to_string(), "my_func");
443 assert!(!func.or_replace);
444 assert!(func.parameters.is_empty());
445 assert!(func.returns.is_none());
446 assert!(func.language.is_none());
447 assert!(func.behavior.is_none());
448 assert!(func.security.is_none());
449 assert!(func.body.is_none());
450 }
451
452 #[rstest]
453 fn test_function_parameter_default() {
454 let parameter = FunctionParameter::default();
455 assert!(parameter.name.is_none());
456 assert!(parameter.param_type.is_none());
457 }
458
459 #[rstest]
460 fn test_function_def_or_replace() {
461 let func = FunctionDef::new("my_func").or_replace(true);
462 assert_eq!(func.name.to_string(), "my_func");
463 assert!(func.or_replace);
464 }
465
466 #[rstest]
467 fn test_function_def_add_parameter() {
468 let func = FunctionDef::new("my_func").add_parameter("param1", "integer");
469 assert_eq!(func.parameters.len(), 1);
470 assert_eq!(
471 func.parameters[0].name.as_ref().unwrap().to_string(),
472 "param1"
473 );
474 assert_eq!(func.parameters[0].param_type.as_ref().unwrap(), "integer");
475 }
476
477 #[rstest]
478 fn test_function_def_multiple_parameters() {
479 let func = FunctionDef::new("my_func")
480 .add_parameter("param1", "integer")
481 .add_parameter("param2", "text");
482 assert_eq!(func.parameters.len(), 2);
483 assert_eq!(
484 func.parameters[0].name.as_ref().unwrap().to_string(),
485 "param1"
486 );
487 assert_eq!(func.parameters[0].param_type.as_ref().unwrap(), "integer");
488 assert_eq!(
489 func.parameters[1].name.as_ref().unwrap().to_string(),
490 "param2"
491 );
492 assert_eq!(func.parameters[1].param_type.as_ref().unwrap(), "text");
493 }
494
495 #[rstest]
496 fn test_function_def_returns() {
497 let func = FunctionDef::new("my_func").returns("integer");
498 assert_eq!(func.returns.as_ref().unwrap(), "integer");
499 }
500
501 #[rstest]
502 fn test_function_def_language_sql() {
503 let func = FunctionDef::new("my_func").language(FunctionLanguage::Sql);
504 assert_eq!(func.language, Some(FunctionLanguage::Sql));
505 }
506
507 #[rstest]
508 fn test_function_def_language_plpgsql() {
509 let func = FunctionDef::new("my_func").language(FunctionLanguage::PlPgSql);
510 assert_eq!(func.language, Some(FunctionLanguage::PlPgSql));
511 }
512
513 #[rstest]
514 fn test_function_def_behavior_immutable() {
515 let func = FunctionDef::new("my_func").behavior(FunctionBehavior::Immutable);
516 assert_eq!(func.behavior, Some(FunctionBehavior::Immutable));
517 }
518
519 #[rstest]
520 fn test_function_def_behavior_stable() {
521 let func = FunctionDef::new("my_func").behavior(FunctionBehavior::Stable);
522 assert_eq!(func.behavior, Some(FunctionBehavior::Stable));
523 }
524
525 #[rstest]
526 fn test_function_def_behavior_volatile() {
527 let func = FunctionDef::new("my_func").behavior(FunctionBehavior::Volatile);
528 assert_eq!(func.behavior, Some(FunctionBehavior::Volatile));
529 }
530
531 #[rstest]
532 fn test_function_def_security_definer() {
533 let func = FunctionDef::new("my_func").security(FunctionSecurity::Definer);
534 assert_eq!(func.security, Some(FunctionSecurity::Definer));
535 }
536
537 #[rstest]
538 fn test_function_def_security_invoker() {
539 let func = FunctionDef::new("my_func").security(FunctionSecurity::Invoker);
540 assert_eq!(func.security, Some(FunctionSecurity::Invoker));
541 }
542
543 #[rstest]
544 fn test_function_def_body() {
545 let func = FunctionDef::new("my_func").body("SELECT 1");
546 assert_eq!(func.body.as_ref().unwrap(), "SELECT 1");
547 }
548
549 #[rstest]
550 fn test_function_def_all_options() {
551 let func = FunctionDef::new("my_func")
552 .or_replace(true)
553 .add_parameter("a", "integer")
554 .add_parameter("b", "text")
555 .returns("integer")
556 .language(FunctionLanguage::PlPgSql)
557 .behavior(FunctionBehavior::Immutable)
558 .security(FunctionSecurity::Definer)
559 .body("BEGIN RETURN a + LENGTH(b); END;");
560
561 assert_eq!(func.name.to_string(), "my_func");
562 assert!(func.or_replace);
563 assert_eq!(func.parameters.len(), 2);
564 assert_eq!(func.returns.as_ref().unwrap(), "integer");
565 assert_eq!(func.language, Some(FunctionLanguage::PlPgSql));
566 assert_eq!(func.behavior, Some(FunctionBehavior::Immutable));
567 assert_eq!(func.security, Some(FunctionSecurity::Definer));
568 assert_eq!(
569 func.body.as_ref().unwrap(),
570 "BEGIN RETURN a + LENGTH(b); END;"
571 );
572 }
573
574 #[rstest]
576 fn test_function_parameter_basic() {
577 let param = FunctionParameter::new();
578 assert!(param.name.is_none());
579 assert!(param.param_type.is_none());
580 assert!(param.mode.is_none());
581 assert!(param.default_value.is_none());
582 }
583
584 #[rstest]
585 fn test_function_parameter_name() {
586 let param = FunctionParameter::new().name("my_param");
587 assert_eq!(param.name.as_ref().unwrap().to_string(), "my_param");
588 }
589
590 #[rstest]
591 fn test_function_parameter_type() {
592 let param = FunctionParameter::new().param_type("integer");
593 assert_eq!(param.param_type.as_ref().unwrap(), "integer");
594 }
595
596 #[rstest]
597 fn test_function_parameter_mode_in() {
598 let param = FunctionParameter::new().mode(ParameterMode::In);
599 assert_eq!(param.mode, Some(ParameterMode::In));
600 }
601
602 #[rstest]
603 fn test_function_parameter_mode_out() {
604 let param = FunctionParameter::new().mode(ParameterMode::Out);
605 assert_eq!(param.mode, Some(ParameterMode::Out));
606 }
607
608 #[rstest]
609 fn test_function_parameter_mode_inout() {
610 let param = FunctionParameter::new().mode(ParameterMode::InOut);
611 assert_eq!(param.mode, Some(ParameterMode::InOut));
612 }
613
614 #[rstest]
615 fn test_function_parameter_mode_variadic() {
616 let param = FunctionParameter::new().mode(ParameterMode::Variadic);
617 assert_eq!(param.mode, Some(ParameterMode::Variadic));
618 }
619
620 #[rstest]
621 fn test_function_parameter_default_value() {
622 let param = FunctionParameter::new().default_value("42");
623 assert_eq!(param.default_value.as_ref().unwrap(), "42");
624 }
625
626 #[rstest]
627 fn test_function_parameter_all_options() {
628 let param = FunctionParameter::new()
629 .name("my_param")
630 .param_type("integer")
631 .mode(ParameterMode::InOut)
632 .default_value("42");
633
634 assert_eq!(param.name.as_ref().unwrap().to_string(), "my_param");
635 assert_eq!(param.param_type.as_ref().unwrap(), "integer");
636 assert_eq!(param.mode, Some(ParameterMode::InOut));
637 assert_eq!(param.default_value.as_ref().unwrap(), "42");
638 }
639
640 #[rstest]
641 fn test_function_def_add_parameter_spec() {
642 let param = FunctionParameter::new()
643 .name("my_param")
644 .param_type("integer")
645 .mode(ParameterMode::Out);
646
647 let func = FunctionDef::new("my_func").add_parameter_spec(param);
648
649 assert_eq!(func.parameters.len(), 1);
650 assert_eq!(
651 func.parameters[0].name.as_ref().unwrap().to_string(),
652 "my_param"
653 );
654 assert_eq!(func.parameters[0].param_type.as_ref().unwrap(), "integer");
655 assert_eq!(func.parameters[0].mode, Some(ParameterMode::Out));
656 }
657
658 #[rstest]
660 fn test_function_language_custom() {
661 let lang = FunctionLanguage::Custom("plpython3u".to_string());
662 assert_eq!(lang, FunctionLanguage::Custom("plpython3u".to_string()));
663 }
664}