| Crates.io | athena-udf |
| lib.rs | athena-udf |
| version | 0.2.1 |
| created_at | 2025-12-04 17:13:48.565445+00 |
| updated_at | 2025-12-06 00:08:33.146451+00 |
| description | A crate for building AWS Athena User Defined Functions in Rust |
| homepage | https://github.com/matthias-Q/athena-udf |
| repository | https://github.com/matthias-Q/athena-udf |
| max_upload_size | |
| id | 1966726 |
| size | 115,248 |
A Rust crate for building AWS Athena User Defined Functions (UDFs) using AWS Lambda and Apache Arrow.
Add this to your Cargo.toml:
[dependencies]
athena-udf = "0.1.0"
lambda_runtime = "0.13"
tokio = { version = "1", features = ["macros"] }
serde_json = "1.0"
tracing-subscriber = "0.3"
We provide a simple macro to generate the Lambda function. Use
athena_udf_handler! and register the UDFs in there with the name and the
type.
use athena_udf::*;
use lambda_runtime::{service_fn, run, LambdaEvent, Error};
use serde_json::Value;
/// SQL: USING EXTERNAL FUNCTION string_reverse(input VARCHAR) RETURNS VARCHAR
pub fn string_reverse(value: String) -> String {
value.chars().rev().collect()
}
/// SQL: USING EXTERNAL FUNCTION add_numbers(a BIGINT, b BIGINT) RETURNS BIGINT
pub fn add_numbers(a: i64, b: i64) -> i64 {
a + b
}
athena_udf_handler! {
"string_reverse" => string_reverse: (String) -> String,
"add_numbers" => add_numbers: (i64, i64) -> i64,
}
#[tokio::main]
async fn main() -> Result<(), Error> {
tracing_subscriber::fmt()
.with_max_level(tracing_subscriber::filter::LevelFilter::INFO)
.init();
run(service_fn(function_handler)).await
}
The athena_udf_handler! macro generates the complete async fn function_handler for you. It:
process_* methodFor more control, you can use the lower-level register_udfs! macro or manually implement the handler.
Build for Lambda (Amazon Linux 2):
cargo lambda build --release --arm64
Deploy:
cargo lambda deploy
USING EXTERNAL FUNCTION string_reverse(input VARCHAR) RETURNS VARCHAR
LAMBDA 'your-lambda-function-name'
SELECT string_reverse('hello-athena') as reversed;
-- Result: 'anehta-olleh'
Uses the athena_udf_handler! macro for minimal boilerplate:
Option<T>Manual implementation without macros for full control:
Both examples demonstrate the same functionality - choose based on your needs for control vs. simplicity.
The crate supports automatic conversion between Athena SQL types and Rust types:
| Athena SQL Type | Rust Type |
|---|---|
| VARCHAR | String |
| BIGINT | i64 |
| INTEGER | i32 |
| DOUBLE | f64 |
| BOOLEAN | bool |
| VARBINARY | Vec |
The crate provides two ways to handle null values:
When you use unwrapped types like String or i64, nulls are automatically handled:
pub fn string_reverse(value: String) -> String {
value.chars().rev().collect()
// Never receives null, never needs to handle it
}
Use Option<T> to explicitly handle nulls:
pub fn string_reverse_nullable(value: String) -> Option<String> {
if value.length() > 3 {
Some(value)
} else {
None
}
}
This project was develop while working at Unite .
Licensed under MIT license (LICENSE-MIT http://opensource.org/licenses/MIT)