Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
udwf.rs - source
[go: Go Back, main page]

datafusion_expr/
udwf.rs

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//! [`WindowUDF`]: User Defined Window Functions
19
20use arrow::compute::SortOptions;
21use std::cmp::Ordering;
22use std::hash::{DefaultHasher, Hash, Hasher};
23use std::{
24    any::Any,
25    fmt::{self, Debug, Display, Formatter},
26    sync::Arc,
27};
28
29use arrow::datatypes::{DataType, FieldRef};
30
31use crate::expr::WindowFunction;
32use crate::{
33    function::WindowFunctionSimplification, Expr, PartitionEvaluator, Signature,
34};
35use datafusion_common::{not_impl_err, Result};
36use datafusion_doc::Documentation;
37use datafusion_functions_window_common::expr::ExpressionArgs;
38use datafusion_functions_window_common::field::WindowUDFFieldArgs;
39use datafusion_functions_window_common::partition::PartitionEvaluatorArgs;
40use datafusion_physical_expr_common::physical_expr::PhysicalExpr;
41
42/// Logical representation of a user-defined window function (UDWF).
43///
44/// A Window Function is called via the SQL `OVER` clause:
45///
46/// ```sql
47/// SELECT first_value(col) OVER (PARTITION BY a, b ORDER BY c) FROM foo;
48/// ```
49///
50/// A UDWF is different from a user defined function (UDF) in that it is
51/// stateful across batches.
52///
53/// See the documentation on [`PartitionEvaluator`] for more details
54///
55/// 1. For simple use cases, use [`create_udwf`] (examples in
56///    [`simple_udwf.rs`]).
57///
58/// 2. For advanced use cases, use [`WindowUDFImpl`] which provides full API
59///    access (examples in [`advanced_udwf.rs`]).
60///
61/// # API Note
62/// This is a separate struct from `WindowUDFImpl` to maintain backwards
63/// compatibility with the older API.
64///
65/// [`PartitionEvaluator`]: crate::PartitionEvaluator
66/// [`create_udwf`]: crate::expr_fn::create_udwf
67/// [`simple_udwf.rs`]: https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/simple_udwf.rs
68/// [`advanced_udwf.rs`]: https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/advanced_udwf.rs
69#[derive(Debug, Clone, PartialOrd)]
70pub struct WindowUDF {
71    inner: Arc<dyn WindowUDFImpl>,
72}
73
74/// Defines how the WindowUDF is shown to users
75impl Display for WindowUDF {
76    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
77        write!(f, "{}", self.name())
78    }
79}
80
81impl PartialEq for WindowUDF {
82    fn eq(&self, other: &Self) -> bool {
83        self.inner.equals(other.inner.as_ref())
84    }
85}
86
87impl Eq for WindowUDF {}
88
89impl Hash for WindowUDF {
90    fn hash<H: Hasher>(&self, state: &mut H) {
91        self.inner.hash_value().hash(state)
92    }
93}
94
95impl WindowUDF {
96    /// Create a new `WindowUDF` from a `[WindowUDFImpl]` trait object
97    ///
98    /// Note this is the same as using the `From` impl (`WindowUDF::from`)
99    pub fn new_from_impl<F>(fun: F) -> WindowUDF
100    where
101        F: WindowUDFImpl + 'static,
102    {
103        Self::new_from_shared_impl(Arc::new(fun))
104    }
105
106    /// Create a new `WindowUDF` from a `[WindowUDFImpl]` trait object
107    pub fn new_from_shared_impl(fun: Arc<dyn WindowUDFImpl>) -> WindowUDF {
108        Self { inner: fun }
109    }
110
111    /// Return the underlying [`WindowUDFImpl`] trait object for this function
112    pub fn inner(&self) -> &Arc<dyn WindowUDFImpl> {
113        &self.inner
114    }
115
116    /// Adds additional names that can be used to invoke this function, in
117    /// addition to `name`
118    ///
119    /// If you implement [`WindowUDFImpl`] directly you should return aliases directly.
120    pub fn with_aliases(self, aliases: impl IntoIterator<Item = &'static str>) -> Self {
121        Self::new_from_impl(AliasedWindowUDFImpl::new(Arc::clone(&self.inner), aliases))
122    }
123
124    /// creates a [`Expr`] that calls the window function with default
125    /// values for `order_by`, `partition_by`, `window_frame`.
126    ///
127    /// See [`ExprFunctionExt`] for details on setting these values.
128    ///
129    /// This utility allows using a user defined window function without
130    /// requiring access to the registry, such as with the DataFrame API.
131    ///
132    /// [`ExprFunctionExt`]: crate::expr_fn::ExprFunctionExt
133    pub fn call(&self, args: Vec<Expr>) -> Expr {
134        let fun = crate::WindowFunctionDefinition::WindowUDF(Arc::new(self.clone()));
135
136        Expr::from(WindowFunction::new(fun, args))
137    }
138
139    /// Returns this function's name
140    ///
141    /// See [`WindowUDFImpl::name`] for more details.
142    pub fn name(&self) -> &str {
143        self.inner.name()
144    }
145
146    /// Returns the aliases for this function.
147    pub fn aliases(&self) -> &[String] {
148        self.inner.aliases()
149    }
150
151    /// Returns this function's signature (what input types are accepted)
152    ///
153    /// See [`WindowUDFImpl::signature`] for more details.
154    pub fn signature(&self) -> &Signature {
155        self.inner.signature()
156    }
157
158    /// Do the function rewrite
159    ///
160    /// See [`WindowUDFImpl::simplify`] for more details.
161    pub fn simplify(&self) -> Option<WindowFunctionSimplification> {
162        self.inner.simplify()
163    }
164
165    /// Expressions that are passed to the [`PartitionEvaluator`].
166    ///
167    /// See [`WindowUDFImpl::expressions`] for more details.
168    pub fn expressions(&self, expr_args: ExpressionArgs) -> Vec<Arc<dyn PhysicalExpr>> {
169        self.inner.expressions(expr_args)
170    }
171    /// Return a `PartitionEvaluator` for evaluating this window function
172    pub fn partition_evaluator_factory(
173        &self,
174        partition_evaluator_args: PartitionEvaluatorArgs,
175    ) -> Result<Box<dyn PartitionEvaluator>> {
176        self.inner.partition_evaluator(partition_evaluator_args)
177    }
178
179    /// Returns the field of the final result of evaluating this window function.
180    ///
181    /// See [`WindowUDFImpl::field`] for more details.
182    pub fn field(&self, field_args: WindowUDFFieldArgs) -> Result<FieldRef> {
183        self.inner.field(field_args)
184    }
185
186    /// Returns custom result ordering introduced by this window function
187    /// which is used to update ordering equivalences.
188    ///
189    /// See [`WindowUDFImpl::sort_options`] for more details.
190    pub fn sort_options(&self) -> Option<SortOptions> {
191        self.inner.sort_options()
192    }
193
194    /// See [`WindowUDFImpl::coerce_types`] for more details.
195    pub fn coerce_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
196        self.inner.coerce_types(arg_types)
197    }
198
199    /// Returns the reversed user-defined window function when the
200    /// order of evaluation is reversed.
201    ///
202    /// See [`WindowUDFImpl::reverse_expr`] for more details.
203    pub fn reverse_expr(&self) -> ReversedUDWF {
204        self.inner.reverse_expr()
205    }
206
207    /// Returns the documentation for this Window UDF.
208    ///
209    /// Documentation can be accessed programmatically as well as
210    /// generating publicly facing documentation.
211    pub fn documentation(&self) -> Option<&Documentation> {
212        self.inner.documentation()
213    }
214}
215
216impl<F> From<F> for WindowUDF
217where
218    F: WindowUDFImpl + Send + Sync + 'static,
219{
220    fn from(fun: F) -> Self {
221        Self::new_from_impl(fun)
222    }
223}
224
225/// Trait for implementing [`WindowUDF`].
226///
227/// This trait exposes the full API for implementing user defined window functions and
228/// can be used to implement any function.
229///
230/// See [`advanced_udwf.rs`] for a full example with complete implementation and
231/// [`WindowUDF`] for other available options.
232///
233///
234/// [`advanced_udwf.rs`]: https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/advanced_udwf.rs
235/// # Basic Example
236/// ```
237/// # use std::any::Any;
238/// # use std::sync::LazyLock;
239/// # use arrow::datatypes::{DataType, Field, FieldRef};
240/// # use datafusion_common::{DataFusionError, plan_err, Result};
241/// # use datafusion_expr::{col, Signature, Volatility, PartitionEvaluator, WindowFrame, ExprFunctionExt, Documentation};
242/// # use datafusion_expr::{WindowUDFImpl, WindowUDF};
243/// # use datafusion_functions_window_common::field::WindowUDFFieldArgs;
244/// # use datafusion_functions_window_common::partition::PartitionEvaluatorArgs;
245/// # use datafusion_expr::window_doc_sections::DOC_SECTION_ANALYTICAL;
246///
247/// #[derive(Debug, Clone)]
248/// struct SmoothIt {
249///   signature: Signature,
250/// }
251///
252/// impl SmoothIt {
253///   fn new() -> Self {
254///     Self {
255///       signature: Signature::uniform(1, vec![DataType::Int32], Volatility::Immutable),
256///      }
257///   }
258/// }
259///
260/// static DOCUMENTATION: LazyLock<Documentation> = LazyLock::new(|| {
261///     Documentation::builder(DOC_SECTION_ANALYTICAL, "smooths the windows", "smooth_it(2)")
262///         .with_argument("arg1", "The int32 number to smooth by")
263///         .build()
264/// });
265///
266/// fn get_doc() -> &'static Documentation {
267///     &DOCUMENTATION
268/// }
269///
270/// /// Implement the WindowUDFImpl trait for SmoothIt
271/// impl WindowUDFImpl for SmoothIt {
272///    fn as_any(&self) -> &dyn Any { self }
273///    fn name(&self) -> &str { "smooth_it" }
274///    fn signature(&self) -> &Signature { &self.signature }
275///    // The actual implementation would smooth the window
276///    fn partition_evaluator(
277///        &self,
278///        _partition_evaluator_args: PartitionEvaluatorArgs,
279///    ) -> Result<Box<dyn PartitionEvaluator>> {
280///        unimplemented!()
281///    }
282///    fn field(&self, field_args: WindowUDFFieldArgs) -> Result<FieldRef> {
283///      if let Some(DataType::Int32) = field_args.get_input_field(0).map(|f| f.data_type().clone()) {
284///        Ok(Field::new(field_args.name(), DataType::Int32, false).into())
285///      } else {
286///        plan_err!("smooth_it only accepts Int32 arguments")
287///      }
288///    }
289///    fn documentation(&self) -> Option<&Documentation> {
290///      Some(get_doc())
291///    }
292/// }
293///
294/// // Create a new WindowUDF from the implementation
295/// let smooth_it = WindowUDF::from(SmoothIt::new());
296///
297/// // Call the function `add_one(col)`
298/// // smooth_it(speed) OVER (PARTITION BY car ORDER BY time ASC)
299/// let expr = smooth_it.call(vec![col("speed")])
300///     .partition_by(vec![col("car")])
301///     .order_by(vec![col("time").sort(true, true)])
302///     .window_frame(WindowFrame::new(None))
303///     .build()
304///     .unwrap();
305/// ```
306pub trait WindowUDFImpl: Debug + Send + Sync {
307    // Note: When adding any methods (with default implementations), remember to add them also
308    // into the AliasedWindowUDFImpl below!
309
310    /// Returns this object as an [`Any`] trait object
311    fn as_any(&self) -> &dyn Any;
312
313    /// Returns this function's name
314    fn name(&self) -> &str;
315
316    /// Returns any aliases (alternate names) for this function.
317    ///
318    /// Note: `aliases` should only include names other than [`Self::name`].
319    /// Defaults to `[]` (no aliases)
320    fn aliases(&self) -> &[String] {
321        &[]
322    }
323
324    /// Returns the function's [`Signature`] for information about what input
325    /// types are accepted and the function's Volatility.
326    fn signature(&self) -> &Signature;
327
328    /// Returns the expressions that are passed to the [`PartitionEvaluator`].
329    fn expressions(&self, expr_args: ExpressionArgs) -> Vec<Arc<dyn PhysicalExpr>> {
330        expr_args.input_exprs().into()
331    }
332
333    /// Invoke the function, returning the [`PartitionEvaluator`] instance
334    fn partition_evaluator(
335        &self,
336        partition_evaluator_args: PartitionEvaluatorArgs,
337    ) -> Result<Box<dyn PartitionEvaluator>>;
338
339    /// Optionally apply per-UDWF simplification / rewrite rules.
340    ///
341    /// This can be used to apply function specific simplification rules during
342    /// optimization. The default implementation does nothing.
343    ///
344    /// Note that DataFusion handles simplifying arguments and  "constant
345    /// folding" (replacing a function call with constant arguments such as
346    /// `my_add(1,2) --> 3` ). Thus, there is no need to implement such
347    /// optimizations manually for specific UDFs.
348    ///
349    /// Example:
350    /// [`advanced_udwf.rs`]: <https://github.com/apache/arrow-datafusion/blob/main/datafusion-examples/examples/advanced_udwf.rs>
351    ///
352    /// # Returns
353    /// [None] if simplify is not defined or,
354    ///
355    /// Or, a closure with two arguments:
356    /// * 'window_function': [crate::expr::WindowFunction] for which simplified has been invoked
357    /// * 'info': [crate::simplify::SimplifyInfo]
358    fn simplify(&self) -> Option<WindowFunctionSimplification> {
359        None
360    }
361
362    /// Return true if this window UDF is equal to the other.
363    ///
364    /// Allows customizing the equality of window UDFs.
365    /// *Must* be implemented explicitly if the UDF type has internal state.
366    /// Must be consistent with [`Self::hash_value`] and follow the same rules as [`Eq`]:
367    ///
368    /// - reflexive: `a.equals(a)`;
369    /// - symmetric: `a.equals(b)` implies `b.equals(a)`;
370    /// - transitive: `a.equals(b)` and `b.equals(c)` implies `a.equals(c)`.
371    ///
372    /// By default, compares type, [`Self::name`], [`Self::aliases`] and [`Self::signature`].
373    fn equals(&self, other: &dyn WindowUDFImpl) -> bool {
374        self.as_any().type_id() == other.as_any().type_id()
375            && self.name() == other.name()
376            && self.aliases() == other.aliases()
377            && self.signature() == other.signature()
378    }
379
380    /// Returns a hash value for this window UDF.
381    ///
382    /// Allows customizing the hash code of window UDFs.
383    /// *Must* be implemented explicitly whenever [`Self::equals`] is implemented.
384    ///
385    /// Similarly to [`Hash`] and [`Eq`], if [`Self::equals`] returns true for two UDFs,
386    /// their `hash_value`s must be the same.
387    ///
388    /// By default, it is consistent with default implementation of [`Self::equals`].
389    fn hash_value(&self) -> u64 {
390        let hasher = &mut DefaultHasher::new();
391        self.as_any().type_id().hash(hasher);
392        self.name().hash(hasher);
393        self.aliases().hash(hasher);
394        self.signature().hash(hasher);
395        hasher.finish()
396    }
397
398    /// The [`FieldRef`] of the final result of evaluating this window function.
399    ///
400    /// Call `field_args.name()` to get the fully qualified name for defining
401    /// the [`FieldRef`]. For a complete example see the implementation in the
402    /// [Basic Example](WindowUDFImpl#basic-example) section.
403    fn field(&self, field_args: WindowUDFFieldArgs) -> Result<FieldRef>;
404
405    /// Allows the window UDF to define a custom result ordering.
406    ///
407    /// By default, a window UDF doesn't introduce an ordering.
408    /// But when specified by a window UDF this is used to update
409    /// ordering equivalences.
410    fn sort_options(&self) -> Option<SortOptions> {
411        None
412    }
413
414    /// Coerce arguments of a function call to types that the function can evaluate.
415    ///
416    /// This function is only called if [`WindowUDFImpl::signature`] returns [`crate::TypeSignature::UserDefined`]. Most
417    /// UDWFs should return one of the other variants of `TypeSignature` which handle common
418    /// cases
419    ///
420    /// See the [type coercion module](crate::type_coercion)
421    /// documentation for more details on type coercion
422    ///
423    /// For example, if your function requires a floating point arguments, but the user calls
424    /// it like `my_func(1::int)` (aka with `1` as an integer), coerce_types could return `[DataType::Float64]`
425    /// to ensure the argument was cast to `1::double`
426    ///
427    /// # Parameters
428    /// * `arg_types`: The argument types of the arguments  this function with
429    ///
430    /// # Return value
431    /// A Vec the same length as `arg_types`. DataFusion will `CAST` the function call
432    /// arguments to these specific types.
433    fn coerce_types(&self, _arg_types: &[DataType]) -> Result<Vec<DataType>> {
434        not_impl_err!("Function {} does not implement coerce_types", self.name())
435    }
436
437    /// Allows customizing the behavior of the user-defined window
438    /// function when it is evaluated in reverse order.
439    fn reverse_expr(&self) -> ReversedUDWF {
440        ReversedUDWF::NotSupported
441    }
442
443    /// Returns the documentation for this Window UDF.
444    ///
445    /// Documentation can be accessed programmatically as well as
446    /// generating publicly facing documentation.
447    fn documentation(&self) -> Option<&Documentation> {
448        None
449    }
450}
451
452pub enum ReversedUDWF {
453    /// The result of evaluating the user-defined window function
454    /// remains identical when reversed.
455    Identical,
456    /// A window function which does not support evaluating the result
457    /// in reverse order.
458    NotSupported,
459    /// Customize the user-defined window function for evaluating the
460    /// result in reverse order.
461    Reversed(Arc<WindowUDF>),
462}
463
464impl PartialEq for dyn WindowUDFImpl {
465    fn eq(&self, other: &Self) -> bool {
466        self.equals(other)
467    }
468}
469
470impl PartialOrd for dyn WindowUDFImpl {
471    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
472        match self.name().partial_cmp(other.name()) {
473            Some(Ordering::Equal) => self.signature().partial_cmp(other.signature()),
474            cmp => cmp,
475        }
476    }
477}
478
479/// WindowUDF that adds an alias to the underlying function. It is better to
480/// implement [`WindowUDFImpl`], which supports aliases, directly if possible.
481#[derive(Debug)]
482struct AliasedWindowUDFImpl {
483    inner: Arc<dyn WindowUDFImpl>,
484    aliases: Vec<String>,
485}
486
487impl AliasedWindowUDFImpl {
488    pub fn new(
489        inner: Arc<dyn WindowUDFImpl>,
490        new_aliases: impl IntoIterator<Item = &'static str>,
491    ) -> Self {
492        let mut aliases = inner.aliases().to_vec();
493        aliases.extend(new_aliases.into_iter().map(|s| s.to_string()));
494
495        Self { inner, aliases }
496    }
497}
498
499impl WindowUDFImpl for AliasedWindowUDFImpl {
500    fn as_any(&self) -> &dyn Any {
501        self
502    }
503
504    fn name(&self) -> &str {
505        self.inner.name()
506    }
507
508    fn signature(&self) -> &Signature {
509        self.inner.signature()
510    }
511
512    fn expressions(&self, expr_args: ExpressionArgs) -> Vec<Arc<dyn PhysicalExpr>> {
513        expr_args
514            .input_exprs()
515            .first()
516            .map_or(vec![], |expr| vec![Arc::clone(expr)])
517    }
518
519    fn partition_evaluator(
520        &self,
521        partition_evaluator_args: PartitionEvaluatorArgs,
522    ) -> Result<Box<dyn PartitionEvaluator>> {
523        self.inner.partition_evaluator(partition_evaluator_args)
524    }
525
526    fn aliases(&self) -> &[String] {
527        &self.aliases
528    }
529
530    fn simplify(&self) -> Option<WindowFunctionSimplification> {
531        self.inner.simplify()
532    }
533
534    fn equals(&self, other: &dyn WindowUDFImpl) -> bool {
535        if let Some(other) = other.as_any().downcast_ref::<AliasedWindowUDFImpl>() {
536            self.inner.equals(other.inner.as_ref()) && self.aliases == other.aliases
537        } else {
538            false
539        }
540    }
541
542    fn hash_value(&self) -> u64 {
543        let hasher = &mut DefaultHasher::new();
544        self.inner.hash_value().hash(hasher);
545        self.aliases.hash(hasher);
546        hasher.finish()
547    }
548
549    fn field(&self, field_args: WindowUDFFieldArgs) -> Result<FieldRef> {
550        self.inner.field(field_args)
551    }
552
553    fn sort_options(&self) -> Option<SortOptions> {
554        self.inner.sort_options()
555    }
556
557    fn coerce_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
558        self.inner.coerce_types(arg_types)
559    }
560
561    fn documentation(&self) -> Option<&Documentation> {
562        self.inner.documentation()
563    }
564}
565
566// Window UDF doc sections for use in public documentation
567pub mod window_doc_sections {
568    use datafusion_doc::DocSection;
569
570    pub fn doc_sections() -> Vec<DocSection> {
571        vec![
572            DOC_SECTION_AGGREGATE,
573            DOC_SECTION_RANKING,
574            DOC_SECTION_ANALYTICAL,
575        ]
576    }
577
578    pub const DOC_SECTION_AGGREGATE: DocSection = DocSection {
579        include: true,
580        label: "Aggregate Functions",
581        description: Some("All aggregate functions can be used as window functions."),
582    };
583
584    pub const DOC_SECTION_RANKING: DocSection = DocSection {
585        include: true,
586        label: "Ranking Functions",
587        description: None,
588    };
589
590    pub const DOC_SECTION_ANALYTICAL: DocSection = DocSection {
591        include: true,
592        label: "Analytical Functions",
593        description: None,
594    };
595}
596
597#[cfg(test)]
598mod test {
599    use crate::{PartitionEvaluator, WindowUDF, WindowUDFImpl};
600    use arrow::datatypes::{DataType, FieldRef};
601    use datafusion_common::Result;
602    use datafusion_expr_common::signature::{Signature, Volatility};
603    use datafusion_functions_window_common::field::WindowUDFFieldArgs;
604    use datafusion_functions_window_common::partition::PartitionEvaluatorArgs;
605    use std::any::Any;
606    use std::cmp::Ordering;
607
608    #[derive(Debug, Clone)]
609    struct AWindowUDF {
610        signature: Signature,
611    }
612
613    impl AWindowUDF {
614        fn new() -> Self {
615            Self {
616                signature: Signature::uniform(
617                    1,
618                    vec![DataType::Int32],
619                    Volatility::Immutable,
620                ),
621            }
622        }
623    }
624
625    /// Implement the WindowUDFImpl trait for AddOne
626    impl WindowUDFImpl for AWindowUDF {
627        fn as_any(&self) -> &dyn Any {
628            self
629        }
630        fn name(&self) -> &str {
631            "a"
632        }
633        fn signature(&self) -> &Signature {
634            &self.signature
635        }
636        fn partition_evaluator(
637            &self,
638            _partition_evaluator_args: PartitionEvaluatorArgs,
639        ) -> Result<Box<dyn PartitionEvaluator>> {
640            unimplemented!()
641        }
642        fn field(&self, _field_args: WindowUDFFieldArgs) -> Result<FieldRef> {
643            unimplemented!()
644        }
645    }
646
647    #[derive(Debug, Clone)]
648    struct BWindowUDF {
649        signature: Signature,
650    }
651
652    impl BWindowUDF {
653        fn new() -> Self {
654            Self {
655                signature: Signature::uniform(
656                    1,
657                    vec![DataType::Int32],
658                    Volatility::Immutable,
659                ),
660            }
661        }
662    }
663
664    /// Implement the WindowUDFImpl trait for AddOne
665    impl WindowUDFImpl for BWindowUDF {
666        fn as_any(&self) -> &dyn Any {
667            self
668        }
669        fn name(&self) -> &str {
670            "b"
671        }
672        fn signature(&self) -> &Signature {
673            &self.signature
674        }
675        fn partition_evaluator(
676            &self,
677            _partition_evaluator_args: PartitionEvaluatorArgs,
678        ) -> Result<Box<dyn PartitionEvaluator>> {
679            unimplemented!()
680        }
681        fn field(&self, _field_args: WindowUDFFieldArgs) -> Result<FieldRef> {
682            unimplemented!()
683        }
684    }
685
686    #[test]
687    fn test_partial_ord() {
688        let a1 = WindowUDF::from(AWindowUDF::new());
689        let a2 = WindowUDF::from(AWindowUDF::new());
690        assert_eq!(a1.partial_cmp(&a2), Some(Ordering::Equal));
691
692        let b1 = WindowUDF::from(BWindowUDF::new());
693        assert!(a1 < b1);
694        assert!(!(a1 == b1));
695    }
696}