You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by al...@apache.org on 2024/10/03 14:43:36 UTC
(datafusion) branch main updated: Adds macros for creating `WindowUDF` and `WindowFunction` expression (#12693)
This is an automated email from the ASF dual-hosted git repository.
alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git
The following commit(s) were added to refs/heads/main by this push:
new cfd861c29a Adds macros for creating `WindowUDF` and `WindowFunction` expression (#12693)
cfd861c29a is described below
commit cfd861c29a54dffb0e6b434dddc4682dfd58d2a4
Author: jcsherin <ja...@protoship.io>
AuthorDate: Thu Oct 3 20:13:30 2024 +0530
Adds macros for creating `WindowUDF` and `WindowFunction` expression (#12693)
* Adds macro for udwf singleton
* Adds a doc comment parameter to macro
* Add doc comment for `create_udwf` macro
* Uses default constructor
* Update `Cargo.lock` in `datafusion-cli`
* Fixes: expand `$FN_NAME` in doc strings
* Adds example for macro usage
* Renames macro
* Improve doc comments
* Rename udwf macro
* Minor: doc copy edits
* Adds macro for creating fluent-style expression API
* Adds support for 1 or more parameters in expression function
* Rewrite doc comments
* Rename parameters
* Minor: formatting
* Adds doc comment for `create_udwf_expr` macro
* Improve example docs
* Hides extraneous code in doc comments
* Add a one-line readme
* Adds doc test assertions + minor formatting fixes
* Adds common macro for defining user-defined window functions
* Adds doc comment for `define_udwf_and_expr`
* Defines `RowNumber` using common macro
* Add usage example for common macro
* Adds usage for custom constructor
* Add examples for remaining patterns
* Improve doc comments for usage examples
* Rewrite inner line docs
* Rewrite `create_udwf_expr!` doc comments
* Minor doc improvements
* Fix doc test and usage example
* Add inline comments for macro patterns
* Minor: change doc comment in example
---
datafusion-cli/Cargo.lock | 159 +++---
datafusion/functions-window/Cargo.toml | 1 +
datafusion/functions-window/src/lib.rs | 2 +
datafusion/functions-window/src/macros.rs | 674 ++++++++++++++++++++++++++
datafusion/functions-window/src/row_number.rs | 28 +-
5 files changed, 742 insertions(+), 122 deletions(-)
diff --git a/datafusion-cli/Cargo.lock b/datafusion-cli/Cargo.lock
index 2d7ff2af89..a1157cbffb 100644
--- a/datafusion-cli/Cargo.lock
+++ b/datafusion-cli/Cargo.lock
@@ -424,9 +424,9 @@ dependencies = [
[[package]]
name = "async-trait"
-version = "0.1.82"
+version = "0.1.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1"
+checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
dependencies = [
"proc-macro2",
"quote",
@@ -450,15 +450,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "autocfg"
-version = "1.3.0"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "aws-config"
-version = "1.5.6"
+version = "1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "848d7b9b605720989929279fa644ce8f244d0ce3146fcca5b70e4eb7b3c020fc"
+checksum = "8191fb3091fa0561d1379ef80333c3c7191c6f0435d986e85821bcf7acbd1126"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -523,9 +523,9 @@ dependencies = [
[[package]]
name = "aws-sdk-sso"
-version = "1.43.0"
+version = "1.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70a9d27ed1c12b1140c47daf1bc541606c43fdafd918c4797d520db0043ceef2"
+checksum = "0b90cfe6504115e13c41d3ea90286ede5aa14da294f3fe077027a6e83850843c"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -545,9 +545,9 @@ dependencies = [
[[package]]
name = "aws-sdk-ssooidc"
-version = "1.44.0"
+version = "1.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44514a6ca967686cde1e2a1b81df6ef1883d0e3e570da8d8bc5c491dcb6fc29b"
+checksum = "167c0fad1f212952084137308359e8e4c4724d1c643038ce163f06de9662c1d0"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -567,9 +567,9 @@ dependencies = [
[[package]]
name = "aws-sdk-sts"
-version = "1.43.0"
+version = "1.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd7a4d279762a35b9df97209f6808b95d4fe78547fe2316b4d200a0283960c5a"
+checksum = "2cb5f98188ec1435b68097daa2a37d74b9d17c9caa799466338a8d1544e71b9d"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -707,9 +707,9 @@ dependencies = [
[[package]]
name = "aws-smithy-types"
-version = "1.2.6"
+version = "1.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03701449087215b5369c7ea17fef0dd5d24cb93439ec5af0c7615f58c3f22605"
+checksum = "147100a7bea70fa20ef224a6bad700358305f5dc0f84649c53769761395b355b"
dependencies = [
"base64-simd",
"bytes",
@@ -917,9 +917,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.1.21"
+version = "1.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0"
+checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
dependencies = [
"jobserver",
"libc",
@@ -975,9 +975,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.17"
+version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac"
+checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3"
dependencies = [
"clap_builder",
"clap_derive",
@@ -985,9 +985,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.17"
+version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73"
+checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b"
dependencies = [
"anstream",
"anstyle",
@@ -997,9 +997,9 @@ dependencies = [
[[package]]
name = "clap_derive"
-version = "4.5.13"
+version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
+checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
dependencies = [
"heck 0.5.0",
"proc-macro2",
@@ -1447,6 +1447,7 @@ dependencies = [
"datafusion-functions-window-common",
"datafusion-physical-expr-common",
"log",
+ "paste",
]
[[package]]
@@ -1722,9 +1723,9 @@ dependencies = [
[[package]]
name = "flate2"
-version = "1.0.33"
+version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253"
+checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0"
dependencies = [
"crc32fast",
"miniz_oxide",
@@ -2137,9 +2138,9 @@ dependencies = [
[[package]]
name = "hyper-util"
-version = "0.1.8"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba"
+checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b"
dependencies = [
"bytes",
"futures-channel",
@@ -2150,7 +2151,6 @@ dependencies = [
"pin-project-lite",
"socket2",
"tokio",
- "tower",
"tower-service",
"tracing",
]
@@ -2333,9 +2333,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.158"
+version = "0.2.159"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
+checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
[[package]]
name = "libflate"
@@ -2799,26 +2799,6 @@ dependencies = [
"siphasher",
]
-[[package]]
-name = "pin-project"
-version = "1.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
-dependencies = [
- "pin-project-internal",
-]
-
-[[package]]
-name = "pin-project-internal"
-version = "1.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
[[package]]
name = "pin-project-lite"
version = "0.2.14"
@@ -2833,9 +2813,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "powerfmt"
@@ -2908,9 +2888,9 @@ checksum = "b76f1009795ca44bb5aaae8fd3f18953e209259c33d9b059b1f53d58ab7511db"
[[package]]
name = "quick-xml"
-version = "0.36.1"
+version = "0.36.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96a05e2e8efddfa51a84ca47cec303fac86c8541b686d37cac5efc0e094417bc"
+checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe"
dependencies = [
"memchr",
"serde",
@@ -3015,9 +2995,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.5.4"
+version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853"
+checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b"
dependencies = [
"bitflags 2.6.0",
]
@@ -3289,9 +3269,9 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
-version = "1.8.0"
+version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0"
+checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55"
[[package]]
name = "rustls-webpki"
@@ -3397,9 +3377,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
-version = "2.11.1"
+version = "2.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf"
+checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6"
dependencies = [
"core-foundation-sys",
"libc",
@@ -3510,18 +3490,18 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "snafu"
-version = "0.8.4"
+version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b835cb902660db3415a672d862905e791e54d306c6e8189168c7f3d9ae1c79d"
+checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019"
dependencies = [
"snafu-derive",
]
[[package]]
name = "snafu-derive"
-version = "0.8.4"
+version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38d1e02fca405f6280643174a50c942219f0bbf4dbf7d480f1dd864d6f211ae5"
+checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917"
dependencies = [
"heck 0.5.0",
"proc-macro2",
@@ -3633,9 +3613,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
-version = "2.0.77"
+version = "2.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
+checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
dependencies = [
"proc-macro2",
"quote",
@@ -3653,9 +3633,9 @@ dependencies = [
[[package]]
name = "tempfile"
-version = "3.12.0"
+version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
+checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
dependencies = [
"cfg-if",
"fastrand",
@@ -3672,18 +3652,18 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
[[package]]
name = "thiserror"
-version = "1.0.63"
+version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
+checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.63"
+version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
+checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
dependencies = [
"proc-macro2",
"quote",
@@ -3826,36 +3806,15 @@ checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
[[package]]
name = "toml_edit"
-version = "0.22.21"
+version = "0.22.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
dependencies = [
"indexmap",
"toml_datetime",
"winnow",
]
-[[package]]
-name = "tower"
-version = "0.4.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
-dependencies = [
- "futures-core",
- "futures-util",
- "pin-project",
- "pin-project-lite",
- "tokio",
- "tower-layer",
- "tower-service",
-]
-
-[[package]]
-name = "tower-layer"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
-
[[package]]
name = "tower-service"
version = "0.3.3"
@@ -3964,9 +3923,9 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-width"
-version = "0.1.13"
+version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "untrusted"
@@ -4122,9 +4081,9 @@ checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
[[package]]
name = "wasm-streams"
-version = "0.4.0"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
+checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd"
dependencies = [
"futures-util",
"js-sys",
@@ -4341,9 +4300,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
-version = "0.6.18"
+version = "0.6.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
dependencies = [
"memchr",
]
diff --git a/datafusion/functions-window/Cargo.toml b/datafusion/functions-window/Cargo.toml
index 8dcec6bc96..952e5720c7 100644
--- a/datafusion/functions-window/Cargo.toml
+++ b/datafusion/functions-window/Cargo.toml
@@ -43,6 +43,7 @@ datafusion-expr = { workspace = true }
datafusion-functions-window-common = { workspace = true }
datafusion-physical-expr-common = { workspace = true }
log = { workspace = true }
+paste = "1.0.15"
[dev-dependencies]
arrow = { workspace = true }
diff --git a/datafusion/functions-window/src/lib.rs b/datafusion/functions-window/src/lib.rs
index 790a500f1f..6e98bb0914 100644
--- a/datafusion/functions-window/src/lib.rs
+++ b/datafusion/functions-window/src/lib.rs
@@ -29,6 +29,8 @@ use log::debug;
use datafusion_expr::registry::FunctionRegistry;
use datafusion_expr::WindowUDF;
+#[macro_use]
+pub mod macros;
pub mod row_number;
/// Fluent-style API for creating `Expr`s
diff --git a/datafusion/functions-window/src/macros.rs b/datafusion/functions-window/src/macros.rs
new file mode 100644
index 0000000000..843d8ecb38
--- /dev/null
+++ b/datafusion/functions-window/src/macros.rs
@@ -0,0 +1,674 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+//! Convenience macros for defining a user-defined window function
+//! and associated expression API (fluent style).
+//!
+//! See [`define_udwf_and_expr!`] for usage examples.
+//!
+//! [`define_udwf_and_expr!`]: crate::define_udwf_and_expr!
+
+/// Lazily initializes a user-defined window function exactly once
+/// when called concurrently. Repeated calls return a reference to the
+/// same instance.
+///
+/// # Parameters
+///
+/// * `$UDWF`: The struct which defines the [`Signature`](datafusion_expr::Signature)
+/// of the user-defined window function.
+/// * `$OUT_FN_NAME`: The basename to generate a unique function name like
+/// `$OUT_FN_NAME_udwf`.
+/// * `$DOC`: Doc comments for UDWF.
+/// * (optional) `$CTOR`: Pass a custom constructor. When omitted it
+/// automatically resolves to `$UDWF::default()`.
+///
+/// # Example
+///
+/// ```
+/// # use std::any::Any;
+/// # use datafusion_common::arrow::datatypes::{DataType, Field};
+/// # use datafusion_expr::{PartitionEvaluator, Signature, Volatility, WindowUDFImpl};
+/// #
+/// # use datafusion_functions_window_common::field::WindowUDFFieldArgs;
+/// # use datafusion_functions_window::get_or_init_udwf;
+/// #
+/// /// Defines the `simple_udwf()` user-defined window function.
+/// get_or_init_udwf!(
+/// SimpleUDWF,
+/// simple,
+/// "Simple user-defined window function doc comment."
+/// );
+/// #
+/// # assert_eq!(simple_udwf().name(), "simple_user_defined_window_function");
+/// #
+/// # #[derive(Debug)]
+/// # struct SimpleUDWF {
+/// # signature: Signature,
+/// # }
+/// #
+/// # impl Default for SimpleUDWF {
+/// # fn default() -> Self {
+/// # Self {
+/// # signature: Signature::any(0, Volatility::Immutable),
+/// # }
+/// # }
+/// # }
+/// #
+/// # impl WindowUDFImpl for SimpleUDWF {
+/// # fn as_any(&self) -> &dyn Any {
+/// # self
+/// # }
+/// # fn name(&self) -> &str {
+/// # "simple_user_defined_window_function"
+/// # }
+/// # fn signature(&self) -> &Signature {
+/// # &self.signature
+/// # }
+/// # fn partition_evaluator(
+/// # &self,
+/// # ) -> datafusion_common::Result<Box<dyn PartitionEvaluator>> {
+/// # unimplemented!()
+/// # }
+/// # fn field(&self, field_args: WindowUDFFieldArgs) -> datafusion_common::Result<Field> {
+/// # Ok(Field::new(field_args.name(), DataType::Int64, false))
+/// # }
+/// # }
+/// #
+/// ```
+#[macro_export]
+macro_rules! get_or_init_udwf {
+ ($UDWF:ident, $OUT_FN_NAME:ident, $DOC:expr) => {
+ get_or_init_udwf!($UDWF, $OUT_FN_NAME, $DOC, $UDWF::default);
+ };
+
+ ($UDWF:ident, $OUT_FN_NAME:ident, $DOC:expr, $CTOR:path) => {
+ paste::paste! {
+ #[doc = concat!(" Singleton instance of [`", stringify!($OUT_FN_NAME), "`], ensures the user-defined")]
+ #[doc = concat!(" window function is only created once.")]
+ #[allow(non_upper_case_globals)]
+ static [<STATIC_ $UDWF>]: std::sync::OnceLock<std::sync::Arc<datafusion_expr::WindowUDF>> =
+ std::sync::OnceLock::new();
+
+ #[doc = concat!(" Returns a [`WindowUDF`](datafusion_expr::WindowUDF) for [`", stringify!($OUT_FN_NAME), "`].")]
+ #[doc = ""]
+ #[doc = concat!(" ", $DOC)]
+ pub fn [<$OUT_FN_NAME _udwf>]() -> std::sync::Arc<datafusion_expr::WindowUDF> {
+ [<STATIC_ $UDWF>]
+ .get_or_init(|| {
+ std::sync::Arc::new(datafusion_expr::WindowUDF::from($CTOR()))
+ })
+ .clone()
+ }
+ }
+ };
+}
+
+/// Create a [`WindowFunction`] expression that exposes a fluent API
+/// which you can use to build more complex expressions.
+///
+/// [`WindowFunction`]: datafusion_expr::Expr::WindowFunction
+///
+/// # Parameters
+///
+/// * `$UDWF`: The struct which defines the [`Signature`] of the
+/// user-defined window function.
+/// * `$OUT_FN_NAME`: The basename to generate a unique function name like
+/// `$OUT_FN_NAME_udwf`.
+/// * `$DOC`: Doc comments for UDWF.
+/// * (optional) `[$($PARAM:ident),+]`: An array of 1 or more parameters
+/// for the generated function. The type of parameters is [`Expr`].
+/// When omitted this creates a function with zero parameters.
+///
+/// [`Signature`]: datafusion_expr::Signature
+/// [`Expr`]: datafusion_expr::Expr
+///
+/// # Example
+///
+/// 1. With Zero Parameters
+/// ```
+/// # use std::any::Any;
+/// # use datafusion_common::arrow::datatypes::{DataType, Field};
+/// # use datafusion_expr::{PartitionEvaluator, Signature, Volatility, WindowUDFImpl};
+/// # use datafusion_functions_window::{create_udwf_expr, get_or_init_udwf};
+/// # use datafusion_functions_window_common::field::WindowUDFFieldArgs;
+/// # get_or_init_udwf!(
+/// # RowNumber,
+/// # row_number,
+/// # "Returns a unique row number for each row in window partition beginning at 1."
+/// # );
+/// /// Creates `row_number()` API which has zero parameters:
+/// ///
+/// /// ```
+/// /// /// Returns a unique row number for each row in window partition
+/// /// /// beginning at 1.
+/// /// pub fn row_number() -> datafusion_expr::Expr {
+/// /// row_number_udwf().call(vec![])
+/// /// }
+/// /// ```
+/// create_udwf_expr!(
+/// RowNumber,
+/// row_number,
+/// "Returns a unique row number for each row in window partition beginning at 1."
+/// );
+/// #
+/// # assert_eq!(
+/// # row_number().name_for_alias().unwrap(),
+/// # "row_number() ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING"
+/// # );
+/// #
+/// # #[derive(Debug)]
+/// # struct RowNumber {
+/// # signature: Signature,
+/// # }
+/// # impl Default for RowNumber {
+/// # fn default() -> Self {
+/// # Self {
+/// # signature: Signature::any(0, Volatility::Immutable),
+/// # }
+/// # }
+/// # }
+/// # impl WindowUDFImpl for RowNumber {
+/// # fn as_any(&self) -> &dyn Any {
+/// # self
+/// # }
+/// # fn name(&self) -> &str {
+/// # "row_number"
+/// # }
+/// # fn signature(&self) -> &Signature {
+/// # &self.signature
+/// # }
+/// # fn partition_evaluator(
+/// # &self,
+/// # ) -> datafusion_common::Result<Box<dyn PartitionEvaluator>> {
+/// # unimplemented!()
+/// # }
+/// # fn field(&self, field_args: WindowUDFFieldArgs) -> datafusion_common::Result<Field> {
+/// # Ok(Field::new(field_args.name(), DataType::UInt64, false))
+/// # }
+/// # }
+/// ```
+///
+/// 2. With Multiple Parameters
+/// ```
+/// # use std::any::Any;
+/// #
+/// # use datafusion_expr::{
+/// # PartitionEvaluator, Signature, TypeSignature, Volatility, WindowUDFImpl,
+/// # };
+/// #
+/// # use datafusion_functions_window::{create_udwf_expr, get_or_init_udwf};
+/// # use datafusion_functions_window_common::field::WindowUDFFieldArgs;
+/// #
+/// # use datafusion_common::arrow::datatypes::Field;
+/// # use datafusion_common::ScalarValue;
+/// # use datafusion_expr::{col, lit};
+/// #
+/// # get_or_init_udwf!(Lead, lead, "user-defined window function");
+/// #
+/// /// Creates `lead(expr, offset, default)` with 3 parameters:
+/// ///
+/// /// ```
+/// /// /// Returns a value evaluated at the row that is offset rows
+/// /// /// after the current row within the partition.
+/// /// pub fn lead(
+/// /// expr: datafusion_expr::Expr,
+/// /// offset: datafusion_expr::Expr,
+/// /// default: datafusion_expr::Expr,
+/// /// ) -> datafusion_expr::Expr {
+/// /// lead_udwf().call(vec![expr, offset, default])
+/// /// }
+/// /// ```
+/// create_udwf_expr!(
+/// Lead,
+/// lead,
+/// [expr, offset, default],
+/// "Returns a value evaluated at the row that is offset rows after the current row within the partition."
+/// );
+/// #
+/// # assert_eq!(
+/// # lead(col("a"), lit(1i64), lit(ScalarValue::Null))
+/// # .name_for_alias()
+/// # .unwrap(),
+/// # "lead(a,Int64(1),NULL) ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING"
+/// # );
+/// #
+/// # #[derive(Debug)]
+/// # struct Lead {
+/// # signature: Signature,
+/// # }
+/// #
+/// # impl Default for Lead {
+/// # fn default() -> Self {
+/// # Self {
+/// # signature: Signature::one_of(
+/// # vec![
+/// # TypeSignature::Any(1),
+/// # TypeSignature::Any(2),
+/// # TypeSignature::Any(3),
+/// # ],
+/// # Volatility::Immutable,
+/// # ),
+/// # }
+/// # }
+/// # }
+/// #
+/// # impl WindowUDFImpl for Lead {
+/// # fn as_any(&self) -> &dyn Any {
+/// # self
+/// # }
+/// # fn name(&self) -> &str {
+/// # "lead"
+/// # }
+/// # fn signature(&self) -> &Signature {
+/// # &self.signature
+/// # }
+/// # fn partition_evaluator(
+/// # &self,
+/// # ) -> datafusion_common::Result<Box<dyn PartitionEvaluator>> {
+/// # unimplemented!()
+/// # }
+/// # fn field(&self, field_args: WindowUDFFieldArgs) -> datafusion_common::Result<Field> {
+/// # Ok(Field::new(
+/// # field_args.name(),
+/// # field_args.get_input_type(0).unwrap(),
+/// # false,
+/// # ))
+/// # }
+/// # }
+/// ```
+#[macro_export]
+macro_rules! create_udwf_expr {
+ // zero arguments
+ ($UDWF:ident, $OUT_FN_NAME:ident, $DOC:expr) => {
+ paste::paste! {
+ #[doc = " Create a [`WindowFunction`](datafusion_expr::Expr::WindowFunction) expression for"]
+ #[doc = concat!(" [`", stringify!($UDWF), "`] user-defined window function.")]
+ #[doc = ""]
+ #[doc = concat!(" ", $DOC)]
+ pub fn $OUT_FN_NAME() -> datafusion_expr::Expr {
+ [<$OUT_FN_NAME _udwf>]().call(vec![])
+ }
+ }
+ };
+
+ // 1 or more arguments
+ ($UDWF:ident, $OUT_FN_NAME:ident, [$($PARAM:ident),+], $DOC:expr) => {
+ paste::paste! {
+ #[doc = " Create a [`WindowFunction`](datafusion_expr::Expr::WindowFunction) expression for"]
+ #[doc = concat!(" [`", stringify!($UDWF), "`] user-defined window function.")]
+ #[doc = ""]
+ #[doc = concat!(" ", $DOC)]
+ pub fn $OUT_FN_NAME(
+ $($PARAM: datafusion_expr::Expr),+
+ ) -> datafusion_expr::Expr {
+ [<$OUT_FN_NAME _udwf>]()
+ .call(vec![$($PARAM),+])
+ }
+ }
+ };
+}
+
+/// Defines a user-defined window function.
+///
+/// Combines [`get_or_init_udwf!`] and [`create_udwf_expr!`] into a
+/// single macro for convenience.
+///
+/// # Arguments
+///
+/// * `$UDWF`: The struct which defines the [`Signature`] of the
+/// user-defined window function.
+/// * `$OUT_FN_NAME`: The basename to generate a unique function name like
+/// `$OUT_FN_NAME_udwf`.
+/// * (optional) `[$($PARAM:ident),+]`: An array of 1 or more parameters
+/// for the generated function. The type of parameters is [`Expr`].
+/// When omitted this creates a function with zero parameters.
+/// * `$DOC`: Doc comments for UDWF.
+/// * (optional) `$CTOR`: Pass a custom constructor. When omitted it
+/// automatically resolves to `$UDWF::default()`.
+///
+/// [`Signature`]: datafusion_expr::Signature
+/// [`Expr`]: datafusion_expr::Expr
+///
+/// # Usage
+///
+/// ## Expression API With Zero parameters
+/// 1. Uses default constructor for UDWF.
+///
+/// ```
+/// # use std::any::Any;
+/// # use datafusion_common::arrow::datatypes::{DataType, Field};
+/// # use datafusion_expr::{PartitionEvaluator, Signature, Volatility, WindowUDFImpl};
+/// #
+/// # use datafusion_functions_window_common::field::WindowUDFFieldArgs;
+/// # use datafusion_functions_window::{define_udwf_and_expr, get_or_init_udwf, create_udwf_expr};
+/// #
+/// /// 1. Defines the `simple_udwf()` user-defined window function.
+/// ///
+/// /// 2. Defines the expression API:
+/// /// ```
+/// /// pub fn simple() -> datafusion_expr::Expr {
+/// /// simple_udwf().call(vec![])
+/// /// }
+/// /// ```
+/// define_udwf_and_expr!(
+/// SimpleUDWF,
+/// simple,
+/// "a simple user-defined window function"
+/// );
+/// #
+/// # assert_eq!(simple_udwf().name(), "simple_user_defined_window_function");
+/// #
+/// # #[derive(Debug)]
+/// # struct SimpleUDWF {
+/// # signature: Signature,
+/// # }
+/// #
+/// # impl Default for SimpleUDWF {
+/// # fn default() -> Self {
+/// # Self {
+/// # signature: Signature::any(0, Volatility::Immutable),
+/// # }
+/// # }
+/// # }
+/// #
+/// # impl WindowUDFImpl for SimpleUDWF {
+/// # fn as_any(&self) -> &dyn Any {
+/// # self
+/// # }
+/// # fn name(&self) -> &str {
+/// # "simple_user_defined_window_function"
+/// # }
+/// # fn signature(&self) -> &Signature {
+/// # &self.signature
+/// # }
+/// # fn partition_evaluator(
+/// # &self,
+/// # ) -> datafusion_common::Result<Box<dyn PartitionEvaluator>> {
+/// # unimplemented!()
+/// # }
+/// # fn field(&self, field_args: WindowUDFFieldArgs) -> datafusion_common::Result<Field> {
+/// # Ok(Field::new(field_args.name(), DataType::Int64, false))
+/// # }
+/// # }
+/// #
+/// ```
+///
+/// 2. Uses a custom constructor for UDWF.
+///
+/// ```
+/// # use std::any::Any;
+/// # use datafusion_common::arrow::datatypes::{DataType, Field};
+/// # use datafusion_expr::{PartitionEvaluator, Signature, Volatility, WindowUDFImpl};
+/// # use datafusion_functions_window::{create_udwf_expr, define_udwf_and_expr, get_or_init_udwf};
+/// # use datafusion_functions_window_common::field::WindowUDFFieldArgs;
+/// #
+/// /// 1. Defines the `row_number_udwf()` user-defined window function.
+/// ///
+/// /// 2. Defines the expression API:
+/// /// ```
+/// /// pub fn row_number() -> datafusion_expr::Expr {
+/// /// row_number_udwf().call(vec![])
+/// /// }
+/// /// ```
+/// define_udwf_and_expr!(
+/// RowNumber,
+/// row_number,
+/// "Returns a unique row number for each row in window partition beginning at 1.",
+/// RowNumber::new // <-- custom constructor
+/// );
+/// #
+/// # assert_eq!(
+/// # row_number().name_for_alias().unwrap(),
+/// # "row_number() ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING"
+/// # );
+/// #
+/// # #[derive(Debug)]
+/// # struct RowNumber {
+/// # signature: Signature,
+/// # }
+/// # impl RowNumber {
+/// # fn new() -> Self {
+/// # Self {
+/// # signature: Signature::any(0, Volatility::Immutable),
+/// # }
+/// # }
+/// # }
+/// # impl WindowUDFImpl for RowNumber {
+/// # fn as_any(&self) -> &dyn Any {
+/// # self
+/// # }
+/// # fn name(&self) -> &str {
+/// # "row_number"
+/// # }
+/// # fn signature(&self) -> &Signature {
+/// # &self.signature
+/// # }
+/// # fn partition_evaluator(
+/// # &self,
+/// # ) -> datafusion_common::Result<Box<dyn PartitionEvaluator>> {
+/// # unimplemented!()
+/// # }
+/// # fn field(&self, field_args: WindowUDFFieldArgs) -> datafusion_common::Result<Field> {
+/// # Ok(Field::new(field_args.name(), DataType::UInt64, false))
+/// # }
+/// # }
+/// ```
+///
+/// ## Expression API With Multiple Parameters
+/// 3. Uses default constructor for UDWF
+///
+/// ```
+/// # use std::any::Any;
+/// #
+/// # use datafusion_expr::{
+/// # PartitionEvaluator, Signature, TypeSignature, Volatility, WindowUDFImpl,
+/// # };
+/// #
+/// # use datafusion_functions_window::{create_udwf_expr, define_udwf_and_expr, get_or_init_udwf};
+/// # use datafusion_functions_window_common::field::WindowUDFFieldArgs;
+/// #
+/// # use datafusion_common::arrow::datatypes::Field;
+/// # use datafusion_common::ScalarValue;
+/// # use datafusion_expr::{col, lit};
+/// #
+/// /// 1. Defines the `lead_udwf()` user-defined window function.
+/// ///
+/// /// 2. Defines the expression API:
+/// /// ```
+/// /// pub fn lead(
+/// /// expr: datafusion_expr::Expr,
+/// /// offset: datafusion_expr::Expr,
+/// /// default: datafusion_expr::Expr,
+/// /// ) -> datafusion_expr::Expr {
+/// /// lead_udwf().call(vec![expr, offset, default])
+/// /// }
+/// /// ```
+/// define_udwf_and_expr!(
+/// Lead,
+/// lead,
+/// [expr, offset, default], // <- 3 parameters
+/// "user-defined window function"
+/// );
+/// #
+/// # assert_eq!(
+/// # lead(col("a"), lit(1i64), lit(ScalarValue::Null))
+/// # .name_for_alias()
+/// # .unwrap(),
+/// # "lead(a,Int64(1),NULL) ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING"
+/// # );
+/// #
+/// # #[derive(Debug)]
+/// # struct Lead {
+/// # signature: Signature,
+/// # }
+/// #
+/// # impl Default for Lead {
+/// # fn default() -> Self {
+/// # Self {
+/// # signature: Signature::one_of(
+/// # vec![
+/// # TypeSignature::Any(1),
+/// # TypeSignature::Any(2),
+/// # TypeSignature::Any(3),
+/// # ],
+/// # Volatility::Immutable,
+/// # ),
+/// # }
+/// # }
+/// # }
+/// #
+/// # impl WindowUDFImpl for Lead {
+/// # fn as_any(&self) -> &dyn Any {
+/// # self
+/// # }
+/// # fn name(&self) -> &str {
+/// # "lead"
+/// # }
+/// # fn signature(&self) -> &Signature {
+/// # &self.signature
+/// # }
+/// # fn partition_evaluator(
+/// # &self,
+/// # ) -> datafusion_common::Result<Box<dyn PartitionEvaluator>> {
+/// # unimplemented!()
+/// # }
+/// # fn field(&self, field_args: WindowUDFFieldArgs) -> datafusion_common::Result<Field> {
+/// # Ok(Field::new(
+/// # field_args.name(),
+/// # field_args.get_input_type(0).unwrap(),
+/// # false,
+/// # ))
+/// # }
+/// # }
+/// ```
+/// 4. Uses custom constructor for UDWF
+///
+/// ```
+/// # use std::any::Any;
+/// #
+/// # use datafusion_expr::{
+/// # PartitionEvaluator, Signature, TypeSignature, Volatility, WindowUDFImpl,
+/// # };
+/// #
+/// # use datafusion_functions_window::{create_udwf_expr, define_udwf_and_expr, get_or_init_udwf};
+/// # use datafusion_functions_window_common::field::WindowUDFFieldArgs;
+/// #
+/// # use datafusion_common::arrow::datatypes::Field;
+/// # use datafusion_common::ScalarValue;
+/// # use datafusion_expr::{col, lit};
+/// #
+/// /// 1. Defines the `lead_udwf()` user-defined window function.
+/// ///
+/// /// 2. Defines the expression API:
+/// /// ```
+/// /// pub fn lead(
+/// /// expr: datafusion_expr::Expr,
+/// /// offset: datafusion_expr::Expr,
+/// /// default: datafusion_expr::Expr,
+/// /// ) -> datafusion_expr::Expr {
+/// /// lead_udwf().call(vec![expr, offset, default])
+/// /// }
+/// /// ```
+/// define_udwf_and_expr!(
+/// Lead,
+/// lead,
+/// [expr, offset, default], // <- 3 parameters
+/// "user-defined window function",
+/// Lead::new // <- Custom constructor
+/// );
+/// #
+/// # assert_eq!(
+/// # lead(col("a"), lit(1i64), lit(ScalarValue::Null))
+/// # .name_for_alias()
+/// # .unwrap(),
+/// # "lead(a,Int64(1),NULL) ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING"
+/// # );
+/// #
+/// # #[derive(Debug)]
+/// # struct Lead {
+/// # signature: Signature,
+/// # }
+/// #
+/// # impl Lead {
+/// # fn new() -> Self {
+/// # Self {
+/// # signature: Signature::one_of(
+/// # vec![
+/// # TypeSignature::Any(1),
+/// # TypeSignature::Any(2),
+/// # TypeSignature::Any(3),
+/// # ],
+/// # Volatility::Immutable,
+/// # ),
+/// # }
+/// # }
+/// # }
+/// #
+/// # impl WindowUDFImpl for Lead {
+/// # fn as_any(&self) -> &dyn Any {
+/// # self
+/// # }
+/// # fn name(&self) -> &str {
+/// # "lead"
+/// # }
+/// # fn signature(&self) -> &Signature {
+/// # &self.signature
+/// # }
+/// # fn partition_evaluator(
+/// # &self,
+/// # ) -> datafusion_common::Result<Box<dyn PartitionEvaluator>> {
+/// # unimplemented!()
+/// # }
+/// # fn field(&self, field_args: WindowUDFFieldArgs) -> datafusion_common::Result<Field> {
+/// # Ok(Field::new(
+/// # field_args.name(),
+/// # field_args.get_input_type(0).unwrap(),
+/// # false,
+/// # ))
+/// # }
+/// # }
+/// ```
+#[macro_export]
+macro_rules! define_udwf_and_expr {
+ // Defines UDWF with default constructor
+ // Defines expression API with zero parameters
+ ($UDWF:ident, $OUT_FN_NAME:ident, $DOC:expr) => {
+ get_or_init_udwf!($UDWF, $OUT_FN_NAME, $DOC);
+ create_udwf_expr!($UDWF, $OUT_FN_NAME, $DOC);
+ };
+
+ // Defines UDWF by passing a custom constructor
+ // Defines expression API with zero parameters
+ ($UDWF:ident, $OUT_FN_NAME:ident, $DOC:expr, $CTOR:path) => {
+ get_or_init_udwf!($UDWF, $OUT_FN_NAME, $DOC, $CTOR);
+ create_udwf_expr!($UDWF, $OUT_FN_NAME, $DOC);
+ };
+
+ // Defines UDWF with default constructor
+ // Defines expression API with multiple parameters
+ ($UDWF:ident, $OUT_FN_NAME:ident, [$($PARAM:ident),+], $DOC:expr) => {
+ get_or_init_udwf!($UDWF, $OUT_FN_NAME, $DOC);
+ create_udwf_expr!($UDWF, $OUT_FN_NAME, [$($PARAM),+], $DOC);
+ };
+
+ // Defines UDWF by passing a custom constructor
+ // Defines expression API with multiple parameters
+ ($UDWF:ident, $OUT_FN_NAME:ident, [$($PARAM:ident),+], $DOC:expr, $CTOR:path) => {
+ get_or_init_udwf!($UDWF, $OUT_FN_NAME, $DOC, $CTOR);
+ create_udwf_expr!($UDWF, $OUT_FN_NAME, [$($PARAM),+], $DOC);
+ };
+}
diff --git a/datafusion/functions-window/src/row_number.rs b/datafusion/functions-window/src/row_number.rs
index 7f348bf9d2..a2e1b2222b 100644
--- a/datafusion/functions-window/src/row_number.rs
+++ b/datafusion/functions-window/src/row_number.rs
@@ -27,31 +27,15 @@ use datafusion_common::arrow::compute::SortOptions;
use datafusion_common::arrow::datatypes::DataType;
use datafusion_common::arrow::datatypes::Field;
use datafusion_common::{Result, ScalarValue};
-use datafusion_expr::expr::WindowFunction;
-use datafusion_expr::{Expr, PartitionEvaluator, Signature, Volatility, WindowUDFImpl};
+use datafusion_expr::{PartitionEvaluator, Signature, Volatility, WindowUDFImpl};
use datafusion_functions_window_common::field;
use field::WindowUDFFieldArgs;
-/// Create a [`WindowFunction`](Expr::WindowFunction) expression for
-/// `row_number` user-defined window function.
-pub fn row_number() -> Expr {
- Expr::WindowFunction(WindowFunction::new(row_number_udwf(), vec![]))
-}
-
-/// Singleton instance of `row_number`, ensures the UDWF is only created once.
-#[allow(non_upper_case_globals)]
-static STATIC_RowNumber: std::sync::OnceLock<std::sync::Arc<datafusion_expr::WindowUDF>> =
- std::sync::OnceLock::new();
-
-/// Returns a [`WindowUDF`](datafusion_expr::WindowUDF) for `row_number`
-/// user-defined window function.
-pub fn row_number_udwf() -> std::sync::Arc<datafusion_expr::WindowUDF> {
- STATIC_RowNumber
- .get_or_init(|| {
- std::sync::Arc::new(datafusion_expr::WindowUDF::from(RowNumber::default()))
- })
- .clone()
-}
+define_udwf_and_expr!(
+ RowNumber,
+ row_number,
+ "Returns a unique row number for each row in window partition beginning at 1."
+);
/// row_number expression
#[derive(Debug)]
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org