summaryrefslogtreecommitdiff
path: root/makima/src/db/models.rs
diff options
context:
space:
mode:
Diffstat (limited to 'makima/src/db/models.rs')
-rw-r--r--makima/src/db/models.rs38
1 files changed, 38 insertions, 0 deletions
diff --git a/makima/src/db/models.rs b/makima/src/db/models.rs
index 6accb48..0e1303c 100644
--- a/makima/src/db/models.rs
+++ b/makima/src/db/models.rs
@@ -6,6 +6,42 @@ use sqlx::FromRow;
use utoipa::ToSchema;
use uuid::Uuid;
+/// Flexible datetime deserialization module.
+/// Accepts both date-only ("2026-01-15") and full ISO 8601 datetime ("2026-01-15T00:00:00Z") formats.
+pub mod flexible_datetime {
+ use chrono::{DateTime, NaiveDate, NaiveTime, TimeZone, Utc};
+ use serde::{self, Deserialize, Deserializer};
+
+ /// Deserializes a datetime from either date-only or full datetime format.
+ pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<DateTime<Utc>>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let s: Option<String> = Option::deserialize(deserializer)?;
+ match s {
+ None => Ok(None),
+ Some(s) if s.is_empty() => Ok(None),
+ Some(s) => {
+ // Try full datetime first (RFC 3339 / ISO 8601)
+ if let Ok(dt) = DateTime::parse_from_rfc3339(&s) {
+ return Ok(Some(dt.with_timezone(&Utc)));
+ }
+
+ // Try date-only format (YYYY-MM-DD) and convert to start of day UTC
+ if let Ok(date) = NaiveDate::parse_from_str(&s, "%Y-%m-%d") {
+ let datetime = date.and_time(NaiveTime::MIN);
+ return Ok(Some(Utc.from_utc_datetime(&datetime)));
+ }
+
+ Err(serde::de::Error::custom(format!(
+ "Invalid datetime format '{}'. Expected ISO 8601 datetime (e.g., '2026-01-15T00:00:00Z') or date (e.g., '2026-01-15')",
+ s
+ )))
+ }
+ }
+ }
+}
+
/// TranscriptEntry stored in JSONB - matches frontend TranscriptEntry
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
@@ -1646,7 +1682,9 @@ pub struct ToolCallInfo {
pub struct HistoryQueryFilters {
pub phase: Option<String>,
pub event_types: Option<Vec<String>>,
+ #[serde(default, deserialize_with = "flexible_datetime::deserialize")]
pub from: Option<DateTime<Utc>>,
+ #[serde(default, deserialize_with = "flexible_datetime::deserialize")]
pub to: Option<DateTime<Utc>>,
pub limit: Option<i32>,
pub cursor: Option<String>,