mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-19 09:34:18 +01:00
feat: add timediff data and time function
This commit is contained in:
@@ -293,6 +293,7 @@ pub enum ScalarFunc {
|
|||||||
StrfTime,
|
StrfTime,
|
||||||
Printf,
|
Printf,
|
||||||
Likely,
|
Likely,
|
||||||
|
TimeDiff,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for ScalarFunc {
|
impl Display for ScalarFunc {
|
||||||
@@ -348,6 +349,7 @@ impl Display for ScalarFunc {
|
|||||||
Self::StrfTime => "strftime".to_string(),
|
Self::StrfTime => "strftime".to_string(),
|
||||||
Self::Printf => "printf".to_string(),
|
Self::Printf => "printf".to_string(),
|
||||||
Self::Likely => "likely".to_string(),
|
Self::Likely => "likely".to_string(),
|
||||||
|
Self::TimeDiff => "timediff".to_string(),
|
||||||
};
|
};
|
||||||
write!(f, "{}", str)
|
write!(f, "{}", str)
|
||||||
}
|
}
|
||||||
@@ -555,6 +557,12 @@ impl Func {
|
|||||||
}
|
}
|
||||||
Ok(Self::Agg(AggFunc::Total))
|
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")]
|
#[cfg(feature = "json")]
|
||||||
"jsonb_group_array" => Ok(Self::Agg(AggFunc::JsonbGroupArray)),
|
"jsonb_group_array" => Ok(Self::Agg(AggFunc::JsonbGroupArray)),
|
||||||
#[cfg(feature = "json")]
|
#[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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -1642,4 +1697,67 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_strftime() {}
|
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)
|
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 => {
|
ScalarFunc::TotalChanges => {
|
||||||
if args.is_some() {
|
if args.is_some() {
|
||||||
crate::bail_parse_error!(
|
crate::bail_parse_error!(
|
||||||
|
|||||||
@@ -3406,6 +3406,21 @@ pub fn op_function(
|
|||||||
let result = exec_time(values);
|
let result = exec_time(values);
|
||||||
state.registers[*dest] = Register::OwnedValue(result);
|
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 => {
|
ScalarFunc::TotalChanges => {
|
||||||
let res = &program.connection.upgrade().unwrap().total_changes;
|
let res = &program.connection.upgrade().unwrap().total_changes;
|
||||||
let total_changes = res.get();
|
let total_changes = res.get();
|
||||||
|
|||||||
Reference in New Issue
Block a user