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_def_or_replace() {
454 let func = FunctionDef::new("my_func").or_replace(true);
455 assert_eq!(func.name.to_string(), "my_func");
456 assert!(func.or_replace);
457 }
458
459 #[rstest]
460 fn test_function_def_add_parameter() {
461 let func = FunctionDef::new("my_func").add_parameter("param1", "integer");
462 assert_eq!(func.parameters.len(), 1);
463 assert_eq!(
464 func.parameters[0].name.as_ref().unwrap().to_string(),
465 "param1"
466 );
467 assert_eq!(func.parameters[0].param_type.as_ref().unwrap(), "integer");
468 }
469
470 #[rstest]
471 fn test_function_def_multiple_parameters() {
472 let func = FunctionDef::new("my_func")
473 .add_parameter("param1", "integer")
474 .add_parameter("param2", "text");
475 assert_eq!(func.parameters.len(), 2);
476 assert_eq!(
477 func.parameters[0].name.as_ref().unwrap().to_string(),
478 "param1"
479 );
480 assert_eq!(func.parameters[0].param_type.as_ref().unwrap(), "integer");
481 assert_eq!(
482 func.parameters[1].name.as_ref().unwrap().to_string(),
483 "param2"
484 );
485 assert_eq!(func.parameters[1].param_type.as_ref().unwrap(), "text");
486 }
487
488 #[rstest]
489 fn test_function_def_returns() {
490 let func = FunctionDef::new("my_func").returns("integer");
491 assert_eq!(func.returns.as_ref().unwrap(), "integer");
492 }
493
494 #[rstest]
495 fn test_function_def_language_sql() {
496 let func = FunctionDef::new("my_func").language(FunctionLanguage::Sql);
497 assert_eq!(func.language, Some(FunctionLanguage::Sql));
498 }
499
500 #[rstest]
501 fn test_function_def_language_plpgsql() {
502 let func = FunctionDef::new("my_func").language(FunctionLanguage::PlPgSql);
503 assert_eq!(func.language, Some(FunctionLanguage::PlPgSql));
504 }
505
506 #[rstest]
507 fn test_function_def_behavior_immutable() {
508 let func = FunctionDef::new("my_func").behavior(FunctionBehavior::Immutable);
509 assert_eq!(func.behavior, Some(FunctionBehavior::Immutable));
510 }
511
512 #[rstest]
513 fn test_function_def_behavior_stable() {
514 let func = FunctionDef::new("my_func").behavior(FunctionBehavior::Stable);
515 assert_eq!(func.behavior, Some(FunctionBehavior::Stable));
516 }
517
518 #[rstest]
519 fn test_function_def_behavior_volatile() {
520 let func = FunctionDef::new("my_func").behavior(FunctionBehavior::Volatile);
521 assert_eq!(func.behavior, Some(FunctionBehavior::Volatile));
522 }
523
524 #[rstest]
525 fn test_function_def_security_definer() {
526 let func = FunctionDef::new("my_func").security(FunctionSecurity::Definer);
527 assert_eq!(func.security, Some(FunctionSecurity::Definer));
528 }
529
530 #[rstest]
531 fn test_function_def_security_invoker() {
532 let func = FunctionDef::new("my_func").security(FunctionSecurity::Invoker);
533 assert_eq!(func.security, Some(FunctionSecurity::Invoker));
534 }
535
536 #[rstest]
537 fn test_function_def_body() {
538 let func = FunctionDef::new("my_func").body("SELECT 1");
539 assert_eq!(func.body.as_ref().unwrap(), "SELECT 1");
540 }
541
542 #[rstest]
543 fn test_function_def_all_options() {
544 let func = FunctionDef::new("my_func")
545 .or_replace(true)
546 .add_parameter("a", "integer")
547 .add_parameter("b", "text")
548 .returns("integer")
549 .language(FunctionLanguage::PlPgSql)
550 .behavior(FunctionBehavior::Immutable)
551 .security(FunctionSecurity::Definer)
552 .body("BEGIN RETURN a + LENGTH(b); END;");
553
554 assert_eq!(func.name.to_string(), "my_func");
555 assert!(func.or_replace);
556 assert_eq!(func.parameters.len(), 2);
557 assert_eq!(func.returns.as_ref().unwrap(), "integer");
558 assert_eq!(func.language, Some(FunctionLanguage::PlPgSql));
559 assert_eq!(func.behavior, Some(FunctionBehavior::Immutable));
560 assert_eq!(func.security, Some(FunctionSecurity::Definer));
561 assert_eq!(
562 func.body.as_ref().unwrap(),
563 "BEGIN RETURN a + LENGTH(b); END;"
564 );
565 }
566
567 #[rstest]
569 fn test_function_parameter_basic() {
570 let param = FunctionParameter::new();
571 assert!(param.name.is_none());
572 assert!(param.param_type.is_none());
573 assert!(param.mode.is_none());
574 assert!(param.default_value.is_none());
575 }
576
577 #[rstest]
578 fn test_function_parameter_name() {
579 let param = FunctionParameter::new().name("my_param");
580 assert_eq!(param.name.as_ref().unwrap().to_string(), "my_param");
581 }
582
583 #[rstest]
584 fn test_function_parameter_type() {
585 let param = FunctionParameter::new().param_type("integer");
586 assert_eq!(param.param_type.as_ref().unwrap(), "integer");
587 }
588
589 #[rstest]
590 fn test_function_parameter_mode_in() {
591 let param = FunctionParameter::new().mode(ParameterMode::In);
592 assert_eq!(param.mode, Some(ParameterMode::In));
593 }
594
595 #[rstest]
596 fn test_function_parameter_mode_out() {
597 let param = FunctionParameter::new().mode(ParameterMode::Out);
598 assert_eq!(param.mode, Some(ParameterMode::Out));
599 }
600
601 #[rstest]
602 fn test_function_parameter_mode_inout() {
603 let param = FunctionParameter::new().mode(ParameterMode::InOut);
604 assert_eq!(param.mode, Some(ParameterMode::InOut));
605 }
606
607 #[rstest]
608 fn test_function_parameter_mode_variadic() {
609 let param = FunctionParameter::new().mode(ParameterMode::Variadic);
610 assert_eq!(param.mode, Some(ParameterMode::Variadic));
611 }
612
613 #[rstest]
614 fn test_function_parameter_default_value() {
615 let param = FunctionParameter::new().default_value("42");
616 assert_eq!(param.default_value.as_ref().unwrap(), "42");
617 }
618
619 #[rstest]
620 fn test_function_parameter_all_options() {
621 let param = FunctionParameter::new()
622 .name("my_param")
623 .param_type("integer")
624 .mode(ParameterMode::InOut)
625 .default_value("42");
626
627 assert_eq!(param.name.as_ref().unwrap().to_string(), "my_param");
628 assert_eq!(param.param_type.as_ref().unwrap(), "integer");
629 assert_eq!(param.mode, Some(ParameterMode::InOut));
630 assert_eq!(param.default_value.as_ref().unwrap(), "42");
631 }
632
633 #[rstest]
634 fn test_function_def_add_parameter_spec() {
635 let param = FunctionParameter::new()
636 .name("my_param")
637 .param_type("integer")
638 .mode(ParameterMode::Out);
639
640 let func = FunctionDef::new("my_func").add_parameter_spec(param);
641
642 assert_eq!(func.parameters.len(), 1);
643 assert_eq!(
644 func.parameters[0].name.as_ref().unwrap().to_string(),
645 "my_param"
646 );
647 assert_eq!(func.parameters[0].param_type.as_ref().unwrap(), "integer");
648 assert_eq!(func.parameters[0].mode, Some(ParameterMode::Out));
649 }
650
651 #[rstest]
653 fn test_function_language_custom() {
654 let lang = FunctionLanguage::Custom("plpython3u".to_string());
655 assert_eq!(lang, FunctionLanguage::Custom("plpython3u".to_string()));
656 }
657}