use crate::ctx::Context; use crate::err::Error; use crate::fnc::util::string; use crate::sql::value::Value; pub fn concat(_: &Context, args: Vec) -> Result { Ok(args.into_iter().map(|x| x.as_string()).collect::>().concat().into()) } pub fn ends_with(_: &Context, args: Vec) -> Result { let args: [Value; 2] = args.try_into().unwrap(); let [val, chr] = args.map(Value::as_string); Ok(val.ends_with(&chr).into()) } pub fn join(_: &Context, args: Vec) -> Result { let mut args = args.into_iter().map(Value::as_string); let chr = args.next().unwrap(); // FIXME: Use intersperse to avoid intermediate allocation once stable // https://github.com/rust-lang/rust/issues/79524 let val = args.collect::>().join(&chr); Ok(val.into()) } pub fn length(_: &Context, mut args: Vec) -> Result { let val = args.remove(0).as_string(); let num = val.chars().count() as i64; Ok(num.into()) } pub fn lowercase(_: &Context, mut args: Vec) -> Result { Ok(args.remove(0).as_string().to_lowercase().into()) } pub fn repeat(_: &Context, args: Vec) -> Result { let [val_arg, num_arg]: [Value; 2] = args.try_into().unwrap(); let val = val_arg.as_string(); let num = num_arg.as_int() as usize; const LIMIT: usize = 2usize.pow(20); if val.len().saturating_mul(num) > LIMIT { Err(Error::InvalidArguments { name: String::from("string::repeat"), message: format!("Output must not exceed {} bytes.", LIMIT), }) } else { Ok(val.repeat(num).into()) } } pub fn replace(_: &Context, args: Vec) -> Result { let args: [Value; 3] = args.try_into().unwrap(); let [val, old, new] = args.map(Value::as_string); Ok(val.replace(&old, &new).into()) } pub fn reverse(_: &Context, mut args: Vec) -> Result { Ok(args.remove(0).as_string().chars().rev().collect::().into()) } pub fn slice(_: &Context, args: Vec) -> Result { let [val_arg, beg_arg, lim_arg]: [Value; 3] = args.try_into().unwrap(); let val = val_arg.as_string(); let beg = beg_arg.as_int() as usize; let lim = lim_arg.as_int() as usize; let val = val.chars().skip(beg).take(lim).collect::(); Ok(val.into()) } pub fn slug(_: &Context, mut args: Vec) -> Result { Ok(string::slug(&args.remove(0).as_string()).into()) } pub fn split(_: &Context, args: Vec) -> Result { let args: [Value; 2] = args.try_into().unwrap(); let [val, chr] = args.map(Value::as_string); let val = val.split(&chr).collect::>(); Ok(val.into()) } pub fn starts_with(_: &Context, args: Vec) -> Result { let args: [Value; 2] = args.try_into().unwrap(); let [val, chr] = args.map(Value::as_string); Ok(val.starts_with(&chr).into()) } pub fn trim(_: &Context, mut args: Vec) -> Result { Ok(args.remove(0).as_string().trim().into()) } pub fn uppercase(_: &Context, mut args: Vec) -> Result { Ok(args.remove(0).as_string().to_uppercase().into()) } pub fn words(_: &Context, mut args: Vec) -> Result { Ok(args.remove(0).as_string().split_whitespace().collect::>().into()) }