use std::collections::BTreeMap;
use std::fmt;
use grumpydb::Value;
use uuid::Uuid;
#[derive(Debug, Clone)]
pub struct Task {
pub id: Uuid,
pub title: String,
pub description: Option<String>,
pub done: bool,
pub created_at: i64,
pub tags: Vec<String>,
}
impl Task {
pub fn new(title: impl Into<String>, description: Option<&str>, tags: Vec<&str>) -> Self {
Self {
id: Uuid::new_v4(),
title: title.into(),
description: description.map(String::from),
done: false,
created_at: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs() as i64,
tags: tags.into_iter().map(String::from).collect(),
}
}
pub fn to_value(&self) -> Value {
let mut map = BTreeMap::new();
map.insert("title".into(), Value::String(self.title.clone()));
map.insert("done".into(), Value::Bool(self.done));
map.insert("created_at".into(), Value::Integer(self.created_at));
map.insert(
"description".into(),
match &self.description {
Some(desc) => Value::String(desc.clone()),
None => Value::Null,
},
);
map.insert(
"tags".into(),
Value::Array(self.tags.iter().map(|t| Value::String(t.clone())).collect()),
);
Value::Object(map)
}
pub fn from_value(id: Uuid, value: &Value) -> Option<Self> {
let obj = value.as_object()?;
let title = obj.get("title")?.as_str()?.to_string();
let done = obj.get("done")?.as_bool()?;
let created_at = obj.get("created_at")?.as_i64()?;
let description = obj
.get("description")
.and_then(|v| if v.is_null() { None } else { v.as_str() })
.map(String::from);
let tags = obj
.get("tags")
.and_then(|v| v.as_array())
.map(|arr| {
arr.iter()
.filter_map(|v| v.as_str().map(String::from))
.collect()
})
.unwrap_or_default();
Some(Self {
id,
title,
description,
done,
created_at,
tags,
})
}
}
impl fmt::Display for Task {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let status = if self.done { "✓" } else { "○" };
let short_id = &self.id.to_string()[..8];
write!(f, "[{status}] {short_id} {}", self.title)?;
if !self.tags.is_empty() {
let tags_str: Vec<&str> = self.tags.iter().map(|s| s.as_str()).collect();
write!(f, " ({})", tags_str.join(", "))?;
}
Ok(())
}
}