1use chrono::{DateTime, TimeZone, Utc};
2use rusqlite::{Connection, Result};
3
4#[derive(Debug)]
5pub struct Event {
6 pub id: String,
7 pub timestamp: i64,
8 pub source: String,
9 pub content: String,
10 pub meta: Option<String>,
11}
12
13impl Event {
14 pub fn format_time(&self) -> String {
15 let dt: DateTime<Utc> = Utc.timestamp_opt(self.timestamp, 0).unwrap();
16 dt.format("%Y-%m-%d %H:%M:%S UTC").to_string()
17 }
18
19 pub fn preview_content(&self, max_chars: usize) -> String {
20 if self.content.len() <= max_chars {
21 self.content.clone()
22 } else {
23 format!(
24 "{}...\n\n[Content truncated: {} of {} chars shown]",
25 &self.content[..max_chars],
26 max_chars,
27 self.content.len()
28 )
29 }
30 }
31}
32
33pub fn recent(conn: &Connection, limit: i64) -> Result<Vec<Event>> {
34 let mut stmt = conn.prepare(
35 "SELECT id, timestamp, source, content, meta
36 FROM events
37 ORDER BY timestamp DESC
38 LIMIT ?1",
39 )?;
40
41 let rows = stmt.query_map([limit], |row| {
42 Ok(Event {
43 id: row.get(0)?,
44 timestamp: row.get(1)?,
45 source: row.get(2)?,
46 content: row.get(3)?,
47 meta: row.get(4)?,
48 })
49 })?;
50
51 Ok(rows.filter_map(Result::ok).collect())
52}
53
54pub fn search(conn: &Connection, term: &str) -> Result<Vec<Event>> {
55 let like = format!("%{}%", term);
56
57 let mut stmt = conn.prepare(
58 "SELECT id, timestamp, source, content, meta
59 FROM events
60 WHERE content LIKE ?1
61 ORDER BY timestamp DESC",
62 )?;
63
64 let rows = stmt.query_map([like], |row| {
65 Ok(Event {
66 id: row.get(0)?,
67 timestamp: row.get(1)?,
68 source: row.get(2)?,
69 content: row.get(3)?,
70 meta: row.get(4)?,
71 })
72 })?;
73
74 Ok(rows.filter_map(Result::ok).collect())
75}
76
77pub fn by_source(conn: &Connection, source: &str, limit: Option<i64>) -> Result<Vec<Event>> {
78 let query = if let Some(lim) = limit {
79 format!(
80 "SELECT id, timestamp, source, content, meta
81 FROM events
82 WHERE source = ?1
83 ORDER BY timestamp DESC
84 LIMIT {}",
85 lim
86 )
87 } else {
88 "SELECT id, timestamp, source, content, meta
89 FROM events
90 WHERE source = ?1
91 ORDER BY timestamp DESC"
92 .to_string()
93 };
94
95 let mut stmt = conn.prepare(&query)?;
96
97 let rows = stmt.query_map([source], |row| {
98 Ok(Event {
99 id: row.get(0)?,
100 timestamp: row.get(1)?,
101 source: row.get(2)?,
102 content: row.get(3)?,
103 meta: row.get(4)?,
104 })
105 })?;
106
107 Ok(rows.filter_map(Result::ok).collect())
108}
109
110pub fn get_by_id(conn: &Connection, id: &str) -> Result<Event> {
111 conn.query_row(
112 "SELECT id, timestamp, source, content, meta
113 FROM events
114 WHERE id = ?1",
115 [id],
116 |row| {
117 Ok(Event {
118 id: row.get(0)?,
119 timestamp: row.get(1)?,
120 source: row.get(2)?,
121 content: row.get(3)?,
122 meta: row.get(4)?,
123 })
124 },
125 )
126}