use stoolap::Database;
#[test]
fn test_date_trunc_year() {
let db = Database::open("memory://date_trunc_year").expect("Failed to create database");
db.execute(
"CREATE TABLE time_test (
id INTEGER PRIMARY KEY,
event_timestamp TIMESTAMP
)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO time_test (id, event_timestamp) VALUES
(1, TIMESTAMP '2021-03-15 09:15:30'),
(2, TIMESTAMP '2021-07-20 14:30:00'),
(3, TIMESTAMP '2022-01-10 08:55:20')",
(),
)
.expect("Failed to insert data");
let result = db
.query(
"SELECT DATE_TRUNC('year', event_timestamp) AS year_trunc FROM time_test ORDER BY id",
(),
)
.expect("Failed to execute query");
let mut results: Vec<String> = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let truncated: String = row.get(0).unwrap();
results.push(truncated);
}
assert_eq!(results.len(), 3, "Expected 3 rows");
assert!(
results[0].contains("2021-01-01"),
"Expected year truncation to 2021-01-01, got {}",
results[0]
);
assert!(
results[1].contains("2021-01-01"),
"Expected year truncation to 2021-01-01, got {}",
results[1]
);
assert!(
results[2].contains("2022-01-01"),
"Expected year truncation to 2022-01-01, got {}",
results[2]
);
}
#[test]
fn test_date_trunc_month() {
let db = Database::open("memory://date_trunc_month").expect("Failed to create database");
db.execute(
"CREATE TABLE time_test (
id INTEGER PRIMARY KEY,
event_timestamp TIMESTAMP
)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO time_test (id, event_timestamp) VALUES
(1, TIMESTAMP '2021-03-15 09:15:30'),
(2, TIMESTAMP '2021-03-20 14:30:00'),
(3, TIMESTAMP '2021-05-10 08:55:20')",
(),
)
.expect("Failed to insert data");
let result = db
.query(
"SELECT DATE_TRUNC('month', event_timestamp) AS month_trunc FROM time_test ORDER BY id",
(),
)
.expect("Failed to execute query");
let mut results: Vec<String> = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let truncated: String = row.get(0).unwrap();
results.push(truncated);
}
assert_eq!(results.len(), 3, "Expected 3 rows");
assert!(
results[0].contains("2021-03-01"),
"Expected month truncation to 2021-03-01, got {}",
results[0]
);
assert!(
results[1].contains("2021-03-01"),
"Expected month truncation to 2021-03-01, got {}",
results[1]
);
assert!(
results[2].contains("2021-05-01"),
"Expected month truncation to 2021-05-01, got {}",
results[2]
);
}
#[test]
fn test_time_trunc_hour() {
let db = Database::open("memory://time_trunc_hour").expect("Failed to create database");
db.execute(
"CREATE TABLE time_test (
id INTEGER PRIMARY KEY,
event_timestamp TIMESTAMP
)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO time_test (id, event_timestamp) VALUES
(1, TIMESTAMP '2021-03-15 09:15:30'),
(2, TIMESTAMP '2021-03-15 09:45:00'),
(3, TIMESTAMP '2021-03-15 10:30:00')",
(),
)
.expect("Failed to insert data");
let result = db
.query(
"SELECT TIME_TRUNC('1h', event_timestamp) AS hour_trunc FROM time_test ORDER BY id",
(),
)
.expect("Failed to execute query");
let mut results: Vec<String> = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let truncated: String = row.get(0).unwrap();
results.push(truncated);
}
assert_eq!(results.len(), 3, "Expected 3 rows");
assert!(
results[0].contains("09:00:00"),
"Expected hour truncation to 09:00:00, got {}",
results[0]
);
assert!(
results[1].contains("09:00:00"),
"Expected hour truncation to 09:00:00, got {}",
results[1]
);
assert!(
results[2].contains("10:00:00"),
"Expected hour truncation to 10:00:00, got {}",
results[2]
);
}
#[test]
fn test_time_trunc_15_minutes() {
let db = Database::open("memory://time_trunc_15m").expect("Failed to create database");
db.execute(
"CREATE TABLE time_test (
id INTEGER PRIMARY KEY,
event_timestamp TIMESTAMP
)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO time_test (id, event_timestamp) VALUES
(1, TIMESTAMP '2021-03-15 09:15:30'),
(2, TIMESTAMP '2021-03-15 09:25:00'),
(3, TIMESTAMP '2021-03-15 09:35:00')",
(),
)
.expect("Failed to insert data");
let result = db
.query(
"SELECT TIME_TRUNC('15m', event_timestamp) AS min_trunc FROM time_test ORDER BY id",
(),
)
.expect("Failed to execute query");
let mut results: Vec<String> = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let truncated: String = row.get(0).unwrap();
results.push(truncated);
}
assert_eq!(results.len(), 3, "Expected 3 rows");
assert!(
results[0].contains("09:15:00"),
"Expected 15m truncation to 09:15:00, got {}",
results[0]
);
assert!(
results[1].contains("09:15:00"),
"Expected 15m truncation to 09:15:00, got {}",
results[1]
);
assert!(
results[2].contains("09:30:00"),
"Expected 15m truncation to 09:30:00, got {}",
results[2]
);
}
#[test]
fn test_time_trunc_group_by() {
let db = Database::open("memory://time_trunc_group").expect("Failed to create database");
db.execute(
"CREATE TABLE sales (
id INTEGER PRIMARY KEY,
amount FLOAT,
transaction_time TIMESTAMP
)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO sales (id, amount, transaction_time) VALUES
(1, 50.0, TIMESTAMP '2023-01-01 09:15:00'),
(2, 25.0, TIMESTAMP '2023-01-01 09:30:00'),
(3, 75.0, TIMESTAMP '2023-01-01 10:15:00'),
(4, 100.0, TIMESTAMP '2023-01-01 10:45:00'),
(5, 35.0, TIMESTAMP '2023-01-01 11:15:00'),
(6, 60.0, TIMESTAMP '2023-01-01 11:45:00')",
(),
)
.expect("Failed to insert data");
let result = db
.query(
"SELECT TIME_TRUNC('1h', transaction_time) AS hour_bucket, SUM(amount) AS total_sales
FROM sales
GROUP BY TIME_TRUNC('1h', transaction_time)
ORDER BY hour_bucket",
(),
)
.expect("Failed to execute query");
let mut results: Vec<(String, f64)> = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let bucket: String = row.get(0).unwrap();
let total: f64 = row.get(1).unwrap();
results.push((bucket, total));
}
assert_eq!(results.len(), 3, "Expected 3 hour buckets");
assert!(
results[0].0.contains("09:00"),
"First bucket should be 09:00"
);
assert!(
(results[0].1 - 75.0).abs() < 0.01,
"9:00 hour should have 75.0 total, got {}",
results[0].1
);
assert!(
results[1].0.contains("10:00"),
"Second bucket should be 10:00"
);
assert!(
(results[1].1 - 175.0).abs() < 0.01,
"10:00 hour should have 175.0 total, got {}",
results[1].1
);
assert!(
results[2].0.contains("11:00"),
"Third bucket should be 11:00"
);
assert!(
(results[2].1 - 95.0).abs() < 0.01,
"11:00 hour should have 95.0 total, got {}",
results[2].1
);
}
#[test]
fn test_date_trunc_day() {
let db = Database::open("memory://date_trunc_day").expect("Failed to create database");
db.execute(
"CREATE TABLE events (
id INTEGER PRIMARY KEY,
event_time TIMESTAMP
)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO events (id, event_time) VALUES
(1, TIMESTAMP '2023-06-15 09:30:00'),
(2, TIMESTAMP '2023-06-15 14:45:00'),
(3, TIMESTAMP '2023-06-16 10:00:00')",
(),
)
.expect("Failed to insert data");
let result = db
.query(
"SELECT DATE_TRUNC('day', event_time) AS day_trunc FROM events ORDER BY id",
(),
)
.expect("Failed to execute query");
let mut results: Vec<String> = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let truncated: String = row.get(0).unwrap();
results.push(truncated);
}
assert_eq!(results.len(), 3);
assert!(
results[0].contains("2023-06-15 00:00:00") || results[0].contains("2023-06-15T00:00:00")
);
assert!(
results[1].contains("2023-06-15 00:00:00") || results[1].contains("2023-06-15T00:00:00")
);
assert!(
results[2].contains("2023-06-16 00:00:00") || results[2].contains("2023-06-16T00:00:00")
);
}
#[test]
fn test_time_trunc_5_minutes() {
let db = Database::open("memory://time_trunc_5m").expect("Failed to create database");
db.execute(
"CREATE TABLE metrics (
id INTEGER PRIMARY KEY,
recorded_at TIMESTAMP
)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO metrics (id, recorded_at) VALUES
(1, TIMESTAMP '2023-01-01 10:03:30'),
(2, TIMESTAMP '2023-01-01 10:07:00'),
(3, TIMESTAMP '2023-01-01 10:11:00')",
(),
)
.expect("Failed to insert data");
let result = db
.query(
"SELECT TIME_TRUNC('5m', recorded_at) AS bucket FROM metrics ORDER BY id",
(),
)
.expect("Failed to execute query");
let mut results: Vec<String> = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let truncated: String = row.get(0).unwrap();
results.push(truncated);
}
assert_eq!(results.len(), 3);
assert!(
results[0].contains("10:00:00"),
"10:03:30 should truncate to 10:00:00, got {}",
results[0]
);
assert!(
results[1].contains("10:05:00"),
"10:07:00 should truncate to 10:05:00, got {}",
results[1]
);
assert!(
results[2].contains("10:10:00"),
"10:11:00 should truncate to 10:10:00, got {}",
results[2]
);
}
#[test]
fn test_time_trunc_30_minutes() {
let db = Database::open("memory://time_trunc_30m").expect("Failed to create database");
db.execute(
"CREATE TABLE events (
id INTEGER PRIMARY KEY,
event_time TIMESTAMP
)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO events (id, event_time) VALUES
(1, TIMESTAMP '2023-01-01 10:10:00'),
(2, TIMESTAMP '2023-01-01 10:40:00'),
(3, TIMESTAMP '2023-01-01 11:20:00')",
(),
)
.expect("Failed to insert data");
let result = db
.query(
"SELECT TIME_TRUNC('30m', event_time) AS bucket FROM events ORDER BY id",
(),
)
.expect("Failed to execute query");
let mut results: Vec<String> = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let truncated: String = row.get(0).unwrap();
results.push(truncated);
}
assert_eq!(results.len(), 3);
assert!(
results[0].contains("10:00:00"),
"10:10:00 should truncate to 10:00:00, got {}",
results[0]
);
assert!(
results[1].contains("10:30:00"),
"10:40:00 should truncate to 10:30:00, got {}",
results[1]
);
assert!(
results[2].contains("11:00:00"),
"11:20:00 should truncate to 11:00:00, got {}",
results[2]
);
}
#[test]
fn test_date_trunc_week() {
let db = Database::open("memory://date_trunc_week").expect("Failed to create database");
db.execute(
"CREATE TABLE events (
id INTEGER PRIMARY KEY,
event_time TIMESTAMP
)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO events (id, event_time) VALUES
(1, TIMESTAMP '2023-06-15 10:00:00'),
(2, TIMESTAMP '2023-06-17 14:00:00'),
(3, TIMESTAMP '2023-06-19 09:00:00')",
(),
)
.expect("Failed to insert data");
let result = db
.query(
"SELECT DATE_TRUNC('week', event_time) AS week_trunc FROM events ORDER BY id",
(),
)
.expect("Failed to execute query");
let mut results: Vec<String> = Vec::new();
for row in result {
let row = row.expect("Failed to get row");
let truncated: String = row.get(0).unwrap();
results.push(truncated);
}
assert_eq!(results.len(), 3);
assert!(
results[0].contains("2023-06-12"),
"First date should truncate to week starting 2023-06-12"
);
assert!(
results[1].contains("2023-06-12"),
"Second date should truncate to week starting 2023-06-12"
);
assert!(
results[2].contains("2023-06-19"),
"Third date should truncate to week starting 2023-06-19"
);
}
#[test]
fn test_combined_truncations() {
let db = Database::open("memory://combined_trunc").expect("Failed to create database");
db.execute(
"CREATE TABLE events (
id INTEGER PRIMARY KEY,
event_time TIMESTAMP
)",
(),
)
.expect("Failed to create table");
db.execute(
"INSERT INTO events (id, event_time) VALUES
(1, TIMESTAMP '2023-06-15 10:23:45')",
(),
)
.expect("Failed to insert data");
let result = db
.query(
"SELECT
DATE_TRUNC('month', event_time) AS month_trunc,
TIME_TRUNC('1h', event_time) AS hour_trunc
FROM events WHERE id = 1",
(),
)
.expect("Failed to execute query");
for row in result {
let row = row.expect("Failed to get row");
let month_trunc: String = row.get(0).unwrap();
let hour_trunc: String = row.get(1).unwrap();
assert!(
month_trunc.contains("2023-06-01"),
"Month truncation should be 2023-06-01, got {}",
month_trunc
);
assert!(
hour_trunc.contains("10:00:00"),
"Hour truncation should contain 10:00:00, got {}",
hour_trunc
);
}
}