1use anyhow::Result;
4use linkmarks_core::Bookmark;
5use serde::Serialize;
6
7#[derive(Debug, Serialize)]
11pub struct TableRow<'a> {
12 pub id: &'a str,
13 pub canonical_url: &'a str,
14 pub title: &'a str,
15 pub tags: String,
16 pub collection: String,
17 pub updated_at: String,
18}
19
20impl<'a> From<&'a Bookmark> for TableRow<'a> {
21 fn from(b: &'a Bookmark) -> Self {
22 Self {
23 id: &b.id.0,
24 canonical_url: &b.canonical_url,
25 title: &b.title,
26 tags: b.tags.join(","),
27 collection: b.collection.clone().unwrap_or_default(),
28 updated_at: b.updated_at.to_rfc3339(),
29 }
30 }
31}
32
33pub fn render(bookmarks: &[Bookmark], format: super::Format) -> Result<String> {
35 let mut sorted: Vec<&Bookmark> = bookmarks.iter().collect();
37 sorted.sort_by(|a, b| {
38 a.canonical_url
39 .cmp(&b.canonical_url)
40 .then_with(|| a.id.0.cmp(&b.id.0))
41 });
42
43 match format {
44 super::Format::Table => render_table(&sorted),
45 super::Format::Json => render_json(&sorted),
46 super::Format::Yaml => render_yaml(&sorted),
47 }
48}
49
50fn render_table(sorted: &[&Bookmark]) -> Result<String> {
51 let mut out = String::new();
52 out.push_str("id\tcanonical_url\ttitle\ttags\tcollection\tupdated_at\n");
53 for b in sorted {
54 let row = TableRow::from(*b);
55 out.push_str(&format!(
56 "{id}\t{canonical}\t{title}\t{tags}\t{collection}\t{updated}\n",
57 id = row.id,
58 canonical = row.canonical_url,
59 title = row.title,
60 tags = row.tags,
61 collection = row.collection,
62 updated = row.updated_at,
63 ));
64 }
65 Ok(out)
66}
67
68fn render_json(sorted: &[&Bookmark]) -> Result<String> {
69 let mut out = String::new();
71 for b in sorted {
72 out.push_str(&serde_json::to_string(b)?);
73 out.push('\n');
74 }
75 Ok(out)
76}
77
78fn render_yaml(sorted: &[&Bookmark]) -> Result<String> {
79 let value = serde_yaml::to_string(sorted)?;
80 Ok(value)
81}