1use crate::types::{DynIden, IntoIden};
35
36#[derive(Debug, Clone)]
53#[allow(dead_code)]
54pub struct FunctionDef {
55 pub(crate) name: DynIden,
56 pub(crate) or_replace: bool,
57 pub(crate) parameters: Vec<FunctionParameter>,
58 pub(crate) returns: Option<String>,
59 pub(crate) language: Option<FunctionLanguage>,
60 pub(crate) behavior: Option<FunctionBehavior>,
61 pub(crate) security: Option<FunctionSecurity>,
62 pub(crate) body: Option<String>,
63}
64
65#[derive(Debug, Clone)]
86#[allow(dead_code)]
87pub struct FunctionParameter {
88 pub(crate) name: Option<DynIden>,
89 pub(crate) param_type: Option<String>,
90 pub(crate) mode: Option<ParameterMode>,
91 pub(crate) default_value: Option<String>,
92}
93
94#[derive(Debug, Clone, PartialEq, Eq)]
98#[allow(dead_code)]
99pub enum ParameterMode {
100 In,
102 Out,
104 InOut,
106 Variadic,
108}
109
110#[derive(Debug, Clone, PartialEq, Eq)]
125#[allow(dead_code)]
126pub enum FunctionLanguage {
127 Sql,
129 PlPgSql,
131 C,
133 Custom(String),
139}
140
141#[derive(Debug, Clone, PartialEq, Eq)]
155#[allow(dead_code)]
156pub enum FunctionBehavior {
157 Immutable,
159 Stable,
161 Volatile,
163}
164
165#[derive(Debug, Clone, PartialEq, Eq)]
178#[allow(dead_code)]
179pub enum FunctionSecurity {
180 Definer,
182 Invoker,
184}
185
186impl FunctionDef {
187 pub fn new<N: IntoIden>(name: N) -> Self {
197 Self {
198 name: name.into_iden(),
199 or_replace: false,
200 parameters: Vec::new(),
201 returns: None,
202 language: None,
203 behavior: None,
204 security: None,
205 body: None,
206 }
207 }
208
209 pub fn or_replace(mut self, or_replace: bool) -> Self {
220 self.or_replace = or_replace;
221 self
222 }
223
224 pub fn add_parameter<N: IntoIden, T: Into<String>>(mut self, name: N, param_type: T) -> Self {
236 self.parameters.push(FunctionParameter {
237 name: Some(name.into_iden()),
238 param_type: Some(param_type.into()),
239 mode: None,
240 default_value: None,
241 });
242 self
243 }
244
245 pub fn add_parameter_spec(mut self, param: FunctionParameter) -> Self {
261 self.parameters.push(param);
262 self
263 }
264
265 pub fn returns<T: Into<String>>(mut self, returns: T) -> Self {
276 self.returns = Some(returns.into());
277 self
278 }
279
280 pub fn language(mut self, language: FunctionLanguage) -> Self {
291 self.language = Some(language);
292 self
293 }
294
295 pub fn behavior(mut self, behavior: FunctionBehavior) -> Self {
306 self.behavior = Some(behavior);
307 self
308 }
309
310 pub fn security(mut self, security: FunctionSecurity) -> Self {
321 self.security = Some(security);
322 self
323 }
324
325 pub fn body<B: Into<String>>(mut self, body: B) -> Self {
336 self.body = Some(body.into());
337 self
338 }
339}
340
341impl FunctionParameter {
342 pub fn new() -> Self {
352 Self {
353 name: None,
354 param_type: None,
355 mode: None,
356 default_value: None,
357 }
358 }
359
360 pub fn name<N: IntoIden>(mut self, name: N) -> Self {
371 self.name = Some(name.into_iden());
372 self
373 }
374
375 pub fn param_type<T: Into<String>>(mut self, param_type: T) -> Self {
386 self.param_type = Some(param_type.into());
387 self
388 }
389
390 pub fn mode(mut self, mode: ParameterMode) -> Self {
401 self.mode = Some(mode);
402 self
403 }
404
405 pub fn default_value<V: Into<String>>(mut self, value: V) -> Self {
416 self.default_value = Some(value.into());
417 self
418 }
419}
420
421impl Default for FunctionParameter {
422 fn default() -> Self {
423 Self::new()
424 }
425}
426
427#[cfg(test)]
428mod tests {
429 use super::*;
430 use rstest::*;
431
432 #[rstest]
434 fn test_function_def_basic() {
435 let func = FunctionDef::new("my_func");
436 assert_eq!(func.name.to_string(), "my_func");
437 assert!(!func.or_replace);
438 assert!(func.parameters.is_empty());
439 assert!(func.returns.is_none());
440 assert!(func.language.is_none());
441 assert!(func.behavior.is_none());
442 assert!(func.security.is_none());
443 assert!(func.body.is_none());
444 }
445
446 #[rstest]
447 fn test_function_def_or_replace() {
448 let func = FunctionDef::new("my_func").or_replace(true);
449 assert_eq!(func.name.to_string(), "my_func");
450 assert!(func.or_replace);
451 }
452
453 #[rstest]
454 fn test_function_def_add_parameter() {
455 let func = FunctionDef::new("my_func").add_parameter("param1", "integer");
456 assert_eq!(func.parameters.len(), 1);
457 assert_eq!(
458 func.parameters[0].name.as_ref().unwrap().to_string(),
459 "param1"
460 );
461 assert_eq!(func.parameters[0].param_type.as_ref().unwrap(), "integer");
462 }
463
464 #[rstest]
465 fn test_function_def_multiple_parameters() {
466 let func = FunctionDef::new("my_func")
467 .add_parameter("param1", "integer")
468 .add_parameter("param2", "text");
469 assert_eq!(func.parameters.len(), 2);
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 assert_eq!(
476 func.parameters[1].name.as_ref().unwrap().to_string(),
477 "param2"
478 );
479 assert_eq!(func.parameters[1].param_type.as_ref().unwrap(), "text");
480 }
481
482 #[rstest]
483 fn test_function_def_returns() {
484 let func = FunctionDef::new("my_func").returns("integer");
485 assert_eq!(func.returns.as_ref().unwrap(), "integer");
486 }
487
488 #[rstest]
489 fn test_function_def_language_sql() {
490 let func = FunctionDef::new("my_func").language(FunctionLanguage::Sql);
491 assert_eq!(func.language, Some(FunctionLanguage::Sql));
492 }
493
494 #[rstest]
495 fn test_function_def_language_plpgsql() {
496 let func = FunctionDef::new("my_func").language(FunctionLanguage::PlPgSql);
497 assert_eq!(func.language, Some(FunctionLanguage::PlPgSql));
498 }
499
500 #[rstest]
501 fn test_function_def_behavior_immutable() {
502 let func = FunctionDef::new("my_func").behavior(FunctionBehavior::Immutable);
503 assert_eq!(func.behavior, Some(FunctionBehavior::Immutable));
504 }
505
506 #[rstest]
507 fn test_function_def_behavior_stable() {
508 let func = FunctionDef::new("my_func").behavior(FunctionBehavior::Stable);
509 assert_eq!(func.behavior, Some(FunctionBehavior::Stable));
510 }
511
512 #[rstest]
513 fn test_function_def_behavior_volatile() {
514 let func = FunctionDef::new("my_func").behavior(FunctionBehavior::Volatile);
515 assert_eq!(func.behavior, Some(FunctionBehavior::Volatile));
516 }
517
518 #[rstest]
519 fn test_function_def_security_definer() {
520 let func = FunctionDef::new("my_func").security(FunctionSecurity::Definer);
521 assert_eq!(func.security, Some(FunctionSecurity::Definer));
522 }
523
524 #[rstest]
525 fn test_function_def_security_invoker() {
526 let func = FunctionDef::new("my_func").security(FunctionSecurity::Invoker);
527 assert_eq!(func.security, Some(FunctionSecurity::Invoker));
528 }
529
530 #[rstest]
531 fn test_function_def_body() {
532 let func = FunctionDef::new("my_func").body("SELECT 1");
533 assert_eq!(func.body.as_ref().unwrap(), "SELECT 1");
534 }
535
536 #[rstest]
537 fn test_function_def_all_options() {
538 let func = FunctionDef::new("my_func")
539 .or_replace(true)
540 .add_parameter("a", "integer")
541 .add_parameter("b", "text")
542 .returns("integer")
543 .language(FunctionLanguage::PlPgSql)
544 .behavior(FunctionBehavior::Immutable)
545 .security(FunctionSecurity::Definer)
546 .body("BEGIN RETURN a + LENGTH(b); END;");
547
548 assert_eq!(func.name.to_string(), "my_func");
549 assert!(func.or_replace);
550 assert_eq!(func.parameters.len(), 2);
551 assert_eq!(func.returns.as_ref().unwrap(), "integer");
552 assert_eq!(func.language, Some(FunctionLanguage::PlPgSql));
553 assert_eq!(func.behavior, Some(FunctionBehavior::Immutable));
554 assert_eq!(func.security, Some(FunctionSecurity::Definer));
555 assert_eq!(
556 func.body.as_ref().unwrap(),
557 "BEGIN RETURN a + LENGTH(b); END;"
558 );
559 }
560
561 #[rstest]
563 fn test_function_parameter_basic() {
564 let param = FunctionParameter::new();
565 assert!(param.name.is_none());
566 assert!(param.param_type.is_none());
567 assert!(param.mode.is_none());
568 assert!(param.default_value.is_none());
569 }
570
571 #[rstest]
572 fn test_function_parameter_name() {
573 let param = FunctionParameter::new().name("my_param");
574 assert_eq!(param.name.as_ref().unwrap().to_string(), "my_param");
575 }
576
577 #[rstest]
578 fn test_function_parameter_type() {
579 let param = FunctionParameter::new().param_type("integer");
580 assert_eq!(param.param_type.as_ref().unwrap(), "integer");
581 }
582
583 #[rstest]
584 fn test_function_parameter_mode_in() {
585 let param = FunctionParameter::new().mode(ParameterMode::In);
586 assert_eq!(param.mode, Some(ParameterMode::In));
587 }
588
589 #[rstest]
590 fn test_function_parameter_mode_out() {
591 let param = FunctionParameter::new().mode(ParameterMode::Out);
592 assert_eq!(param.mode, Some(ParameterMode::Out));
593 }
594
595 #[rstest]
596 fn test_function_parameter_mode_inout() {
597 let param = FunctionParameter::new().mode(ParameterMode::InOut);
598 assert_eq!(param.mode, Some(ParameterMode::InOut));
599 }
600
601 #[rstest]
602 fn test_function_parameter_mode_variadic() {
603 let param = FunctionParameter::new().mode(ParameterMode::Variadic);
604 assert_eq!(param.mode, Some(ParameterMode::Variadic));
605 }
606
607 #[rstest]
608 fn test_function_parameter_default_value() {
609 let param = FunctionParameter::new().default_value("42");
610 assert_eq!(param.default_value.as_ref().unwrap(), "42");
611 }
612
613 #[rstest]
614 fn test_function_parameter_all_options() {
615 let param = FunctionParameter::new()
616 .name("my_param")
617 .param_type("integer")
618 .mode(ParameterMode::InOut)
619 .default_value("42");
620
621 assert_eq!(param.name.as_ref().unwrap().to_string(), "my_param");
622 assert_eq!(param.param_type.as_ref().unwrap(), "integer");
623 assert_eq!(param.mode, Some(ParameterMode::InOut));
624 assert_eq!(param.default_value.as_ref().unwrap(), "42");
625 }
626
627 #[rstest]
628 fn test_function_def_add_parameter_spec() {
629 let param = FunctionParameter::new()
630 .name("my_param")
631 .param_type("integer")
632 .mode(ParameterMode::Out);
633
634 let func = FunctionDef::new("my_func").add_parameter_spec(param);
635
636 assert_eq!(func.parameters.len(), 1);
637 assert_eq!(
638 func.parameters[0].name.as_ref().unwrap().to_string(),
639 "my_param"
640 );
641 assert_eq!(func.parameters[0].param_type.as_ref().unwrap(), "integer");
642 assert_eq!(func.parameters[0].mode, Some(ParameterMode::Out));
643 }
644
645 #[rstest]
647 fn test_function_language_custom() {
648 let lang = FunctionLanguage::Custom("plpython3u".to_string());
649 assert_eq!(lang, FunctionLanguage::Custom("plpython3u".to_string()));
650 }
651}