mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-07-07 20:45:01 +00:00
Add documentation to core/ext and relevant macros
This commit is contained in:
parent
9c47379927
commit
bcd3ae2bd7
3 changed files with 98 additions and 4 deletions
|
@ -48,7 +48,7 @@ use limbo_ext::{register_extension, Value, scalar};
|
|||
|
||||
/// Annotate each with the scalar macro, specifying the name you would like to call it with
|
||||
/// and optionally, an alias.. e.g. SELECT double(4); or SELECT twice(4);
|
||||
# [scalar(name = "double", alias = "twice")]
|
||||
#[scalar(name = "double", alias = "twice")]
|
||||
fn double(&self, args: &[Value]) -> Value {
|
||||
if let Some(arg) = args.first() {
|
||||
match arg.value_type() {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use std::{fmt::Display, os::raw::c_void};
|
||||
|
||||
/// Error type is of type ExtError which can be
|
||||
/// either a user defined error or an error code
|
||||
#[repr(C)]
|
||||
pub enum ResultCode {
|
||||
OK = 0,
|
||||
|
@ -150,6 +152,7 @@ impl Blob {
|
|||
}
|
||||
|
||||
impl Value {
|
||||
/// Creates a new Value with type Null
|
||||
pub fn null() -> Self {
|
||||
Self {
|
||||
value_type: ValueType::Null,
|
||||
|
@ -157,10 +160,12 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the value type of the Value
|
||||
pub fn value_type(&self) -> ValueType {
|
||||
self.value_type
|
||||
}
|
||||
|
||||
/// Returns the float value if the Value is the proper type
|
||||
pub fn to_float(&self) -> Option<f64> {
|
||||
if self.value.is_null() {
|
||||
return None;
|
||||
|
@ -175,7 +180,7 @@ impl Value {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the text value if the Value is the proper type
|
||||
pub fn to_text(&self) -> Option<String> {
|
||||
if self.value_type != ValueType::Text {
|
||||
return None;
|
||||
|
@ -187,6 +192,7 @@ impl Value {
|
|||
Some(String::from(txt.as_str()))
|
||||
}
|
||||
|
||||
/// Returns the blob value if the Value is the proper type
|
||||
pub fn to_blob(&self) -> Option<Vec<u8>> {
|
||||
if self.value_type != ValueType::Blob {
|
||||
return None;
|
||||
|
@ -199,6 +205,7 @@ impl Value {
|
|||
Some(slice.to_vec())
|
||||
}
|
||||
|
||||
/// Returns the integer value if the Value is the proper type
|
||||
pub fn to_integer(&self) -> Option<i64> {
|
||||
if self.value.is_null() {
|
||||
return None;
|
||||
|
@ -214,6 +221,7 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the error message if the value is an error
|
||||
pub fn to_error(&self) -> Option<String> {
|
||||
if self.value_type != ValueType::Error {
|
||||
return None;
|
||||
|
@ -234,6 +242,7 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new integer Value from an i64
|
||||
pub fn from_integer(value: i64) -> Self {
|
||||
let boxed = Box::new(value);
|
||||
Self {
|
||||
|
@ -242,6 +251,7 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new float Value from an f64
|
||||
pub fn from_float(value: f64) -> Self {
|
||||
let boxed = Box::new(value);
|
||||
Self {
|
||||
|
@ -249,7 +259,7 @@ impl Value {
|
|||
value: Box::into_raw(boxed) as *mut c_void,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new text Value from a String
|
||||
pub fn from_text(s: String) -> Self {
|
||||
let buffer = s.into_boxed_str();
|
||||
let ptr = buffer.as_ptr();
|
||||
|
@ -263,6 +273,7 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new error Value from a ResultCode
|
||||
pub fn error(err: ResultCode) -> Self {
|
||||
let error = ExtError {
|
||||
error_type: ErrorType::ErrCode { code: err },
|
||||
|
@ -274,6 +285,7 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a new user defined error Value with a message
|
||||
pub fn custom_error(s: String) -> Self {
|
||||
let buffer = s.into_boxed_str();
|
||||
let ptr = buffer.as_ptr();
|
||||
|
@ -291,6 +303,7 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new blob Value from a Vec<u8>
|
||||
pub fn from_blob(value: Vec<u8>) -> Self {
|
||||
let boxed = Box::new(Blob::new(value.as_ptr(), value.len() as u64));
|
||||
std::mem::forget(value);
|
||||
|
@ -338,5 +351,8 @@ pub struct ExtError {
|
|||
#[repr(C)]
|
||||
pub enum ErrorType {
|
||||
User,
|
||||
ErrCode { code: ResultCode },
|
||||
/// User type has a user provided message
|
||||
ErrCode {
|
||||
code: ResultCode,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -138,6 +138,29 @@ fn generate_get_description(
|
|||
enum_impl.parse().unwrap()
|
||||
}
|
||||
|
||||
/// Declare a scalar function for your extension. This requires the name:
|
||||
/// #[scalar(name = "example")] of what you wish to call your function with.
|
||||
/// Your function __must__ use the signature: `fn (args: &[Value]) -> Value`
|
||||
/// with proper spelling.
|
||||
/// ```ignore
|
||||
/// use limbo_ext::{scalar, Value};
|
||||
/// #[scalar(name = "double", alias = "twice")] // you can provide an <optional> alias
|
||||
/// fn double(args: &[Value]) -> Value {
|
||||
/// match arg.value_type() {
|
||||
/// ValueType::Float => {
|
||||
/// let val = arg.to_float().unwrap();
|
||||
/// Value::from_float(val * 2.0)
|
||||
/// }
|
||||
/// ValueType::Integer => {
|
||||
/// let val = arg.to_integer().unwrap();
|
||||
/// Value::from_integer(val * 2)
|
||||
/// }
|
||||
/// }
|
||||
/// } else {
|
||||
/// Value::null()
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn scalar(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let ast = parse_macro_input!(input as ItemFn);
|
||||
|
@ -199,6 +222,29 @@ pub fn scalar(attr: TokenStream, input: TokenStream) -> TokenStream {
|
|||
TokenStream::from(expanded)
|
||||
}
|
||||
|
||||
/// Define an aggregate function for your extension by deriving
|
||||
/// AggregateDerive on a struct that implements the AggFunc trait.
|
||||
/// ```ignore
|
||||
/// use limbo_ext::{register_extension, Value, AggregateDerive, AggFunc};
|
||||
///
|
||||
///#[derive(AggregateDerive)]
|
||||
///struct SumPlusOne;
|
||||
///
|
||||
///impl AggFunc for SumPlusOne {
|
||||
/// type State = i64;
|
||||
/// const NAME: &'static str = "sum_plus_one";
|
||||
/// const ARGS: i32 = 1;
|
||||
/// fn step(state: &mut Self::State, args: &[Value]) {
|
||||
/// let Some(val) = args[0].to_integer() else {
|
||||
/// return;
|
||||
/// };
|
||||
/// *state += val;
|
||||
/// }
|
||||
/// fn finalize(state: Self::State) -> Value {
|
||||
/// Value::from_integer(state + 1)
|
||||
/// }
|
||||
///}
|
||||
/// ```
|
||||
#[proc_macro_derive(AggregateDerive)]
|
||||
pub fn derive_agg_func(input: TokenStream) -> TokenStream {
|
||||
let ast = parse_macro_input!(input as DeriveInput);
|
||||
|
@ -278,6 +324,38 @@ pub fn derive_agg_func(input: TokenStream) -> TokenStream {
|
|||
TokenStream::from(expanded)
|
||||
}
|
||||
|
||||
/// Register your extension with 'core' by providing the relevant functions
|
||||
///```ignore
|
||||
///use limbo_ext::{register_extension, scalar, Value, AggregateDerive, AggFunc};
|
||||
///
|
||||
/// register_extension!{ scalars: { return_one }, aggregates: { SumPlusOne } }
|
||||
///
|
||||
///#[scalar(name = "one")]
|
||||
///fn return_one(args: &[Value]) -> Value {
|
||||
/// return Value::from_integer(1);
|
||||
///}
|
||||
///
|
||||
///#[derive(AggregateDerive)]
|
||||
///struct SumPlusOne;
|
||||
///
|
||||
///impl AggFunc for SumPlusOne {
|
||||
/// type State = i64;
|
||||
/// const NAME: &'static str = "sum_plus_one";
|
||||
/// const ARGS: i32 = 1;
|
||||
///
|
||||
/// fn step(state: &mut Self::State, args: &[Value]) {
|
||||
/// let Some(val) = args[0].to_integer() else {
|
||||
/// return;
|
||||
/// };
|
||||
/// *state += val;
|
||||
/// }
|
||||
///
|
||||
/// fn finalize(state: Self::State) -> Value {
|
||||
/// Value::from_integer(state + 1)
|
||||
/// }
|
||||
///}
|
||||
///
|
||||
/// ```
|
||||
#[proc_macro]
|
||||
pub fn register_extension(input: TokenStream) -> TokenStream {
|
||||
let input_ast = parse_macro_input!(input as RegisterExtensionInput);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue