mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-01 23:44:19 +01:00
Merge 'Add typeof(X) scalar function' from Lauri Virtanen
See SQLite documentation: https://www.sqlite.org/lang_corefunc.html#typeof Relates to issue #144 Scalar function support Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com> Closes #310
This commit is contained in:
@@ -111,7 +111,7 @@ This document describes the SQLite compatibility status of Limbo:
|
||||
| total_changes() | No | |
|
||||
| trim(X) | Yes | |
|
||||
| trim(X,Y) | Yes | |
|
||||
| typeof(X) | No | |
|
||||
| typeof(X) | Yes | |
|
||||
| unhex(X) | No | |
|
||||
| unhex(X,Y) | No | |
|
||||
| unicode(X) | Yes | |
|
||||
|
||||
@@ -71,6 +71,7 @@ pub enum ScalarFunc {
|
||||
Substring,
|
||||
Date,
|
||||
Time,
|
||||
Typeof,
|
||||
Unicode,
|
||||
Quote,
|
||||
SqliteVersion,
|
||||
@@ -104,6 +105,7 @@ impl Display for ScalarFunc {
|
||||
ScalarFunc::Substring => "substring".to_string(),
|
||||
ScalarFunc::Date => "date".to_string(),
|
||||
ScalarFunc::Time => "time".to_string(),
|
||||
ScalarFunc::Typeof => "typeof".to_string(),
|
||||
ScalarFunc::Unicode => "unicode".to_string(),
|
||||
ScalarFunc::Quote => "quote".to_string(),
|
||||
ScalarFunc::SqliteVersion => "sqlite_version".to_string(),
|
||||
@@ -171,6 +173,7 @@ impl Func {
|
||||
"substring" => Ok(Func::Scalar(ScalarFunc::Substring)),
|
||||
"date" => Ok(Func::Scalar(ScalarFunc::Date)),
|
||||
"time" => Ok(Func::Scalar(ScalarFunc::Time)),
|
||||
"typeof" => Ok(Func::Scalar(ScalarFunc::Typeof)),
|
||||
"unicode" => Ok(Func::Scalar(ScalarFunc::Unicode)),
|
||||
"quote" => Ok(Func::Scalar(ScalarFunc::Quote)),
|
||||
"sqlite_version" => Ok(Func::Scalar(ScalarFunc::SqliteVersion)),
|
||||
|
||||
@@ -1003,6 +1003,7 @@ pub fn translate_expr(
|
||||
| ScalarFunc::Lower
|
||||
| ScalarFunc::Upper
|
||||
| ScalarFunc::Length
|
||||
| ScalarFunc::Typeof
|
||||
| ScalarFunc::Unicode
|
||||
| ScalarFunc::Quote
|
||||
| ScalarFunc::Sign => {
|
||||
|
||||
@@ -1518,6 +1518,7 @@ impl Program {
|
||||
| ScalarFunc::Lower
|
||||
| ScalarFunc::Upper
|
||||
| ScalarFunc::Length
|
||||
| ScalarFunc::Typeof
|
||||
| ScalarFunc::Unicode
|
||||
| ScalarFunc::Quote
|
||||
| ScalarFunc::Sign => {
|
||||
@@ -1528,6 +1529,7 @@ impl Program {
|
||||
ScalarFunc::Lower => exec_lower(reg_value),
|
||||
ScalarFunc::Upper => exec_upper(reg_value),
|
||||
ScalarFunc::Length => Some(exec_length(reg_value)),
|
||||
ScalarFunc::Typeof => Some(exec_typeof(reg_value)),
|
||||
ScalarFunc::Unicode => Some(exec_unicode(reg_value)),
|
||||
ScalarFunc::Quote => Some(exec_quote(reg_value)),
|
||||
_ => unreachable!(),
|
||||
@@ -2132,6 +2134,18 @@ fn exec_substring(
|
||||
}
|
||||
}
|
||||
|
||||
fn exec_typeof(reg: &OwnedValue) -> OwnedValue {
|
||||
match reg {
|
||||
OwnedValue::Null => OwnedValue::Text(Rc::new("null".to_string())),
|
||||
OwnedValue::Integer(_) => OwnedValue::Text(Rc::new("integer".to_string())),
|
||||
OwnedValue::Float(_) => OwnedValue::Text(Rc::new("real".to_string())),
|
||||
OwnedValue::Text(_) => OwnedValue::Text(Rc::new("text".to_string())),
|
||||
OwnedValue::Blob(_) => OwnedValue::Text(Rc::new("blob".to_string())),
|
||||
OwnedValue::Agg(ctx) => exec_typeof(ctx.final_value()),
|
||||
OwnedValue::Record(_) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn exec_unicode(reg: &OwnedValue) -> OwnedValue {
|
||||
match reg {
|
||||
OwnedValue::Text(_)
|
||||
@@ -2249,11 +2263,12 @@ fn execute_sqlite_version(version_integer: i64) -> String {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::{
|
||||
exec_abs, exec_char, exec_if, exec_length, exec_like, exec_lower, exec_ltrim, exec_minmax,
|
||||
exec_nullif, exec_quote, exec_random, exec_round, exec_rtrim, exec_sign, exec_substring,
|
||||
exec_trim, exec_unicode, exec_upper, execute_sqlite_version, get_new_rowid, Cursor,
|
||||
CursorResult, LimboError, OwnedRecord, OwnedValue, Result,
|
||||
exec_trim, exec_typeof, exec_unicode, exec_upper, execute_sqlite_version, get_new_rowid,
|
||||
AggContext, Cursor, CursorResult, LimboError, OwnedRecord, OwnedValue, Result,
|
||||
};
|
||||
use mockall::{mock, predicate};
|
||||
use rand::{rngs::mock::StepRng, thread_rng};
|
||||
@@ -2431,6 +2446,33 @@ mod tests {
|
||||
assert_eq!(exec_quote(&input), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_typeof() {
|
||||
let input = OwnedValue::Null;
|
||||
let expected: OwnedValue = OwnedValue::Text(Rc::new("null".to_string()));
|
||||
assert_eq!(exec_typeof(&input), expected);
|
||||
|
||||
let input = OwnedValue::Integer(123);
|
||||
let expected: OwnedValue = OwnedValue::Text(Rc::new("integer".to_string()));
|
||||
assert_eq!(exec_typeof(&input), expected);
|
||||
|
||||
let input = OwnedValue::Float(123.456);
|
||||
let expected: OwnedValue = OwnedValue::Text(Rc::new("real".to_string()));
|
||||
assert_eq!(exec_typeof(&input), expected);
|
||||
|
||||
let input = OwnedValue::Text(Rc::new("hello".to_string()));
|
||||
let expected: OwnedValue = OwnedValue::Text(Rc::new("text".to_string()));
|
||||
assert_eq!(exec_typeof(&input), expected);
|
||||
|
||||
let input = OwnedValue::Blob(Rc::new("limbo".as_bytes().to_vec()));
|
||||
let expected: OwnedValue = OwnedValue::Text(Rc::new("blob".to_string()));
|
||||
assert_eq!(exec_typeof(&input), expected);
|
||||
|
||||
let input = OwnedValue::Agg(Box::new(AggContext::Sum(OwnedValue::Integer(123))));
|
||||
let expected = OwnedValue::Text(Rc::new("integer".to_string()));
|
||||
assert_eq!(exec_typeof(&input), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unicode() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -347,6 +347,51 @@ do_execsql_test substring-2-args-exceed-length {
|
||||
SELECT substring('limbo', 10);
|
||||
} {}
|
||||
|
||||
do_execsql_test typeof-null {
|
||||
SELECT typeof(null);
|
||||
} {null}
|
||||
|
||||
do_execsql_test typeof-null-case {
|
||||
SELECT typeof(nuLL);
|
||||
} {null}
|
||||
|
||||
do_execsql_test typeof-text {
|
||||
SELECT typeof('hello');
|
||||
} {text}
|
||||
|
||||
do_execsql_test typeof-text-empty {
|
||||
SELECT typeof('');
|
||||
} {text}
|
||||
|
||||
do_execsql_test typeof-integer {
|
||||
SELECT typeof(123);
|
||||
} {integer}
|
||||
|
||||
do_execsql_test typeof-real {
|
||||
SELECT typeof(1.0);
|
||||
} {real}
|
||||
|
||||
# TODO: Uncomment when blobs are better supported
|
||||
# do_execsql_test typeof-blob {
|
||||
# SELECT typeof(x'61');
|
||||
# } {blob}
|
||||
#
|
||||
# do_execsql_test typeof-blob-empty {
|
||||
# SELECT typeof(x'');
|
||||
# } {blob}
|
||||
|
||||
do_execsql_test typeof-sum-integer {
|
||||
SELECT typeof(sum(age)) from users;
|
||||
} {integer}
|
||||
|
||||
do_execsql_test typeof-sum-real {
|
||||
SELECT typeof(sum(price)) from products;
|
||||
} {real}
|
||||
|
||||
do_execsql_test typeof-group_concat {
|
||||
SELECT typeof(group_concat(name)) from products;
|
||||
} {text}
|
||||
|
||||
do_execsql_test unicode-a {
|
||||
SELECT unicode('a');
|
||||
} {97}
|
||||
|
||||
Reference in New Issue
Block a user