Skip to main content

track/db/
row_mapping.rs

1//! Shared SQLite row parsing helpers for domain entities.
2
3use crate::models::{Task, TaskStatus, Todo, TodoStatus};
4use chrono::{DateTime, Utc};
5use rusqlite::{types::Type, Row};
6use std::str::FromStr;
7
8/// Parses an RFC3339 timestamp stored as TEXT.
9pub fn parse_datetime(value: String) -> rusqlite::Result<DateTime<Utc>> {
10    value
11        .parse()
12        .map_err(|e| rusqlite::Error::FromSqlConversionFailure(0, Type::Text, Box::new(e)))
13}
14
15/// Parses a task status column value.
16pub fn parse_task_status(value: String) -> rusqlite::Result<TaskStatus> {
17    TaskStatus::from_str(&value).map_err(|_| rusqlite::Error::InvalidQuery)
18}
19
20/// Parses a todo status column value.
21pub fn parse_todo_status(value: String) -> rusqlite::Result<TodoStatus> {
22    TodoStatus::from_str(&value).map_err(|_| rusqlite::Error::InvalidQuery)
23}
24
25/// Maps a tasks table row into a [`Task`].
26pub fn row_to_task(row: &Row<'_>) -> rusqlite::Result<Task> {
27    Ok(Task {
28        id: row.get(0)?,
29        name: row.get(1)?,
30        description: row.get(2)?,
31        status: parse_task_status(row.get(3)?)?,
32        ticket_id: row.get(4)?,
33        ticket_url: row.get(5)?,
34        alias: row.get(6)?,
35        is_today_task: row.get::<_, i64>(7)? != 0,
36        created_at: parse_datetime(row.get(8)?)?,
37    })
38}
39
40/// Maps a todos table row into a [`Todo`].
41pub fn row_to_todo(row: &Row<'_>) -> rusqlite::Result<Todo> {
42    Ok(Todo {
43        id: row.get(0)?,
44        task_id: row.get(1)?,
45        task_index: row.get(2)?,
46        content: row.get(3)?,
47        status: parse_todo_status(row.get(4)?)?,
48        worktree_requested: row.get(5)?,
49        created_at: parse_datetime(row.get(6)?)?,
50        completed_at: row
51            .get::<_, Option<String>>(7)?
52            .map(parse_datetime)
53            .transpose()?,
54    })
55}