import.rs

 1use anyhow::Result;
 2use serde::Deserialize;
 3use std::io::BufRead;
 4use std::path::Path;
 5
 6use crate::db;
 7
 8#[derive(Deserialize)]
 9struct ImportTask {
10    id: String,
11    title: String,
12    #[serde(default)]
13    description: String,
14    #[serde(rename = "type", default = "default_type")]
15    task_type: String,
16    #[serde(default = "default_priority")]
17    priority: i32,
18    #[serde(default = "default_status")]
19    status: String,
20    #[serde(default)]
21    parent: String,
22    created: String,
23    updated: String,
24    #[serde(default)]
25    labels: Vec<String>,
26    #[serde(default)]
27    blockers: Vec<String>,
28}
29
30fn default_type() -> String {
31    "task".into()
32}
33fn default_priority() -> i32 {
34    2
35}
36fn default_status() -> String {
37    "open".into()
38}
39
40pub fn run(root: &Path, file: &str) -> Result<()> {
41    let conn = db::open(root)?;
42
43    eprintln!("info: importing from {file}...");
44
45    let reader: Box<dyn BufRead> = if file == "-" {
46        Box::new(std::io::stdin().lock())
47    } else {
48        Box::new(std::io::BufReader::new(std::fs::File::open(file)?))
49    };
50
51    for line in reader.lines() {
52        let line = line?;
53        if line.trim().is_empty() {
54            continue;
55        }
56
57        let t: ImportTask = serde_json::from_str(&line)?;
58
59        conn.execute(
60            "INSERT OR REPLACE INTO tasks
61             (id, title, description, type, priority, status, parent, created, updated)
62             VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)",
63            rusqlite::params![
64                t.id,
65                t.title,
66                t.description,
67                t.task_type,
68                t.priority,
69                t.status,
70                t.parent,
71                t.created,
72                t.updated,
73            ],
74        )?;
75
76        // Replace labels.
77        conn.execute("DELETE FROM labels WHERE task_id = ?1", [&t.id])?;
78        for lbl in &t.labels {
79            conn.execute(
80                "INSERT INTO labels (task_id, label) VALUES (?1, ?2)",
81                [&t.id, lbl],
82            )?;
83        }
84
85        // Replace blockers.
86        conn.execute("DELETE FROM blockers WHERE task_id = ?1", [&t.id])?;
87        for blk in &t.blockers {
88            conn.execute(
89                "INSERT INTO blockers (task_id, blocker_id) VALUES (?1, ?2)",
90                [&t.id, blk],
91            )?;
92        }
93    }
94
95    eprintln!("info: import complete");
96    Ok(())
97}