Skip to main content

smelt_types/
functions.rs

1/// Categories of SQL functions
2#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3pub enum FunctionCategory {
4    Aggregate,
5    WindowRanking,
6    WindowDistribution,
7    WindowNavigation,
8    NullHandling,
9    DateTime,
10    String,
11    Math,
12    Trigonometric,
13    Comparison,
14    Json,
15    Boolean,
16    Array,
17    TypeConversion,
18    Constant,
19}
20
21/// Known SQL function names used across smelt crates.
22///
23/// Every function that appears in type inference, optimizer analysis,
24/// diagnostics, or test generators should have a variant here.
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26pub enum SqlFunction {
27    // Aggregate functions
28    Count,
29    Sum,
30    Avg,
31    Min,
32    Max,
33    Stddev,
34    Variance,
35    StddevPop,
36    StddevSamp,
37    VarPop,
38    VarSamp,
39    ArrayAgg,
40    StringAgg,
41    GroupConcat,
42    Listagg,
43    Median,
44    Mode,
45    PercentileCont,
46    PercentileDisc,
47    ApproxCountDistinct,
48    AnyValue,
49    First,
50    Last,
51    BoolAnd,
52    BoolOr,
53    BitAnd,
54    BitOr,
55    BitXor,
56    Corr,
57    CovarPop,
58    CovarSamp,
59    RegrSlope,
60    Every,
61
62    // Window ranking functions
63    RowNumber,
64    Rank,
65    DenseRank,
66    Ntile,
67
68    // Window distribution functions
69    CumeDist,
70    PercentRank,
71
72    // Window navigation functions
73    Lag,
74    Lead,
75    FirstValue,
76    LastValue,
77    NthValue,
78
79    // Null handling
80    Coalesce,
81    Nullif,
82    Ifnull,
83
84    // Date/time functions
85    Now,
86    CurrentTimestamp,
87    CurrentDate,
88    Date,
89    DateTrunc,
90    Extract,
91    DatePart,
92    Year,
93    Month,
94    Day,
95    DayOfWeek,
96    Quarter,
97    MakeDate,
98    MakeTime,
99    MakeTimestamp,
100    MakeTimestamptz,
101    Age,
102
103    // String functions
104    Concat,
105    Upper,
106    Lower,
107    Trim,
108    Ltrim,
109    Rtrim,
110    Substring,
111    Substr,
112    Length,
113    CharLength,
114    CharacterLength,
115    ToChar,
116    Replace,
117    Translate,
118    Reverse,
119    Repeat,
120    Lpad,
121    Rpad,
122    Initcap,
123    QuoteIdent,
124    QuoteLiteral,
125    Left,
126    Right,
127    Position,
128    Strpos,
129    SplitPart,
130
131    // Math functions
132    Abs,
133    Sign,
134    Round,
135    Trunc,
136    Truncate,
137    Ceil,
138    Ceiling,
139    Floor,
140    Power,
141    Pow,
142    Sqrt,
143    Exp,
144    Ln,
145    Log,
146    Log10,
147    Log2,
148    Mod,
149
150    // Trigonometric functions
151    Sin,
152    Cos,
153    Tan,
154    Asin,
155    Acos,
156    Atan,
157    Atan2,
158    Sinh,
159    Cosh,
160    Tanh,
161
162    // Constants / zero-arg functions
163    Pi,
164    Random,
165
166    // Comparison functions
167    Greatest,
168    Least,
169
170    // JSON functions (canonical names — accept dialect aliases via from_name)
171    /// json_object / json_build_object — construct JSON object from key-value pairs
172    JsonObject,
173    /// json_array / json_build_array — construct JSON array from values
174    JsonArray,
175    /// to_json / to_jsonb / row_to_json — convert value to JSON
176    ToJson,
177    /// json_extract / json_extract_path — extract JSON subtree (returns JSON)
178    JsonExtract,
179    /// json_extract_string / json_extract_text / json_extract_path_text / get_json_object — extract as text
180    JsonExtractText,
181    /// json_array_length — number of elements in JSON array
182    JsonArrayLength,
183    /// json_object_keys / json_keys — keys of JSON object
184    JsonObjectKeys,
185    /// json_contains — JSON containment check
186    JsonContains,
187    // Boolean aggregate (also listed under aggregate)
188    // (BoolAnd, BoolOr, Every already above)
189}
190
191/// All variants in definition order. Used by `SqlFunction::all()`.
192const ALL_FUNCTIONS: &[SqlFunction] = &[
193    SqlFunction::Count,
194    SqlFunction::Sum,
195    SqlFunction::Avg,
196    SqlFunction::Min,
197    SqlFunction::Max,
198    SqlFunction::Stddev,
199    SqlFunction::Variance,
200    SqlFunction::StddevPop,
201    SqlFunction::StddevSamp,
202    SqlFunction::VarPop,
203    SqlFunction::VarSamp,
204    SqlFunction::ArrayAgg,
205    SqlFunction::StringAgg,
206    SqlFunction::GroupConcat,
207    SqlFunction::Listagg,
208    SqlFunction::Median,
209    SqlFunction::Mode,
210    SqlFunction::PercentileCont,
211    SqlFunction::PercentileDisc,
212    SqlFunction::ApproxCountDistinct,
213    SqlFunction::AnyValue,
214    SqlFunction::First,
215    SqlFunction::Last,
216    SqlFunction::BoolAnd,
217    SqlFunction::BoolOr,
218    SqlFunction::BitAnd,
219    SqlFunction::BitOr,
220    SqlFunction::BitXor,
221    SqlFunction::Corr,
222    SqlFunction::CovarPop,
223    SqlFunction::CovarSamp,
224    SqlFunction::RegrSlope,
225    SqlFunction::Every,
226    SqlFunction::RowNumber,
227    SqlFunction::Rank,
228    SqlFunction::DenseRank,
229    SqlFunction::Ntile,
230    SqlFunction::CumeDist,
231    SqlFunction::PercentRank,
232    SqlFunction::Lag,
233    SqlFunction::Lead,
234    SqlFunction::FirstValue,
235    SqlFunction::LastValue,
236    SqlFunction::NthValue,
237    SqlFunction::Coalesce,
238    SqlFunction::Nullif,
239    SqlFunction::Ifnull,
240    SqlFunction::Now,
241    SqlFunction::CurrentTimestamp,
242    SqlFunction::CurrentDate,
243    SqlFunction::Date,
244    SqlFunction::DateTrunc,
245    SqlFunction::Extract,
246    SqlFunction::DatePart,
247    SqlFunction::Year,
248    SqlFunction::Month,
249    SqlFunction::Day,
250    SqlFunction::DayOfWeek,
251    SqlFunction::Quarter,
252    SqlFunction::MakeDate,
253    SqlFunction::MakeTime,
254    SqlFunction::MakeTimestamp,
255    SqlFunction::MakeTimestamptz,
256    SqlFunction::Age,
257    SqlFunction::Concat,
258    SqlFunction::Upper,
259    SqlFunction::Lower,
260    SqlFunction::Trim,
261    SqlFunction::Ltrim,
262    SqlFunction::Rtrim,
263    SqlFunction::Substring,
264    SqlFunction::Substr,
265    SqlFunction::Length,
266    SqlFunction::CharLength,
267    SqlFunction::CharacterLength,
268    SqlFunction::ToChar,
269    SqlFunction::Replace,
270    SqlFunction::Translate,
271    SqlFunction::Reverse,
272    SqlFunction::Repeat,
273    SqlFunction::Lpad,
274    SqlFunction::Rpad,
275    SqlFunction::Initcap,
276    SqlFunction::QuoteIdent,
277    SqlFunction::QuoteLiteral,
278    SqlFunction::Left,
279    SqlFunction::Right,
280    SqlFunction::Position,
281    SqlFunction::Strpos,
282    SqlFunction::SplitPart,
283    SqlFunction::Abs,
284    SqlFunction::Sign,
285    SqlFunction::Round,
286    SqlFunction::Trunc,
287    SqlFunction::Truncate,
288    SqlFunction::Ceil,
289    SqlFunction::Ceiling,
290    SqlFunction::Floor,
291    SqlFunction::Power,
292    SqlFunction::Pow,
293    SqlFunction::Sqrt,
294    SqlFunction::Exp,
295    SqlFunction::Ln,
296    SqlFunction::Log,
297    SqlFunction::Log10,
298    SqlFunction::Log2,
299    SqlFunction::Mod,
300    SqlFunction::Sin,
301    SqlFunction::Cos,
302    SqlFunction::Tan,
303    SqlFunction::Asin,
304    SqlFunction::Acos,
305    SqlFunction::Atan,
306    SqlFunction::Atan2,
307    SqlFunction::Sinh,
308    SqlFunction::Cosh,
309    SqlFunction::Tanh,
310    SqlFunction::Pi,
311    SqlFunction::Random,
312    SqlFunction::Greatest,
313    SqlFunction::Least,
314    SqlFunction::JsonObject,
315    SqlFunction::JsonArray,
316    SqlFunction::ToJson,
317    SqlFunction::JsonExtract,
318    SqlFunction::JsonExtractText,
319    SqlFunction::JsonArrayLength,
320    SqlFunction::JsonObjectKeys,
321    SqlFunction::JsonContains,
322];
323
324impl SqlFunction {
325    /// Look up a function by name (case-insensitive).
326    ///
327    /// Accepts both canonical smelt names and dialect-specific aliases
328    /// (e.g., `JSON_BUILD_OBJECT` → `JsonObject`, `GET_JSON_OBJECT` → `JsonExtractText`).
329    pub fn from_name(name: &str) -> Option<Self> {
330        let upper = name.to_uppercase();
331
332        // Check dialect aliases first
333        if let Some(canonical) = Self::resolve_alias(&upper) {
334            return Some(canonical);
335        }
336
337        // Linear scan for canonical names; fine for ~100 variants.
338        ALL_FUNCTIONS.iter().find(|f| f.name() == upper).copied()
339    }
340
341    /// Resolve dialect-specific function name aliases to canonical smelt functions.
342    fn resolve_alias(upper_name: &str) -> Option<Self> {
343        match upper_name {
344            // JSON object construction
345            "JSON_BUILD_OBJECT" => Some(Self::JsonObject),
346            // JSON array construction
347            "JSON_BUILD_ARRAY" => Some(Self::JsonArray),
348            // JSON conversion aliases
349            "TO_JSONB" | "ROW_TO_JSON" => Some(Self::ToJson),
350            // JSON extraction aliases
351            "JSON_EXTRACT_PATH" => Some(Self::JsonExtract),
352            // JSON text extraction aliases
353            "JSON_EXTRACT_STRING" | "JSON_EXTRACT_PATH_TEXT" | "GET_JSON_OBJECT" | "JSON_VALUE" => {
354                Some(Self::JsonExtractText)
355            }
356            // JSON keys alias (DuckDB)
357            "JSON_KEYS" => Some(Self::JsonObjectKeys),
358            // Null handling aliases
359            "NVL" => Some(Self::Ifnull),
360            _ => None,
361        }
362    }
363
364    /// Canonical uppercase SQL name.
365    pub fn name(&self) -> &'static str {
366        match self {
367            Self::Count => "COUNT",
368            Self::Sum => "SUM",
369            Self::Avg => "AVG",
370            Self::Min => "MIN",
371            Self::Max => "MAX",
372            Self::Stddev => "STDDEV",
373            Self::Variance => "VARIANCE",
374            Self::StddevPop => "STDDEV_POP",
375            Self::StddevSamp => "STDDEV_SAMP",
376            Self::VarPop => "VAR_POP",
377            Self::VarSamp => "VAR_SAMP",
378            Self::ArrayAgg => "ARRAY_AGG",
379            Self::StringAgg => "STRING_AGG",
380            Self::GroupConcat => "GROUP_CONCAT",
381            Self::Listagg => "LISTAGG",
382            Self::Median => "MEDIAN",
383            Self::Mode => "MODE",
384            Self::PercentileCont => "PERCENTILE_CONT",
385            Self::PercentileDisc => "PERCENTILE_DISC",
386            Self::ApproxCountDistinct => "APPROX_COUNT_DISTINCT",
387            Self::AnyValue => "ANY_VALUE",
388            Self::First => "FIRST",
389            Self::Last => "LAST",
390            Self::BoolAnd => "BOOL_AND",
391            Self::BoolOr => "BOOL_OR",
392            Self::BitAnd => "BIT_AND",
393            Self::BitOr => "BIT_OR",
394            Self::BitXor => "BIT_XOR",
395            Self::Corr => "CORR",
396            Self::CovarPop => "COVAR_POP",
397            Self::CovarSamp => "COVAR_SAMP",
398            Self::RegrSlope => "REGR_SLOPE",
399            Self::Every => "EVERY",
400            Self::RowNumber => "ROW_NUMBER",
401            Self::Rank => "RANK",
402            Self::DenseRank => "DENSE_RANK",
403            Self::Ntile => "NTILE",
404            Self::CumeDist => "CUME_DIST",
405            Self::PercentRank => "PERCENT_RANK",
406            Self::Lag => "LAG",
407            Self::Lead => "LEAD",
408            Self::FirstValue => "FIRST_VALUE",
409            Self::LastValue => "LAST_VALUE",
410            Self::NthValue => "NTH_VALUE",
411            Self::Coalesce => "COALESCE",
412            Self::Nullif => "NULLIF",
413            Self::Ifnull => "IFNULL",
414            Self::Now => "NOW",
415            Self::CurrentTimestamp => "CURRENT_TIMESTAMP",
416            Self::CurrentDate => "CURRENT_DATE",
417            Self::Date => "DATE",
418            Self::DateTrunc => "DATE_TRUNC",
419            Self::Extract => "EXTRACT",
420            Self::DatePart => "DATE_PART",
421            Self::Year => "YEAR",
422            Self::Month => "MONTH",
423            Self::Day => "DAY",
424            Self::DayOfWeek => "DAYOFWEEK",
425            Self::Quarter => "QUARTER",
426            Self::MakeDate => "MAKE_DATE",
427            Self::MakeTime => "MAKE_TIME",
428            Self::MakeTimestamp => "MAKE_TIMESTAMP",
429            Self::MakeTimestamptz => "MAKE_TIMESTAMPTZ",
430            Self::Age => "AGE",
431            Self::Concat => "CONCAT",
432            Self::Upper => "UPPER",
433            Self::Lower => "LOWER",
434            Self::Trim => "TRIM",
435            Self::Ltrim => "LTRIM",
436            Self::Rtrim => "RTRIM",
437            Self::Substring => "SUBSTRING",
438            Self::Substr => "SUBSTR",
439            Self::Length => "LENGTH",
440            Self::CharLength => "CHAR_LENGTH",
441            Self::CharacterLength => "CHARACTER_LENGTH",
442            Self::ToChar => "TO_CHAR",
443            Self::Replace => "REPLACE",
444            Self::Translate => "TRANSLATE",
445            Self::Reverse => "REVERSE",
446            Self::Repeat => "REPEAT",
447            Self::Lpad => "LPAD",
448            Self::Rpad => "RPAD",
449            Self::Initcap => "INITCAP",
450            Self::QuoteIdent => "QUOTE_IDENT",
451            Self::QuoteLiteral => "QUOTE_LITERAL",
452            Self::Left => "LEFT",
453            Self::Right => "RIGHT",
454            Self::Position => "POSITION",
455            Self::Strpos => "STRPOS",
456            Self::SplitPart => "SPLIT_PART",
457            Self::Abs => "ABS",
458            Self::Sign => "SIGN",
459            Self::Round => "ROUND",
460            Self::Trunc => "TRUNC",
461            Self::Truncate => "TRUNCATE",
462            Self::Ceil => "CEIL",
463            Self::Ceiling => "CEILING",
464            Self::Floor => "FLOOR",
465            Self::Power => "POWER",
466            Self::Pow => "POW",
467            Self::Sqrt => "SQRT",
468            Self::Exp => "EXP",
469            Self::Ln => "LN",
470            Self::Log => "LOG",
471            Self::Log10 => "LOG10",
472            Self::Log2 => "LOG2",
473            Self::Mod => "MOD",
474            Self::Sin => "SIN",
475            Self::Cos => "COS",
476            Self::Tan => "TAN",
477            Self::Asin => "ASIN",
478            Self::Acos => "ACOS",
479            Self::Atan => "ATAN",
480            Self::Atan2 => "ATAN2",
481            Self::Sinh => "SINH",
482            Self::Cosh => "COSH",
483            Self::Tanh => "TANH",
484            Self::Pi => "PI",
485            Self::Random => "RANDOM",
486            Self::Greatest => "GREATEST",
487            Self::Least => "LEAST",
488            Self::JsonObject => "JSON_OBJECT",
489            Self::JsonArray => "JSON_ARRAY",
490            Self::ToJson => "TO_JSON",
491            Self::JsonExtract => "JSON_EXTRACT",
492            Self::JsonExtractText => "JSON_EXTRACT_TEXT",
493            Self::JsonArrayLength => "JSON_ARRAY_LENGTH",
494            Self::JsonObjectKeys => "JSON_OBJECT_KEYS",
495            Self::JsonContains => "JSON_CONTAINS",
496        }
497    }
498
499    /// Function category.
500    pub fn category(&self) -> FunctionCategory {
501        match self {
502            Self::Count
503            | Self::Sum
504            | Self::Avg
505            | Self::Min
506            | Self::Max
507            | Self::Stddev
508            | Self::Variance
509            | Self::StddevPop
510            | Self::StddevSamp
511            | Self::VarPop
512            | Self::VarSamp
513            | Self::ArrayAgg
514            | Self::StringAgg
515            | Self::GroupConcat
516            | Self::Listagg
517            | Self::Median
518            | Self::Mode
519            | Self::PercentileCont
520            | Self::PercentileDisc
521            | Self::ApproxCountDistinct
522            | Self::AnyValue
523            | Self::First
524            | Self::Last
525            | Self::BoolAnd
526            | Self::BoolOr
527            | Self::BitAnd
528            | Self::BitOr
529            | Self::BitXor
530            | Self::Corr
531            | Self::CovarPop
532            | Self::CovarSamp
533            | Self::RegrSlope
534            | Self::Every => FunctionCategory::Aggregate,
535
536            Self::RowNumber | Self::Rank | Self::DenseRank | Self::Ntile => {
537                FunctionCategory::WindowRanking
538            }
539
540            Self::CumeDist | Self::PercentRank => FunctionCategory::WindowDistribution,
541
542            Self::Lag | Self::Lead | Self::FirstValue | Self::LastValue | Self::NthValue => {
543                FunctionCategory::WindowNavigation
544            }
545
546            Self::Coalesce | Self::Nullif | Self::Ifnull => FunctionCategory::NullHandling,
547
548            Self::Now
549            | Self::CurrentTimestamp
550            | Self::CurrentDate
551            | Self::Date
552            | Self::DateTrunc
553            | Self::Extract
554            | Self::DatePart
555            | Self::Year
556            | Self::Month
557            | Self::Day
558            | Self::DayOfWeek
559            | Self::Quarter
560            | Self::MakeDate
561            | Self::MakeTime
562            | Self::MakeTimestamp
563            | Self::MakeTimestamptz
564            | Self::Age => FunctionCategory::DateTime,
565
566            Self::Concat
567            | Self::Upper
568            | Self::Lower
569            | Self::Trim
570            | Self::Ltrim
571            | Self::Rtrim
572            | Self::Substring
573            | Self::Substr
574            | Self::Length
575            | Self::CharLength
576            | Self::CharacterLength
577            | Self::ToChar
578            | Self::Replace
579            | Self::Translate
580            | Self::Reverse
581            | Self::Repeat
582            | Self::Lpad
583            | Self::Rpad
584            | Self::Initcap
585            | Self::QuoteIdent
586            | Self::QuoteLiteral
587            | Self::Left
588            | Self::Right
589            | Self::Position
590            | Self::Strpos
591            | Self::SplitPart => FunctionCategory::String,
592
593            Self::Abs
594            | Self::Sign
595            | Self::Round
596            | Self::Trunc
597            | Self::Truncate
598            | Self::Ceil
599            | Self::Ceiling
600            | Self::Floor
601            | Self::Power
602            | Self::Pow
603            | Self::Sqrt
604            | Self::Exp
605            | Self::Ln
606            | Self::Log
607            | Self::Log10
608            | Self::Log2
609            | Self::Mod => FunctionCategory::Math,
610
611            Self::Sin
612            | Self::Cos
613            | Self::Tan
614            | Self::Asin
615            | Self::Acos
616            | Self::Atan
617            | Self::Atan2
618            | Self::Sinh
619            | Self::Cosh
620            | Self::Tanh => FunctionCategory::Trigonometric,
621
622            Self::Pi | Self::Random => FunctionCategory::Constant,
623
624            Self::Greatest | Self::Least => FunctionCategory::Comparison,
625
626            Self::JsonObject
627            | Self::JsonArray
628            | Self::ToJson
629            | Self::JsonExtract
630            | Self::JsonExtractText
631            | Self::JsonArrayLength
632            | Self::JsonObjectKeys
633            | Self::JsonContains => FunctionCategory::Json,
634        }
635    }
636
637    /// Whether this function is an aggregate function.
638    pub fn is_aggregate(&self) -> bool {
639        self.category() == FunctionCategory::Aggregate
640    }
641
642    /// Whether this function is a window function (ranking, distribution, or navigation).
643    pub fn is_window(&self) -> bool {
644        matches!(
645            self.category(),
646            FunctionCategory::WindowRanking
647                | FunctionCategory::WindowDistribution
648                | FunctionCategory::WindowNavigation
649        )
650    }
651
652    /// Iterator over all known SQL functions.
653    pub fn all() -> impl Iterator<Item = SqlFunction> {
654        ALL_FUNCTIONS.iter().copied()
655    }
656}
657
658impl std::fmt::Display for SqlFunction {
659    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
660        f.write_str(self.name())
661    }
662}
663
664#[cfg(test)]
665mod tests {
666    use super::*;
667
668    #[test]
669    fn round_trip_all_variants() {
670        for f in SqlFunction::all() {
671            assert_eq!(
672                SqlFunction::from_name(f.name()),
673                Some(f),
674                "round-trip failed for {:?} (name={})",
675                f,
676                f.name()
677            );
678        }
679    }
680
681    #[test]
682    fn from_name_case_insensitive() {
683        assert_eq!(SqlFunction::from_name("count"), Some(SqlFunction::Count));
684        assert_eq!(SqlFunction::from_name("Count"), Some(SqlFunction::Count));
685        assert_eq!(SqlFunction::from_name("COUNT"), Some(SqlFunction::Count));
686    }
687
688    #[test]
689    fn from_name_unknown_returns_none() {
690        assert_eq!(SqlFunction::from_name("not_a_function"), None);
691    }
692
693    #[test]
694    fn aggregate_classification() {
695        assert!(SqlFunction::Count.is_aggregate());
696        assert!(SqlFunction::Sum.is_aggregate());
697        assert!(SqlFunction::Stddev.is_aggregate());
698        assert!(!SqlFunction::RowNumber.is_aggregate());
699        assert!(!SqlFunction::Upper.is_aggregate());
700    }
701
702    #[test]
703    fn window_classification() {
704        assert!(SqlFunction::RowNumber.is_window());
705        assert!(SqlFunction::Lag.is_window());
706        assert!(SqlFunction::CumeDist.is_window());
707        assert!(!SqlFunction::Count.is_window());
708    }
709
710    #[test]
711    fn all_variants_have_category() {
712        // Ensures the category match is exhaustive at compile time
713        // (it already is, but this test exercises the runtime path)
714        for f in SqlFunction::all() {
715            let _ = f.category();
716        }
717    }
718
719    #[test]
720    fn json_dialect_aliases() {
721        // PostgreSQL names
722        assert_eq!(
723            SqlFunction::from_name("json_build_object"),
724            Some(SqlFunction::JsonObject)
725        );
726        assert_eq!(
727            SqlFunction::from_name("json_build_array"),
728            Some(SqlFunction::JsonArray)
729        );
730        assert_eq!(
731            SqlFunction::from_name("to_jsonb"),
732            Some(SqlFunction::ToJson)
733        );
734        assert_eq!(
735            SqlFunction::from_name("row_to_json"),
736            Some(SqlFunction::ToJson)
737        );
738        assert_eq!(
739            SqlFunction::from_name("json_extract_path_text"),
740            Some(SqlFunction::JsonExtractText)
741        );
742
743        // DuckDB names
744        assert_eq!(
745            SqlFunction::from_name("json_extract_string"),
746            Some(SqlFunction::JsonExtractText)
747        );
748        assert_eq!(
749            SqlFunction::from_name("json_keys"),
750            Some(SqlFunction::JsonObjectKeys)
751        );
752
753        // Spark names
754        assert_eq!(
755            SqlFunction::from_name("get_json_object"),
756            Some(SqlFunction::JsonExtractText)
757        );
758
759        // Canonical names
760        assert_eq!(
761            SqlFunction::from_name("json_object"),
762            Some(SqlFunction::JsonObject)
763        );
764        assert_eq!(
765            SqlFunction::from_name("json_extract"),
766            Some(SqlFunction::JsonExtract)
767        );
768        assert_eq!(
769            SqlFunction::from_name("json_contains"),
770            Some(SqlFunction::JsonContains)
771        );
772    }
773}