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