## Coverage Report

#### Created: 2024-10-13 08:39

    /Users/andrewlamb/Software/datafusion/datafusion/expr/src/udf_docs.rs

    Line
    Count
    Source (jump to first uncovered line)
    1
    // Licensed to the Apache Software Foundation (ASF) under one
    2
    // or more contributor license agreements.  See the NOTICE file
    3
    // distributed with this work for additional information
    4
    // regarding copyright ownership.  The ASF licenses this file
    5
    // to you under the Apache License, Version 2.0 (the
    6
    // "License"); you may not use this file except in compliance
    7
    // with the License.  You may obtain a copy of the License at
    8
    //
    9
    //   http://www.apache.org/licenses/LICENSE-2.0
    10
    //
    11
    // Unless required by applicable law or agreed to in writing,
    12
    // software distributed under the License is distributed on an
    13
    // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    14
    // KIND, either express or implied.  See the License for the
    15
    // specific language governing permissions and limitations
    16
    // under the License.
    17
    18
    use datafusion_common::exec_err;
    19
    use datafusion_common::Result;
    20
    21
    /// Documentation for use by [`ScalarUDFImpl`](crate::ScalarUDFImpl),
    22
    /// [`AggregateUDFImpl`](crate::AggregateUDFImpl) and [`WindowUDFImpl`](crate::WindowUDFImpl) functions
    23
    /// that will be used to generate public documentation.
    24
    ///
    25
    /// The name of the udf will be pulled from the [`ScalarUDFImpl::name`](crate::ScalarUDFImpl::name),
    26
    /// [`AggregateUDFImpl::name`](crate::AggregateUDFImpl::name) or [`WindowUDFImpl::name`](crate::WindowUDFImpl::name)
    27
    /// function as appropriate.
    28
    ///
    29
    /// All strings in the documentation are required to be
    30
    /// in [markdown format](https://www.markdownguide.org/basic-syntax/).
    31
    ///
    32
    /// Currently, documentation only supports a single language
    33
    /// thus all text should be in English.
    34
    #[derive(Debug, Clone)]
    35
    pub struct Documentation {
    36
        /// the section in the documentation where the UDF will be documented
    37
        pub doc_section: DocSection,
    38
        /// the description for the UDF
    39
        pub description: String,
    40
        /// a brief example of the syntax. For example "ascii(str)"
    41
        pub syntax_example: String,
    42
        /// a sql example for the UDF, usually in the form of a sql prompt
    43
        /// query and output. It is strongly recommended to provide an
    44
        /// example for anything but the most basic UDF's
    45
        pub sql_example: Option<String>,
    46
        /// arguments for the UDF which will be displayed in array order.
    47
        /// Left member of a pair is the argument name, right is a
    48
        /// description for the argument
    49
        pub arguments: Option<Vec<(String, String)>>,
    50
        /// related functions if any. Values should match the related
    51
        /// udf's name exactly. Related udf's must be of the same
    52
        /// UDF type (scalar, aggregate or window) for proper linking to
    53
        /// occur
    54
        pub related_udfs: Option<Vec<String>>,
    55
    }
    56
    57
    impl Documentation {
    58
        /// Returns a new [`DocumentationBuilder`] with no options set.
    59
    0
        pub fn builder() -> DocumentationBuilder {
    60
    0
            DocumentationBuilder::new()
    61
    0
        }
    62
    }
    63
    64
    #[derive(Debug, Clone, PartialEq)]
    65
    pub struct DocSection {
    66
        /// true to include this doc section in the public
    67
        /// documentation, false otherwise
    68
        pub include: bool,
    69
        /// a display label for the doc section. For example: "Math Expressions"
    70
        pub label: &'static str,
    71
        /// an optional description for the doc section
    72
        pub description: Option<&'static str>,
    73
    }
    74
    75
    /// A builder to be used for building [`Documentation`]'s.
    76
    ///
    77
    /// Example:
    78
    ///
    79
    /// ```rust
    80
    /// # use datafusion_expr::Documentation;
    81
    /// # use datafusion_expr::scalar_doc_sections::DOC_SECTION_MATH;
    82
    /// # use datafusion_common::Result;
    83
    /// #
    84
    /// # fn main() -> Result<()> {
    85
    ///       let documentation = Documentation::builder()
    86
    ///           .with_doc_section(DOC_SECTION_MATH)
    87
    ///           .with_description("Add one to an int32")
    88
    ///           .with_syntax_example("add_one(2)")
    89
    ///           .with_argument("arg_1", "The int32 number to add one to")
    90
    ///           .build()?;
    91
    ///       Ok(())
    92
    /// # }
    93
    pub struct DocumentationBuilder {
    94
        pub doc_section: Option<DocSection>,
    95
        pub description: Option<String>,
    96
        pub syntax_example: Option<String>,
    97
        pub sql_example: Option<String>,
    98
        pub arguments: Option<Vec<(String, String)>>,
    99
        pub related_udfs: Option<Vec<String>>,
    100
    }
    101
    102
    impl DocumentationBuilder {
    103
    0
        pub fn new() -> Self {
    104
    0
            Self {
    105
    0
                doc_section: None,
    106
    0
                description: None,
    107
    0
                syntax_example: None,
    108
    0
                sql_example: None,
    109
    0
                arguments: None,
    110
    0
                related_udfs: None,
    111
    0
            }
    112
    0
        }
    113
    114
    0
        pub fn with_doc_section(mut self, doc_section: DocSection) -> Self {
    115
    0
            self.doc_section = Some(doc_section);
    116
    0
            self
    117
    0
        }
    118
    119
    0
        pub fn with_description(mut self, description: impl Into<String>) -> Self {
    120
    0
            self.description = Some(description.into());
    121
    0
            self
    122
    0
        }
    123
    124
    0
        pub fn with_syntax_example(mut self, syntax_example: impl Into<String>) -> Self {
    125
    0
            self.syntax_example = Some(syntax_example.into());
    126
    0
            self
    127
    0
        }
    128
    129
    0
        pub fn with_sql_example(mut self, sql_example: impl Into<String>) -> Self {
    130
    0
            self.sql_example = Some(sql_example.into());
    131
    0
            self
    132
    0
        }
    133
    134
        /// Adds documentation for a specific argument to the documentation.
    135
        ///
    136
        /// Arguments are displayed in the order they are added.
    137
    0
        pub fn with_argument(
    138
    0
            mut self,
    139
    0
            arg_name: impl Into<String>,
    140
    0
            arg_description: impl Into<String>,
    141
    0
        ) -> Self {
    142
    0
            let mut args = self.arguments.unwrap_or_default();
    143
    0
            args.push((arg_name.into(), arg_description.into()));
    144
    0
            self.arguments = Some(args);
    145
    0
            self
    146
    0
        }
    147
    148
        /// Add a standard "expression" argument to the documentation
    149
        ///
    150
        /// This is similar to  [`Self::with_argument`] except that  a standard
    151
        /// description is appended to the end: `"Can be a constant, column, or
    152
        /// function, and any combination of arithmetic operators."`
    153
        ///
    154
        /// The argument is rendered like
    155
        ///
    156
        /// ```text
    157
        /// <arg_name>:
    158
        ///   <expression_type> expression to operate on. Can be a constant, column, or function, and any combination of arithmetic operators.
    159
        /// ```
    160
    0
        pub fn with_standard_argument(
    161
    0
            self,
    162
    0
            arg_name: impl Into<String>,
    163
    0
            expression_type: impl AsRef<str>,
    164
    0
        ) -> Self {
    165
    0
            let expression_type = expression_type.as_ref();
    166
    0
            self.with_argument(arg_name, format!("{expression_type} expression to operate on. Can be a constant, column, or function, and any combination of operators."))
    167
    0
        }
    168
    169
    0
        pub fn with_related_udf(mut self, related_udf: impl Into<String>) -> Self {
    170
    0
            let mut related = self.related_udfs.unwrap_or_default();
    171
    0
            related.push(related_udf.into());
    172
    0
            self.related_udfs = Some(related);
    173
    0
            self
    174
    0
        }
    175
    176
    0
        pub fn build(self) -> Result<Documentation> {
    177
    0
            let Self {
    178
    0
                doc_section,
    179
    0
                description,
    180
    0
                syntax_example,
    181
    0
                sql_example,
    182
    0
                arguments,
    183
    0
                related_udfs,
    184
    0
            } = self;
    185
    0
    186
    0
            if doc_section.is_none() {
    187
    0
                return exec_err!("Documentation must have a doc section");
    188
    0
            }
    189
    0
            if description.is_none() {
    190
    0
                return exec_err!("Documentation must have a description");
    191
    0
            }
    192
    0
            if syntax_example.is_none() {
    193
    0
                return exec_err!("Documentation must have a syntax_example");
    194
    0
            }
    195
    0
    196
    0
            Ok(Documentation {
    197
    0
                doc_section: doc_section.unwrap(),
    198
    0
                description: description.unwrap(),
    199
    0
                syntax_example: syntax_example.unwrap(),
    200
    0
                sql_example,
    201
    0
                arguments,
    202
    0
                related_udfs,
    203
    0
            })
    204
    0
        }
    205
    }
    206
    207
    impl Default for DocumentationBuilder {
    208
    0
        fn default() -> Self {
    209
    0
            Self::new()
    210
    0
        }
    211
    }