CLI
This commit is contained in:
72
Cargo.lock
generated
72
Cargo.lock
generated
@@ -19,6 +19,26 @@ dependencies = [
|
|||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atty"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -77,6 +97,21 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "2.34.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||||
|
dependencies = [
|
||||||
|
"ansi_term",
|
||||||
|
"atty",
|
||||||
|
"bitflags",
|
||||||
|
"strsim",
|
||||||
|
"textwrap",
|
||||||
|
"unicode-width",
|
||||||
|
"vec_map",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codepage"
|
name = "codepage"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@@ -157,6 +192,15 @@ dependencies = [
|
|||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.109"
|
version = "0.2.109"
|
||||||
@@ -285,6 +329,12 @@ version = "1.7.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.82"
|
version = "1.0.82"
|
||||||
@@ -296,6 +346,15 @@ dependencies = [
|
|||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textwrap"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.30"
|
version = "1.0.30"
|
||||||
@@ -327,6 +386,12 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -339,6 +404,12 @@ version = "0.2.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vec_map"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
@@ -379,6 +450,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"calamine",
|
"calamine",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"clap",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
calamine = "0.18.0"
|
calamine = "0.18.0"
|
||||||
chrono = "0.4.19"
|
chrono = "0.4.19"
|
||||||
|
clap = { version = "2.34.0"}
|
||||||
rusqlite = { version = "0.26.3", features = ["bundled"] }
|
rusqlite = { version = "0.26.3", features = ["bundled"] }
|
||||||
smallvec = "1.7.0"
|
smallvec = "1.7.0"
|
||||||
|
|
||||||
|
|||||||
64
sql/get_top.sql
Normal file
64
sql/get_top.sql
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
SELECT
|
||||||
|
description,
|
||||||
|
sku,
|
||||||
|
level2,
|
||||||
|
level3,
|
||||||
|
revenue,
|
||||||
|
quantity,
|
||||||
|
trend
|
||||||
|
from
|
||||||
|
(
|
||||||
|
SELECT
|
||||||
|
*,
|
||||||
|
ROW_NUMBER () OVER (
|
||||||
|
PARTITION BY level2
|
||||||
|
ORDER BY
|
||||||
|
SUM(revenue) DESC
|
||||||
|
) rownum,
|
||||||
|
SUM(revenue) OVER (PARTITION BY level2) total,
|
||||||
|
ROUND(SUM(revenue), 2) as revenue,
|
||||||
|
SUM(quantity) as quantity,
|
||||||
|
trend
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
select
|
||||||
|
*,
|
||||||
|
cast(past as float) / 3 as past,
|
||||||
|
round(
|
||||||
|
cast(present as float) /(cast(past as float) / 3.0),
|
||||||
|
2
|
||||||
|
) as trend
|
||||||
|
from
|
||||||
|
(
|
||||||
|
select
|
||||||
|
*,
|
||||||
|
sum(quantity) FILTER (
|
||||||
|
WHERE
|
||||||
|
year = $year
|
||||||
|
and month between $($month - 4)
|
||||||
|
and $($month - 1)
|
||||||
|
) over (PARTITION BY description) as past,
|
||||||
|
sum(quantity) FILTER (
|
||||||
|
WHERE
|
||||||
|
year = $year
|
||||||
|
and month = %[2]s
|
||||||
|
) over (PARTITION BY description) as present
|
||||||
|
from
|
||||||
|
data
|
||||||
|
)
|
||||||
|
)
|
||||||
|
where
|
||||||
|
year = %[1]s
|
||||||
|
and month = %[2]s
|
||||||
|
GROUP BY
|
||||||
|
description
|
||||||
|
ORDER BY
|
||||||
|
total DESC
|
||||||
|
)
|
||||||
|
WHERE
|
||||||
|
rownum <= 10
|
||||||
|
and revenue > 0
|
||||||
|
order by
|
||||||
|
(sum(revenue) over (
|
||||||
|
partition by level2
|
||||||
|
)) desc;
|
||||||
137
src/converter/mod.rs
Normal file
137
src/converter/mod.rs
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
use std::{error::Error};
|
||||||
|
use std::{collections::HashMap};
|
||||||
|
|
||||||
|
use rusqlite::{Connection, Result};
|
||||||
|
use calamine::{open_workbook, Reader, Xlsx,DataType};
|
||||||
|
|
||||||
|
use super::types::Data;
|
||||||
|
|
||||||
|
const SCHEMA: &str = r#"CREATE TABLE IF NOT EXISTS data (
|
||||||
|
description text,
|
||||||
|
sku text,
|
||||||
|
level2 text,
|
||||||
|
level3 text,
|
||||||
|
revenue float,
|
||||||
|
cost float,
|
||||||
|
quantity integer,
|
||||||
|
year integer,
|
||||||
|
month integer
|
||||||
|
);
|
||||||
|
"#;
|
||||||
|
|
||||||
|
pub fn convert_excel(path: &str) -> Result<(),Box<dyn Error>> {
|
||||||
|
let r = get_excel(path)?;
|
||||||
|
let (indexs,skip_count) = get_index(&r);
|
||||||
|
let data_vec = parse_data(&r,indexs,skip_count)?;
|
||||||
|
write_sql(&data_vec)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_excel(path: &str) -> Result<calamine::Range<DataType>, Box<dyn Error>> {
|
||||||
|
let mut excel: Xlsx<_> = open_workbook(path)?;
|
||||||
|
let r = excel
|
||||||
|
.worksheet_range("Export")
|
||||||
|
.expect("Is There")
|
||||||
|
?;
|
||||||
|
Ok(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_index(r: &calamine::Range<DataType>) -> (HashMap<&'static str, usize>,usize) {
|
||||||
|
let mut indexs = HashMap::new();
|
||||||
|
let mut skip_count = 0;
|
||||||
|
'outer: for row in r.rows() {
|
||||||
|
skip_count += 1;
|
||||||
|
for (i, elm) in row.iter().enumerate() {
|
||||||
|
let header = elm.get_string().expect("header issue");
|
||||||
|
match header {
|
||||||
|
"FiscalYearMonth" => indexs.insert("date", i),
|
||||||
|
"Level2" => indexs.insert("level2", i),
|
||||||
|
"Level3" => indexs.insert("level3", i),
|
||||||
|
"MaterialEntered" => indexs.insert("sku", i),
|
||||||
|
"Quantity" => indexs.insert("quantity", i),
|
||||||
|
"SalesRevenue" => indexs.insert("revenue", i),
|
||||||
|
"CostOfGoodsSold" => indexs.insert("cost", i),
|
||||||
|
"ProductDescription" => indexs.insert("description", i),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if indexs.len() == 8 {
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(indexs,skip_count)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_data(r: &calamine::Range<DataType>, indexs: HashMap<&str,usize>, skip_count: usize) -> Result<Vec<Data>,Box<dyn Error>> {
|
||||||
|
let mut data_vec = Vec::with_capacity(100000);
|
||||||
|
for row in r.rows().skip(skip_count) {
|
||||||
|
if row[indexs["sku"]].get_string() == None {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let datestring = row[indexs["date"]].get_string().expect("Date Parsing Issue");
|
||||||
|
let year = datestring[0..4].parse::<i64>()?;
|
||||||
|
let month = datestring[5..].parse::<i64>()?;
|
||||||
|
data_vec.push(Data {
|
||||||
|
description: String::from(row[indexs["description"]].get_string().unwrap().replace("\"", "")),
|
||||||
|
sku: String::from(row[indexs["sku"]].get_string().unwrap()),
|
||||||
|
level2: String::from(row[indexs["level2"]].get_string().unwrap()),
|
||||||
|
level3: String::from(row[indexs["level3"]].get_string().unwrap()),
|
||||||
|
revenue: match row[indexs["revenue"]].get_float() {
|
||||||
|
Some(x) => x,
|
||||||
|
None => match row[indexs["revenue"]].get_int() {
|
||||||
|
Some(x) => x as f64,
|
||||||
|
None => 0.0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cost: match row[indexs["cost"]].get_float() {
|
||||||
|
Some(x) => x,
|
||||||
|
None => match row[indexs["cost"]].get_int() {
|
||||||
|
Some(x) => x as f64,
|
||||||
|
None => 0.0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
quantity: match row[indexs["quantity"]].get_int() {
|
||||||
|
Some(x) => x,
|
||||||
|
None => match row[indexs["quantity"]].get_float() {
|
||||||
|
Some(x) => x as i64,
|
||||||
|
None => 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
year: year,
|
||||||
|
month: month,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(data_vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_sql(data_vec: &Vec<Data>) -> Result<(), Box<dyn Error>> {
|
||||||
|
let conn = Connection::open("data.db")?;
|
||||||
|
conn.execute("DROP TABLE IF EXISTS data;", [])?;
|
||||||
|
conn.execute(SCHEMA, [])?;
|
||||||
|
|
||||||
|
let mut inserts = Vec::with_capacity(100000);
|
||||||
|
|
||||||
|
inserts.push(String::from("INSERT INTO data (description,sku,level2,level3,revenue,cost,quantity,year,month) VALUES "));
|
||||||
|
|
||||||
|
for row in data_vec {
|
||||||
|
let other: String = format!(
|
||||||
|
"(\"{}\",\"{}\",\"{}\",\"{}\",{},{},{},{},{}),",
|
||||||
|
row.description,
|
||||||
|
row.sku,
|
||||||
|
row.level2,
|
||||||
|
row.level3,
|
||||||
|
row.revenue,
|
||||||
|
row.cost,
|
||||||
|
row.quantity,
|
||||||
|
row.year,
|
||||||
|
row.month
|
||||||
|
);
|
||||||
|
inserts.push(other);
|
||||||
|
}
|
||||||
|
let mut ins = inserts.join("");
|
||||||
|
ins.pop();
|
||||||
|
ins.push(';');
|
||||||
|
|
||||||
|
conn.execute(&ins, [])?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
171
src/main.rs
171
src/main.rs
@@ -1,135 +1,58 @@
|
|||||||
use std::{collections::HashMap, error::Error};
|
use std::error::Error;
|
||||||
|
|
||||||
use calamine::{open_workbook, Reader, Xlsx};
|
mod converter;
|
||||||
use rusqlite::{Connection, Result};
|
mod types;
|
||||||
|
|
||||||
const SCHEMA: &str = r#"CREATE TABLE IF NOT EXISTS data (
|
use clap::{App, Arg, SubCommand};
|
||||||
description text,
|
|
||||||
sku text,
|
|
||||||
level2 text,
|
|
||||||
level3 text,
|
|
||||||
revenue float,
|
|
||||||
cost float,
|
|
||||||
quantity integer,
|
|
||||||
year integer,
|
|
||||||
month integer
|
|
||||||
);
|
|
||||||
"#;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Data {
|
|
||||||
description: String,
|
|
||||||
sku: String,
|
|
||||||
level2: String,
|
|
||||||
level3: String,
|
|
||||||
revenue: f64,
|
|
||||||
cost: f64,
|
|
||||||
quantity: i64,
|
|
||||||
year: i64,
|
|
||||||
month: i64,
|
|
||||||
}
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let now = chrono::offset::Local::now();
|
let mut app = App::new("xlr")
|
||||||
let mut data_vec = Vec::with_capacity(100000);
|
.arg(
|
||||||
let mut excel: Xlsx<_> = open_workbook("data.xlsx").unwrap();
|
Arg::with_name("convert")
|
||||||
let r = excel
|
.short("c")
|
||||||
.worksheet_range("Export")
|
.long("convert")
|
||||||
.expect("Is There")
|
.value_name("FILE")
|
||||||
.expect("Excel Read Error");
|
.help("File to convert")
|
||||||
|
.takes_value(true),
|
||||||
let mut indexs = HashMap::new();
|
)
|
||||||
let mut skip_count = 0;
|
.arg(
|
||||||
'outer: for row in r.rows() {
|
Arg::with_name("get-top")
|
||||||
skip_count += 1;
|
.short("gt")
|
||||||
for (i, elm) in row.iter().enumerate() {
|
.long("get-top")
|
||||||
let header = elm.get_string().expect("header issue");
|
.value_names(&["YEAR", "MONTH"])
|
||||||
match header {
|
.help("Year and month to get top info")
|
||||||
"FiscalYearMonth" => indexs.insert("date", i),
|
.takes_value(true),
|
||||||
"Level2" => indexs.insert("level2", i),
|
|
||||||
"Level3" => indexs.insert("level3", i),
|
|
||||||
"MaterialEntered" => indexs.insert("sku", i),
|
|
||||||
"Quantity" => indexs.insert("quantity", i),
|
|
||||||
"SalesRevenue" => indexs.insert("revenue", i),
|
|
||||||
"CostOfGoodsSold" => indexs.insert("cost", i),
|
|
||||||
"ProductDescription" => indexs.insert("description", i),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
if indexs.len() == 8 {
|
|
||||||
break 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for row in r.rows().skip(skip_count) {
|
|
||||||
if row[indexs["sku"]].get_string() == None {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let datestring = row[indexs["date"]].get_string().expect("Date Parsing Issue");
|
|
||||||
let year = datestring[0..4].parse::<i64>().unwrap();
|
|
||||||
let month = datestring[5..].parse::<i64>().unwrap();
|
|
||||||
data_vec.push(Data {
|
|
||||||
description: String::from(row[indexs["description"]].get_string().unwrap().replace("\"", "")),
|
|
||||||
sku: String::from(row[indexs["sku"]].get_string().unwrap()),
|
|
||||||
level2: String::from(row[indexs["level2"]].get_string().unwrap()),
|
|
||||||
level3: String::from(row[indexs["level3"]].get_string().unwrap()),
|
|
||||||
revenue: match row[indexs["revenue"]].get_float() {
|
|
||||||
Some(x) => x,
|
|
||||||
None => match row[indexs["revenue"]].get_int() {
|
|
||||||
Some(x) => x as f64,
|
|
||||||
None => 0.0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
cost: match row[indexs["cost"]].get_float() {
|
|
||||||
Some(x) => x,
|
|
||||||
None => match row[indexs["cost"]].get_int() {
|
|
||||||
Some(x) => x as f64,
|
|
||||||
None => 0.0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
quantity: match row[indexs["quantity"]].get_int() {
|
|
||||||
Some(x) => x,
|
|
||||||
None => match row[indexs["quantity"]].get_float() {
|
|
||||||
Some(x) => x as i64,
|
|
||||||
None => 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
year: year,
|
|
||||||
month: month,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let conn = Connection::open("data.db")?;
|
|
||||||
conn.execute("DROP TABLE IF EXISTS data;", [])?;
|
|
||||||
conn.execute(SCHEMA, [])?;
|
|
||||||
|
|
||||||
let mut inserts = Vec::with_capacity(100000);
|
|
||||||
|
|
||||||
inserts.push(String::from("INSERT INTO data (description,sku,level2,level3,revenue,cost,quantity,year,month) VALUES "));
|
|
||||||
|
|
||||||
for row in data_vec {
|
|
||||||
let other: String = format!(
|
|
||||||
"(\"{}\",\"{}\",\"{}\",\"{}\",{},{},{},{},{}),",
|
|
||||||
row.description,
|
|
||||||
row.sku,
|
|
||||||
row.level2,
|
|
||||||
row.level3,
|
|
||||||
row.revenue,
|
|
||||||
row.cost,
|
|
||||||
row.quantity,
|
|
||||||
row.year,
|
|
||||||
row.month
|
|
||||||
);
|
);
|
||||||
inserts.push(other);
|
|
||||||
|
let mut helpper = app.clone();
|
||||||
|
let matches = app.get_matches();
|
||||||
|
let mut did_run = false;
|
||||||
|
|
||||||
|
//Convert
|
||||||
|
match matches.value_of("convert") {
|
||||||
|
Some(val) => {
|
||||||
|
let now = chrono::offset::Local::now();
|
||||||
|
converter::convert_excel(val)?;
|
||||||
|
println!(
|
||||||
|
"{:?}",
|
||||||
|
(chrono::offset::Local::now() - now).num_milliseconds()
|
||||||
|
);
|
||||||
|
did_run = true;
|
||||||
|
},
|
||||||
|
None => {},
|
||||||
}
|
}
|
||||||
let mut ins = inserts.join("");
|
|
||||||
ins.pop();
|
|
||||||
ins.push(';');
|
|
||||||
|
|
||||||
conn.execute(&ins, [])?;
|
//Get Top
|
||||||
|
match matches.values_of("get-top") {
|
||||||
|
Some(vals) => {
|
||||||
|
did_run = true;
|
||||||
|
},
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
let after = chrono::offset::Local::now();
|
if !did_run {
|
||||||
let diff = after - now;
|
helpper.print_help().unwrap();
|
||||||
println!("{:?}", diff.num_milliseconds());
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/types/mod.rs
Normal file
12
src/types/mod.rs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Data {
|
||||||
|
pub description: String,
|
||||||
|
pub sku: String,
|
||||||
|
pub level2: String,
|
||||||
|
pub level3: String,
|
||||||
|
pub revenue: f64,
|
||||||
|
pub cost: f64,
|
||||||
|
pub quantity: i64,
|
||||||
|
pub year: i64,
|
||||||
|
pub month: i64,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user