aimx/
sheet.rs

1use std::{
2    fmt,
3    sync::Arc,
4};
5use crate::{
6    Reference,
7    aim::{WorkflowLike, Writer, WriterLike}, values::Node,
8};
9use anyhow::Result;
10use jiff::civil::DateTime;
11use jiff::fmt::strtime;
12use jiff::tz::TimeZone;
13
14#[derive(Debug, Clone, PartialEq)]
15pub struct Sheet {
16    pub locator: Arc<Reference>,
17    pub path: Arc<str>,
18    pub date: DateTime,
19    pub version: u32,
20    pub minor_version: u32,
21    pub first_version: u32,
22    pub latest_version: u32,
23    pub model: Arc<str>,
24    pub pattern: Arc<str>,
25    pub length: u32,
26}
27
28impl Sheet {
29    /// Converts a workflow node into a sheet representation containing metadata about the workflow and its inference configuration.
30    #[doc = include_str!("../docs/sheet/convert.md")]
31    pub fn convert(node: &Node) -> Result<Self> {
32        let workflow = node.get_workflow()?;
33        let locator = workflow.locator();
34        let path_buf = locator.to_path();
35        let path: Arc<str> = Arc::from(path_buf.to_string_lossy());
36        Ok(Self {
37            locator,
38            path,
39            date: workflow.date(),
40            version: workflow.version(),
41            minor_version: workflow.minor_version(),
42            first_version: workflow.first_version(),
43            latest_version: workflow.latest_version(),
44            model: Arc::from(node.inference().model().as_str()),
45            pattern: Arc::from(node.inference().pattern().as_str()),
46            length: workflow.row_count() as u32,
47        })
48    }
49
50    pub fn locator(&self) -> &Arc<Reference> {
51        &self.locator
52    }
53
54    pub fn path(&self) -> &Arc<str> {
55        &self.path
56    }
57
58    pub fn date(&self) -> &DateTime {
59        &self.date
60    }
61
62    pub fn version(&self) -> u32 {
63        self.version
64    }
65
66    pub fn minor_version(&self) -> u32 {
67        self.minor_version
68    }
69
70    pub fn first_version(&self) -> u32 {
71        self.first_version
72    }
73
74    pub fn latest_version(&self) -> u32 {
75        self.latest_version
76    }
77
78    pub fn model(&self) -> &Arc<str> {
79        &self.model
80    }
81
82    pub fn pattern(&self) -> &Arc<str> {
83        &self.pattern
84    }
85
86    pub fn length(&self) -> u32 {
87        self.length
88    }
89
90    pub fn is_empty(&self) -> bool {
91        self.length == 0
92    }
93
94    /// Serializes a Sheet instance to a Writer, outputting structured metadata about a workflow.
95    #[doc = include_str!("../docs/sheet/print.md")]
96    pub fn print(&self, writer: &mut Writer) {
97        writer.write_str("=== SHEET START ==="); writer.write_eol();
98        writer.write_str("- locator: "); self.locator.print(writer); writer.write_eol();
99        writer.write_str("- path: "); writer.print(&self.path); writer.write_eol();
100        writer.write_str("- date: "); writer.write_date(&self.date); writer.write_eol();
101        writer.write_str("- version: "); writer.write_unsigned(self.version); writer.write_eol();
102        writer.write_str("- minor_version: "); writer.write_unsigned(self.minor_version); writer.write_eol();
103        writer.write_str("- first_version: "); writer.write_unsigned(self.first_version); writer.write_eol();
104        writer.write_str("- latest_version: "); writer.write_unsigned(self.latest_version); writer.write_eol();
105        writer.write_str("- model: "); writer.print(&self.model); writer.write_eol();
106        writer.write_str("- pattern: "); writer.print(&self.pattern); writer.write_eol();
107        writer.write_str("- length: "); writer.write_unsigned(self.length); writer.write_eol();
108        writer.write_str("=== SHEET END ==="); writer.write_eol();
109    }
110
111    /// Return the formula-string representation (round-trippable by the parser).
112    #[doc = include_str!("../docs/sheet/to_formula.md")]
113    pub fn to_formula(&self) -> String {
114        let mut writer = Writer::formulizer();
115        self.print(&mut writer);
116        writer.finish()
117    }
118
119    /// Formats the Sheet's date using the computer's local timezone with a custom format string.
120    ///
121    /// # Arguments
122    ///
123    /// * `format` - A strftime-style format string (e.g., "%Y/%m/%d", "%A, %B %d, %Y")
124    ///
125    /// # Returns
126    ///
127    /// Returns a `Result<String>` containing the formatted date string.
128    ///
129    /// # Examples
130    ///
131    /// ```
132    /// use aimx::{Sheet, values::Node};
133    /// 
134    /// // Assuming you have a Node instance
135    /// // let node = /* obtain node from workflow */;
136    /// // let sheet = Sheet::convert(&node)?;
137    /// // let formatted = sheet.custom_format_date("%Y-%m-%d");
138    /// // let formatted = sheet.custom_format_date("%A, %B %d, %Y at %I:%M %p");
139    /// ```
140    pub fn custom_format_date(&self, format: &str) -> String {
141        let date = if let Ok(zoned) = self.date.to_zoned(TimeZone::system()) {
142            zoned.datetime()
143        } else {
144            self.date
145        };
146        if let Ok(result) = strtime::format(format, date) {
147            result
148        } else {
149            let mut writer = Writer::stringizer();
150            writer.write_date(&date);
151            writer.finish()
152        }
153    }
154
155/// Formats the Sheet's date using the computer's local timezone with a default presentable format.
156    ///
157    /// The default format is: "Weekday, DD/MM/YY HH:MM AM/PM"
158    /// For example: "Monday, 15/3/24 02:30 PM"
159    ///
160    /// # Returns
161    ///
162    /// Returns a `Result<String>` containing the formatted date string.
163    ///
164    /// # Examples
165    ///
166    /// ```
167    /// use aimx::{Sheet, values::Node};
168    /// 
169    /// // Assuming you have a Node instance
170    /// // let node = /* obtain node from workflow */;
171    /// // let sheet = Sheet::convert(&node)?;
172    /// // let formatted = sheet.format_date();
173    /// // Output: "Monday, 15/3/24 02:30 PM"
174    /// ```
175    pub fn format_date(&self) -> String {
176        self.custom_format_date("%A, %d/%m/%y %I:%M %p")
177    }
178}
179
180impl WriterLike for Sheet {
181    fn write(&self, writer: &mut Writer) {
182        self.print(writer);
183    }
184}
185
186impl fmt::Display for Sheet {
187    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188        write!(f, "{}", self.to_stringized())
189    }
190}