use stoolap::core::Value;
use stoolap::Database;
#[test]
fn test_interval_now_minus_24_hours() {
let db = Database::open("memory://interval_24h").expect("Failed to create database");
let result = db
.query("SELECT NOW() - INTERVAL '24 hours'", ())
.expect("Failed to execute query");
let mut count = 0;
for row in result {
let row = row.expect("Failed to get row");
let value: Value = row.get(0).unwrap();
if let Value::Timestamp(timestamp) = value {
let now = chrono::Utc::now();
let diff = now.signed_duration_since(timestamp);
assert!(
diff.num_hours() >= 23 && diff.num_hours() <= 25,
"Expected timestamp ~24 hours ago, got {} hours ago",
diff.num_hours()
);
} else {
panic!("Expected Timestamp value, got {:?}", value);
}
count += 1;
}
assert_eq!(count, 1, "Expected 1 row");
}
#[test]
fn test_interval_now_plus_1_day() {
let db = Database::open("memory://interval_1d").expect("Failed to create database");
let result = db
.query("SELECT NOW() + INTERVAL '1 day'", ())
.expect("Failed to execute query");
let mut count = 0;
for row in result {
let row = row.expect("Failed to get row");
let value: Value = row.get(0).unwrap();
if let Value::Timestamp(timestamp) = value {
let now = chrono::Utc::now();
let diff = timestamp.signed_duration_since(now);
assert!(
diff.num_hours() >= 23 && diff.num_hours() <= 25,
"Expected timestamp ~24 hours in future, got {} hours",
diff.num_hours()
);
} else {
panic!("Expected Timestamp value, got {:?}", value);
}
count += 1;
}
assert_eq!(count, 1, "Expected 1 row");
}
#[test]
fn test_interval_now_minus_30_minutes() {
let db = Database::open("memory://interval_30m").expect("Failed to create database");
let result = db
.query("SELECT NOW() - INTERVAL '30 minutes'", ())
.expect("Failed to execute query");
let mut count = 0;
for row in result {
let row = row.expect("Failed to get row");
let value: Value = row.get(0).unwrap();
if let Value::Timestamp(timestamp) = value {
let now = chrono::Utc::now();
let diff = now.signed_duration_since(timestamp);
assert!(
diff.num_minutes() >= 29 && diff.num_minutes() <= 31,
"Expected timestamp ~30 minutes ago, got {} minutes ago",
diff.num_minutes()
);
} else {
panic!("Expected Timestamp value, got {:?}", value);
}
count += 1;
}
assert_eq!(count, 1, "Expected 1 row");
}
#[test]
fn test_interval_with_seconds() {
let db = Database::open("memory://interval_seconds").expect("Failed to create database");
let result = db
.query("SELECT NOW() + INTERVAL '90 seconds'", ())
.expect("Failed to execute query");
let mut count = 0;
for row in result {
let row = row.expect("Failed to get row");
let value: Value = row.get(0).unwrap();
if let Value::Timestamp(timestamp) = value {
let now = chrono::Utc::now();
let diff = timestamp.signed_duration_since(now);
assert!(
diff.num_seconds() >= 89 && diff.num_seconds() <= 91,
"Expected timestamp ~90 seconds in future, got {} seconds",
diff.num_seconds()
);
} else {
panic!("Expected Timestamp value, got {:?}", value);
}
count += 1;
}
assert_eq!(count, 1, "Expected 1 row");
}
#[test]
fn test_interval_with_weeks() {
let db = Database::open("memory://interval_weeks").expect("Failed to create database");
let result = db
.query("SELECT NOW() - INTERVAL '2 weeks'", ())
.expect("Failed to execute query");
let mut count = 0;
for row in result {
let row = row.expect("Failed to get row");
let value: Value = row.get(0).unwrap();
if let Value::Timestamp(timestamp) = value {
let now = chrono::Utc::now();
let diff = now.signed_duration_since(timestamp);
assert!(
diff.num_days() >= 13 && diff.num_days() <= 15,
"Expected timestamp ~14 days ago, got {} days ago",
diff.num_days()
);
} else {
panic!("Expected Timestamp value, got {:?}", value);
}
count += 1;
}
assert_eq!(count, 1, "Expected 1 row");
}
#[test]
fn test_interval_with_timestamp_literal() {
let db = Database::open("memory://interval_literal").expect("Failed to create database");
let result = db
.query(
"SELECT TIMESTAMP '2025-01-01 12:00:00' + INTERVAL '25 hours'",
(),
)
.expect("Failed to execute query");
let mut count = 0;
for row in result {
let row = row.expect("Failed to get row");
let value: Value = row.get(0).unwrap();
if let Value::Timestamp(timestamp) = value {
let expected = chrono::DateTime::parse_from_rfc3339("2025-01-02T13:00:00Z")
.unwrap()
.with_timezone(&chrono::Utc);
assert_eq!(
timestamp, expected,
"Expected {}, got {}",
expected, timestamp
);
} else {
panic!("Expected Timestamp value, got {:?}", value);
}
count += 1;
}
assert_eq!(count, 1, "Expected 1 row");
}
#[test]
fn test_interval_in_where_clause() {
let db = Database::open("memory://interval_where").expect("Failed to create database");
db.execute(
"CREATE TABLE events (
id INTEGER PRIMARY KEY,
name TEXT,
event_time TIMESTAMP
)",
(),
)
.expect("Failed to create table");
db.execute("INSERT INTO events VALUES (1, 'Recent Event', NOW())", ())
.expect("Failed to insert");
db.execute(
"INSERT INTO events VALUES (2, 'Old Event', TIMESTAMP '2020-01-01 00:00:00')",
(),
)
.expect("Failed to insert");
let result = db
.query(
"SELECT * FROM events WHERE event_time > NOW() - INTERVAL '7 days'",
(),
)
.expect("Failed to execute query");
let mut count = 0;
for row in result {
let row = row.expect("Failed to get row");
let name: String = row.get(1).unwrap();
assert_eq!(name, "Recent Event", "Expected only recent events");
count += 1;
}
assert_eq!(count, 1, "Expected 1 recent event");
}
#[test]
fn test_interval_with_hours() {
let db = Database::open("memory://interval_hours").expect("Failed to create database");
let result = db
.query("SELECT NOW() + INTERVAL '5 hours'", ())
.expect("Failed to execute query");
let mut count = 0;
for row in result {
let row = row.expect("Failed to get row");
let value: Value = row.get(0).unwrap();
if let Value::Timestamp(timestamp) = value {
let now = chrono::Utc::now();
let diff = timestamp.signed_duration_since(now);
assert!(
diff.num_hours() >= 4 && diff.num_hours() <= 6,
"Expected timestamp ~5 hours in future, got {} hours",
diff.num_hours()
);
} else {
panic!("Expected Timestamp value, got {:?}", value);
}
count += 1;
}
assert_eq!(count, 1, "Expected 1 row");
}
#[test]
fn test_interval_month_calendar_aware() {
let db = Database::open("memory://interval_month_cal").expect("Failed to create database");
let ts: String = db
.query_one(
"SELECT TIMESTAMP '2025-01-31 10:30:00' + INTERVAL '1 month'",
(),
)
.expect("Failed to execute query");
assert_eq!(ts, "2025-02-28T10:30:00Z");
}
#[test]
fn test_interval_month_leap_year() {
let db = Database::open("memory://interval_month_leap").expect("Failed to create database");
let ts: String = db
.query_one(
"SELECT TIMESTAMP '2024-01-31 15:00:00' + INTERVAL '1 month'",
(),
)
.expect("Failed to execute query");
assert_eq!(ts, "2024-02-29T15:00:00Z");
}
#[test]
fn test_interval_year_calendar_aware() {
let db = Database::open("memory://interval_year_cal").expect("Failed to create database");
let ts: String = db
.query_one(
"SELECT TIMESTAMP '2024-02-29 12:00:00' + INTERVAL '1 year'",
(),
)
.expect("Failed to execute query");
assert_eq!(ts, "2025-02-28T12:00:00Z");
}
#[test]
fn test_interval_subtract_months() {
let db = Database::open("memory://interval_sub_month").expect("Failed to create database");
let ts: String = db
.query_one(
"SELECT TIMESTAMP '2025-03-31 08:00:00' - INTERVAL '1 month'",
(),
)
.expect("Failed to execute query");
assert_eq!(ts, "2025-02-28T08:00:00Z");
}
#[test]
fn test_interval_months_cross_year() {
let db = Database::open("memory://interval_cross_year").expect("Failed to create database");
let ts: String = db
.query_one(
"SELECT TIMESTAMP '2025-11-15 00:00:00' + INTERVAL '3 months'",
(),
)
.expect("Failed to execute query");
assert_eq!(ts, "2026-02-15T00:00:00Z");
}
#[test]
fn test_interval_12_months_equals_1_year() {
let db = Database::open("memory://interval_12m_1y").expect("Failed to create database");
let ts_months: String = db
.query_one(
"SELECT TIMESTAMP '2025-06-15 12:00:00' + INTERVAL '12 months'",
(),
)
.expect("Failed");
let ts_year: String = db
.query_one(
"SELECT TIMESTAMP '2025-06-15 12:00:00' + INTERVAL '1 year'",
(),
)
.expect("Failed");
assert_eq!(ts_months, ts_year);
assert_eq!(ts_months, "2026-06-15T12:00:00Z");
}