mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-25 19:04:26 +01:00
Merge pull request #238 from macroexpansion/feature/add-ltrim-scalar-function
This commit is contained in:
@@ -82,8 +82,8 @@ This document describes the SQLite compatibility status of Limbo:
|
||||
| load_extension(X) | No | |
|
||||
| load_extension(X,Y) | No | |
|
||||
| lower(X) | Yes | |
|
||||
| ltrim(X) | No | |
|
||||
| ltrim(X,Y) | No | |
|
||||
| ltrim(X) | Yes | |
|
||||
| ltrim(X,Y) | Yes | |
|
||||
| max(X,Y,...) | No | |
|
||||
| min(X,Y,...) | No | |
|
||||
| nullif(X,Y) | No | |
|
||||
|
||||
@@ -34,6 +34,7 @@ pub enum ScalarFunc {
|
||||
Lower,
|
||||
Random,
|
||||
Trim,
|
||||
LTrim,
|
||||
Round,
|
||||
Length,
|
||||
Min,
|
||||
@@ -52,6 +53,7 @@ impl ToString for ScalarFunc {
|
||||
ScalarFunc::Lower => "lower".to_string(),
|
||||
ScalarFunc::Random => "random".to_string(),
|
||||
ScalarFunc::Trim => "trim".to_string(),
|
||||
ScalarFunc::LTrim => "ltrim".to_string(),
|
||||
ScalarFunc::Round => "round".to_string(),
|
||||
ScalarFunc::Length => "length".to_string(),
|
||||
ScalarFunc::Min => "min".to_string(),
|
||||
@@ -88,6 +90,7 @@ impl Func {
|
||||
"lower" => Ok(Func::Scalar(ScalarFunc::Lower)),
|
||||
"random" => Ok(Func::Scalar(ScalarFunc::Random)),
|
||||
"trim" => Ok(Func::Scalar(ScalarFunc::Trim)),
|
||||
"ltrim" => Ok(Func::Scalar(ScalarFunc::LTrim)),
|
||||
"round" => Ok(Func::Scalar(ScalarFunc::Round)),
|
||||
"length" => Ok(Func::Scalar(ScalarFunc::Length)),
|
||||
"date" => Ok(Func::Scalar(ScalarFunc::Date)),
|
||||
|
||||
@@ -275,7 +275,7 @@ pub fn translate_expr(
|
||||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
ScalarFunc::Trim | ScalarFunc::Round => {
|
||||
ScalarFunc::Trim | ScalarFunc::LTrim | ScalarFunc::Round => {
|
||||
let args = if let Some(args) = args {
|
||||
if args.len() > 2 {
|
||||
crate::bail_parse_error!(
|
||||
|
||||
@@ -1115,6 +1115,16 @@ impl Program {
|
||||
state.registers[*dest] = result;
|
||||
state.pc += 1;
|
||||
}
|
||||
ScalarFunc::LTrim => {
|
||||
let start_reg = *start_reg;
|
||||
let reg_value = state.registers[start_reg].clone();
|
||||
let pattern_value = state.registers.get(start_reg + 1).cloned();
|
||||
|
||||
let result = exec_ltrim(®_value, pattern_value);
|
||||
|
||||
state.registers[*dest] = result;
|
||||
state.pc += 1;
|
||||
}
|
||||
ScalarFunc::Round => {
|
||||
let start_reg = *start_reg;
|
||||
let reg_value = state.registers[start_reg].clone();
|
||||
@@ -1350,6 +1360,25 @@ fn exec_trim(reg: &OwnedValue, pattern: Option<OwnedValue>) -> OwnedValue {
|
||||
}
|
||||
}
|
||||
|
||||
// Implements LTRIM pattern matching.
|
||||
fn exec_ltrim(reg: &OwnedValue, pattern: Option<OwnedValue>) -> OwnedValue {
|
||||
match (reg, pattern) {
|
||||
(reg, Some(pattern)) => match reg {
|
||||
OwnedValue::Text(_) | OwnedValue::Integer(_) | OwnedValue::Float(_) => {
|
||||
let pattern_chars: Vec<char> = pattern.to_string().chars().collect();
|
||||
OwnedValue::Text(Rc::new(
|
||||
reg.to_string()
|
||||
.trim_start_matches(&pattern_chars[..])
|
||||
.to_string(),
|
||||
))
|
||||
}
|
||||
_ => reg.to_owned(),
|
||||
},
|
||||
(OwnedValue::Text(t), None) => OwnedValue::Text(Rc::new(t.trim_start().to_string())),
|
||||
(reg, _) => reg.to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
// exec_if returns whether you should jump
|
||||
fn exec_if(reg: &OwnedValue, null_reg: &OwnedValue, not: bool) -> bool {
|
||||
match reg {
|
||||
@@ -1367,8 +1396,8 @@ fn exec_if(reg: &OwnedValue, null_reg: &OwnedValue, not: bool) -> bool {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
exec_abs, exec_if, exec_length, exec_like, exec_lower, exec_minmax, exec_random,
|
||||
exec_round, exec_trim, exec_unicode, exec_upper, OwnedValue,
|
||||
exec_abs, exec_if, exec_length, exec_like, exec_lower, exec_ltrim, exec_minmax,
|
||||
exec_random, exec_round, exec_trim, exec_unicode, exec_upper, OwnedValue,
|
||||
};
|
||||
use std::rc::Rc;
|
||||
|
||||
@@ -1477,6 +1506,18 @@ mod tests {
|
||||
assert_eq!(exec_trim(&input_str, Some(pattern_str)), expected_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ltrim() {
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from(" Bob and Alice ")));
|
||||
let expected_str = OwnedValue::Text(Rc::new(String::from("Bob and Alice ")));
|
||||
assert_eq!(exec_ltrim(&input_str, None), expected_str);
|
||||
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from(" Bob and Alice ")));
|
||||
let pattern_str = OwnedValue::Text(Rc::new(String::from("Bob and")));
|
||||
let expected_str = OwnedValue::Text(Rc::new(String::from("Alice ")));
|
||||
assert_eq!(exec_ltrim(&input_str, Some(pattern_str)), expected_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_upper_case() {
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("Limbo")));
|
||||
|
||||
@@ -87,6 +87,42 @@ do_execsql_test trim-no-match-pattern {
|
||||
SELECT trim('Limbo', 'xyz');
|
||||
} {Limbo}
|
||||
|
||||
do_execsql_test ltrim {
|
||||
SELECT ltrim(' Limbo ');
|
||||
} {"Limbo "}
|
||||
|
||||
do_execsql_test ltrim-number {
|
||||
SELECT ltrim(1);
|
||||
} {1}
|
||||
|
||||
do_execsql_test ltrim-null {
|
||||
SELECT ltrim(null);
|
||||
} {}
|
||||
|
||||
do_execsql_test ltrim-leading-whitespace {
|
||||
SELECT ltrim(' Leading');
|
||||
} {Leading}
|
||||
|
||||
do_execsql_test ltrim-no-leading-whitespace {
|
||||
SELECT ltrim('Limbo');
|
||||
} {Limbo}
|
||||
|
||||
do_execsql_test ltrim-pattern {
|
||||
SELECT ltrim('Limbo', 'Limbo');
|
||||
} {}
|
||||
|
||||
do_execsql_test ltrim-pattern-number {
|
||||
SELECT ltrim(1, '1');
|
||||
} {}
|
||||
|
||||
do_execsql_test ltrim-pattern-null {
|
||||
SELECT ltrim(null, 'null');
|
||||
} {}
|
||||
|
||||
do_execsql_test ltrim-no-match-pattern {
|
||||
SELECT ltrim('Limbo', 'xyz');
|
||||
} {Limbo}
|
||||
|
||||
do_execsql_test round-float-no-precision {
|
||||
SELECT round(123.456);
|
||||
} {123.0}
|
||||
|
||||
Reference in New Issue
Block a user