mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-19 01:24:20 +01:00
feat: add timediff data and time function
This commit is contained in:
@@ -293,6 +293,7 @@ pub enum ScalarFunc {
|
||||
StrfTime,
|
||||
Printf,
|
||||
Likely,
|
||||
TimeDiff,
|
||||
}
|
||||
|
||||
impl Display for ScalarFunc {
|
||||
@@ -348,6 +349,7 @@ impl Display for ScalarFunc {
|
||||
Self::StrfTime => "strftime".to_string(),
|
||||
Self::Printf => "printf".to_string(),
|
||||
Self::Likely => "likely".to_string(),
|
||||
Self::TimeDiff => "timediff".to_string(),
|
||||
};
|
||||
write!(f, "{}", str)
|
||||
}
|
||||
@@ -555,6 +557,12 @@ impl Func {
|
||||
}
|
||||
Ok(Self::Agg(AggFunc::Total))
|
||||
}
|
||||
"timediff" => {
|
||||
if arg_count != 2 {
|
||||
crate::bail_parse_error!("wrong number of arguments to function {}()", name)
|
||||
}
|
||||
Ok(Self::Scalar(ScalarFunc::TimeDiff))
|
||||
}
|
||||
#[cfg(feature = "json")]
|
||||
"jsonb_group_array" => Ok(Self::Agg(AggFunc::JsonbGroupArray)),
|
||||
#[cfg(feature = "json")]
|
||||
|
||||
@@ -656,6 +656,61 @@ fn parse_modifier(modifier: &str) -> Result<Modifier> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exec_timediff(values: &[Register]) -> OwnedValue {
|
||||
if values.len() < 2 {
|
||||
return OwnedValue::Null;
|
||||
}
|
||||
|
||||
let start = parse_naive_date_time(values[0].get_owned_value());
|
||||
let end = parse_naive_date_time(values[1].get_owned_value());
|
||||
|
||||
match (start, end) {
|
||||
(Some(start), Some(end)) => {
|
||||
let duration = start.signed_duration_since(end);
|
||||
format_time_duration(&duration)
|
||||
}
|
||||
_ => OwnedValue::Null,
|
||||
}
|
||||
}
|
||||
|
||||
fn format_time_duration(duration: &chrono::Duration) -> OwnedValue {
|
||||
let is_negative = duration.num_seconds() < 0;
|
||||
|
||||
let abs_duration = if is_negative {
|
||||
-duration.clone()
|
||||
} else {
|
||||
duration.clone()
|
||||
};
|
||||
let total_seconds = abs_duration.num_seconds();
|
||||
let hours = total_seconds / 3600;
|
||||
let minutes = (total_seconds % 3600) / 60;
|
||||
let seconds = total_seconds % 60;
|
||||
|
||||
let total_millis = abs_duration.num_milliseconds();
|
||||
let millis = total_millis % 1000;
|
||||
|
||||
let result = if millis > 0 {
|
||||
format!(
|
||||
"{}{:02}:{:02}:{:02}.{:03}",
|
||||
if is_negative { "-" } else { "" },
|
||||
hours,
|
||||
minutes,
|
||||
seconds,
|
||||
millis
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"{}{:02}:{:02}:{:02}",
|
||||
if is_negative { "-" } else { "" },
|
||||
hours,
|
||||
minutes,
|
||||
seconds
|
||||
)
|
||||
};
|
||||
|
||||
OwnedValue::build_text(&result)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -1642,4 +1697,67 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_strftime() {}
|
||||
|
||||
#[test]
|
||||
fn test_exec_timediff() {
|
||||
let start = OwnedValue::build_text("12:00:00");
|
||||
let end = OwnedValue::build_text("14:30:45");
|
||||
let expected = OwnedValue::build_text("-02:30:45");
|
||||
assert_eq!(
|
||||
exec_timediff(&[Register::OwnedValue(start), Register::OwnedValue(end)]),
|
||||
expected
|
||||
);
|
||||
|
||||
let start = OwnedValue::build_text("14:30:45");
|
||||
let end = OwnedValue::build_text("12:00:00");
|
||||
let expected = OwnedValue::build_text("02:30:45");
|
||||
assert_eq!(
|
||||
exec_timediff(&[Register::OwnedValue(start), Register::OwnedValue(end)]),
|
||||
expected
|
||||
);
|
||||
|
||||
let start = OwnedValue::build_text("12:00:01.300");
|
||||
let end = OwnedValue::build_text("12:00:00.500");
|
||||
let expected = OwnedValue::build_text("00:00:00.800");
|
||||
assert_eq!(
|
||||
exec_timediff(&[Register::OwnedValue(start), Register::OwnedValue(end)]),
|
||||
expected
|
||||
);
|
||||
|
||||
let start = OwnedValue::build_text("13:30:00");
|
||||
let end = OwnedValue::build_text("16:45:30");
|
||||
let expected = OwnedValue::build_text("-03:15:30");
|
||||
assert_eq!(
|
||||
exec_timediff(&[Register::OwnedValue(start), Register::OwnedValue(end)]),
|
||||
expected
|
||||
);
|
||||
|
||||
let start = OwnedValue::build_text("2023-05-10 23:30:00");
|
||||
let end = OwnedValue::build_text("2023-05-11 01:15:00");
|
||||
let expected = OwnedValue::build_text("-01:45:00");
|
||||
assert_eq!(
|
||||
exec_timediff(&[Register::OwnedValue(start), Register::OwnedValue(end)]),
|
||||
expected
|
||||
);
|
||||
|
||||
let start = OwnedValue::Null;
|
||||
let end = OwnedValue::build_text("12:00:00");
|
||||
let expected = OwnedValue::Null;
|
||||
assert_eq!(
|
||||
exec_timediff(&[Register::OwnedValue(start), Register::OwnedValue(end)]),
|
||||
expected
|
||||
);
|
||||
|
||||
let start = OwnedValue::build_text("not a time");
|
||||
let end = OwnedValue::build_text("12:00:00");
|
||||
let expected = OwnedValue::Null;
|
||||
assert_eq!(
|
||||
exec_timediff(&[Register::OwnedValue(start), Register::OwnedValue(end)]),
|
||||
expected
|
||||
);
|
||||
|
||||
let start = OwnedValue::build_text("12:00:00");
|
||||
let expected = OwnedValue::Null;
|
||||
assert_eq!(exec_timediff(&[Register::OwnedValue(start)]), expected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1309,6 +1309,33 @@ pub fn translate_expr(
|
||||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
ScalarFunc::TimeDiff => {
|
||||
let args = expect_arguments_exact!(args, 2, srf);
|
||||
|
||||
let start_reg = program.alloc_registers(2);
|
||||
translate_expr(
|
||||
program,
|
||||
referenced_tables,
|
||||
&args[0],
|
||||
start_reg,
|
||||
resolver,
|
||||
)?;
|
||||
translate_expr(
|
||||
program,
|
||||
referenced_tables,
|
||||
&args[1],
|
||||
start_reg + 1,
|
||||
resolver,
|
||||
)?;
|
||||
|
||||
program.emit_insn(Insn::Function {
|
||||
constant_mask: 0,
|
||||
start_reg,
|
||||
dest: target_register,
|
||||
func: func_ctx,
|
||||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
ScalarFunc::TotalChanges => {
|
||||
if args.is_some() {
|
||||
crate::bail_parse_error!(
|
||||
|
||||
@@ -3406,6 +3406,21 @@ pub fn op_function(
|
||||
let result = exec_time(values);
|
||||
state.registers[*dest] = Register::OwnedValue(result);
|
||||
}
|
||||
ScalarFunc::TimeDiff => {
|
||||
if arg_count != 2 {
|
||||
state.registers[*dest] = Register::OwnedValue(OwnedValue::Null);
|
||||
} else {
|
||||
let start = state.registers[*start_reg].get_owned_value().clone();
|
||||
let end = state.registers[*start_reg + 1].get_owned_value().clone();
|
||||
|
||||
let result = crate::functions::datetime::exec_timediff(&[
|
||||
Register::OwnedValue(start),
|
||||
Register::OwnedValue(end),
|
||||
]);
|
||||
|
||||
state.registers[*dest] = Register::OwnedValue(result);
|
||||
}
|
||||
}
|
||||
ScalarFunc::TotalChanges => {
|
||||
let res = &program.connection.upgrade().unwrap().total_changes;
|
||||
let total_changes = res.get();
|
||||
|
||||
Reference in New Issue
Block a user