mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-06 00:34:23 +01:00
feat: add trim scalar function
This commit is contained in:
@@ -109,8 +109,8 @@ This document describes the SQLite compatibility status of Limbo:
|
||||
| substring(X,Y,Z) | No | |
|
||||
| substring(X,Y) | No | |
|
||||
| total_changes() | No | |
|
||||
| trim(X) | No | |
|
||||
| trim(X,Y) | No | |
|
||||
| trim(X) | Yes | |
|
||||
| trim(X,Y) | Yes | |
|
||||
| typeof(X) | No | |
|
||||
| unhex(X) | No | |
|
||||
| unhex(X,Y) | No | |
|
||||
|
||||
36
core/expr.rs
36
core/expr.rs
@@ -366,7 +366,43 @@ pub fn translate_expr(
|
||||
dest: target_register,
|
||||
func: SingleRowFunc::Random,
|
||||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
SingleRowFunc::Trim => {
|
||||
let args = if let Some(args) = args {
|
||||
if args.len() > 2 {
|
||||
anyhow::bail!(
|
||||
"Parse error: trim function with more than 2 arguments"
|
||||
);
|
||||
}
|
||||
args
|
||||
} else {
|
||||
anyhow::bail!("Parse error: trim function with no arguments");
|
||||
};
|
||||
|
||||
if args.len() == 1 {
|
||||
let regs = program.alloc_register();
|
||||
let _ = translate_expr(program, select, &args[0], regs)?;
|
||||
program.emit_insn(Insn::Function {
|
||||
start_reg: regs,
|
||||
dest: target_register,
|
||||
func: SingleRowFunc::Trim,
|
||||
});
|
||||
} else {
|
||||
for arg in args {
|
||||
let reg = program.alloc_register();
|
||||
let _ = translate_expr(program, select, arg, reg)?;
|
||||
match arg {
|
||||
ast::Expr::Literal(_) => program.mark_last_insn_constant(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
program.emit_insn(Insn::Function {
|
||||
start_reg: target_register + 1,
|
||||
dest: target_register,
|
||||
func: SingleRowFunc::Trim,
|
||||
});
|
||||
}
|
||||
Ok(target_register)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ pub enum SingleRowFunc {
|
||||
Upper,
|
||||
Lower,
|
||||
Random,
|
||||
Trim,
|
||||
}
|
||||
|
||||
impl ToString for SingleRowFunc {
|
||||
@@ -46,6 +47,7 @@ impl ToString for SingleRowFunc {
|
||||
SingleRowFunc::Upper => "upper".to_string(),
|
||||
SingleRowFunc::Lower => "lower".to_string(),
|
||||
SingleRowFunc::Random => "random".to_string(),
|
||||
SingleRowFunc::Trim => "trim".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,6 +76,7 @@ impl FromStr for Func {
|
||||
"upper" => Ok(Func::SingleRow(SingleRowFunc::Upper)),
|
||||
"lower" => Ok(Func::SingleRow(SingleRowFunc::Lower)),
|
||||
"random" => Ok(Func::SingleRow(SingleRowFunc::Random)),
|
||||
"trim" => Ok(Func::SingleRow(SingleRowFunc::Trim)),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
43
core/vdbe.rs
43
core/vdbe.rs
@@ -1293,6 +1293,16 @@ impl Program {
|
||||
state.registers[*dest] = exec_random();
|
||||
state.pc += 1;
|
||||
}
|
||||
SingleRowFunc::Trim => {
|
||||
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_trim(®_value, pattern_value);
|
||||
|
||||
state.registers[*dest] = result;
|
||||
state.pc += 1;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1878,6 +1888,23 @@ fn exec_like(pattern: &str, text: &str) -> bool {
|
||||
re.is_match(text)
|
||||
}
|
||||
|
||||
// Implements TRIM pattern matching.
|
||||
fn exec_trim(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_matches(&pattern_chars[..]).to_string(),
|
||||
))
|
||||
}
|
||||
_ => reg.to_owned(),
|
||||
},
|
||||
(OwnedValue::Text(t), None) => OwnedValue::Text(Rc::new(t.trim().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 {
|
||||
@@ -1894,9 +1921,23 @@ fn exec_if(reg: &OwnedValue, null_reg: &OwnedValue, not: bool) -> bool {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{exec_abs, exec_if, exec_like, exec_lower, exec_random, exec_upper, OwnedValue};
|
||||
use super::{
|
||||
exec_abs, exec_if, exec_like, exec_lower, exec_random, exec_trim, exec_upper, OwnedValue,
|
||||
};
|
||||
use std::rc::Rc;
|
||||
|
||||
#[test]
|
||||
fn test_trim() {
|
||||
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_trim(&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_trim(&input_str, Some(pattern_str)), expected_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_upper_case() {
|
||||
let input_str = OwnedValue::Text(Rc::new(String::from("Limbo")));
|
||||
|
||||
@@ -50,3 +50,39 @@ do_execsql_test lower-char {
|
||||
do_execsql_test lower-null {
|
||||
select lower(null)
|
||||
} {}
|
||||
|
||||
do_execsql_test trim {
|
||||
SELECT trim(' Limbo ');
|
||||
} {Limbo}
|
||||
|
||||
do_execsql_test trim-number {
|
||||
SELECT trim(1);
|
||||
} {1}
|
||||
|
||||
do_execsql_test trim-null {
|
||||
SELECT trim(null);
|
||||
} {}
|
||||
|
||||
do_execsql_test trim-leading-whitespace {
|
||||
SELECT trim(' Leading');
|
||||
} {Leading}
|
||||
|
||||
do_execsql_test trim-trailing-whitespace {
|
||||
SELECT trim('Trailing ');
|
||||
} {Trailing}
|
||||
|
||||
do_execsql_test trim-pattern {
|
||||
SELECT trim('Limbo', 'Limbo');
|
||||
} {}
|
||||
|
||||
do_execsql_test trim-pattern-number {
|
||||
SELECT trim(1, '1');
|
||||
} {}
|
||||
|
||||
do_execsql_test trim-pattern-null {
|
||||
SELECT trim(null, 'null');
|
||||
} {}
|
||||
|
||||
do_execsql_test trim-no-match-pattern {
|
||||
SELECT trim('Limbo', 'xyz');
|
||||
} {Limbo}
|
||||
Reference in New Issue
Block a user