excel_lib/
utils.rs

1use chrono::{NaiveDate, Duration}; 
2
3use crate::parser::{
4    parse_str, 
5    ast::Expr
6}; 
7use crate::reference::Reference; 
8use crate::errors::Error; 
9
10pub fn excel_to_date(serial: f64)  -> NaiveDate {
11    let start_date = NaiveDate::from_ymd(1899, 12, 30); 
12    let mut duration = Duration::days(serial as i64); 
13    let frac = (serial - serial.floor()) as i64; 
14    if frac > 0 {
15        duration = duration.checked_add(&Duration::hours(24 * frac)).expect("Could not add two dates together"); 
16    }
17    start_date.checked_add_signed(duration).unwrap()
18}
19
20pub fn adjust_formula(
21    base_reference: Reference,
22    current_reference: Reference,
23    formula_text: String,
24) -> Result<String, Error> {
25    let row_offset: i32 = current_reference.row() as i32 - base_reference.row() as i32;
26    let column_offset: i32 = current_reference.column() as i32 - base_reference.column() as i32;
27    let mut expression: Expr = parse_str(&formula_text)?; 
28    adjust_expression(row_offset, column_offset, &mut expression)?; 
29	Ok(format!("{}", expression))
30}
31
32pub fn adjust_expression(
33    row_offset: i32, 
34    column_offset: i32, 
35    expression: &mut Expr
36) -> Result<(), Error> {
37    match *expression {
38        Expr::Reference { sheet: _, ref mut reference } => {
39            let mut r = Reference::from(reference.to_string());
40			r.offset((row_offset, column_offset));
41			*reference = r.to_string(); 
42        }, 
43        Expr::Infix(_, ref mut a, ref mut b) => {
44            adjust_expression(row_offset, column_offset, a)?; 
45            adjust_expression(row_offset, column_offset, b)?; 
46        }, 
47        Expr::Prefix(_, ref mut a) => {
48            adjust_expression(row_offset, column_offset, a)?; 
49        }, 
50        Expr::Func { name: _, ref mut args } => {
51            for arg in args.iter_mut() {
52                adjust_expression(row_offset, column_offset, arg)?; 
53            } 
54        }, 
55        Expr::Array(ref mut arr) => {
56            for a in arr.iter_mut() {
57                adjust_expression(row_offset, column_offset, a)?; 
58            }
59        }
60        _ => {}
61    }
62    Ok(())
63}
64
65#[cfg(test)]
66mod tests {
67    use crate::reference::Reference; 
68    use crate::utils::adjust_formula; 
69    use crate::errors::Error; 
70    
71    #[test]
72    fn test_adjust_formula() -> Result<(), Error> {
73       let base_reference = Reference::from((1, 1));
74       let current_reference = Reference::from((2, 1));
75       assert_eq!(&adjust_formula(base_reference, current_reference, String::from("Sheet1!A1"))?, &"Sheet1!A2"); 
76       assert_eq!(&adjust_formula(base_reference, current_reference, String::from("A1+A2"))?, &"(A2+A3)"); 
77       assert_eq!(&adjust_formula(base_reference, current_reference, String::from("SUM(A1+A2)"))?, &"SUM((A2+A3))"); 
78       assert_eq!(&adjust_formula(base_reference, current_reference, String::from("{A1, A2}"))?, &"{A2, A3}"); 
79        Ok(())
80    }
81
82    #[test]
83    fn test_adjust_formula_anchored() -> Result<(), Error> {
84       let base_reference = Reference::from((1, 1));
85       let current_reference = Reference::from((2, 2));
86       assert_eq!(&adjust_formula(base_reference, current_reference, String::from("Sheet1!$A$1"))?, &"Sheet1!$A$1"); 
87       assert_eq!(&adjust_formula(base_reference, current_reference, String::from("$A$1+A2"))?, &"($A$1+B3)"); 
88       assert_eq!(&adjust_formula(base_reference, current_reference, String::from("SUM(A$1+A$2)"))?, &"SUM((B$1+B$2))"); 
89       assert_eq!(&adjust_formula(base_reference, current_reference, String::from("{A1, A2}"))?, &"{B2, B3}"); 
90        Ok(())
91    }
92}