· 7 years ago · Dec 12, 2018, 11:50 PM
1use rusqlite::{Result, Connection, Error};
2use rusqlite::Error::{QueryReturnedNoRows};
3use tools::variant_eq;
4use std::path::Path;
5use inventory::{Product};
6
7pub struct Proxy {
8 conn: Connection
9}
10
11impl Proxy {
12 pub fn new(path: &str) -> Proxy {
13 Proxy {
14 conn: Proxy::connect(
15 Path::new(path)
16 )
17 }
18 }
19 ///Connects to Database and creates tables
20 fn connect<P: AsRef<Path>>(path: P) -> Connection {
21 let conn = Connection::open(path).unwrap();
22 let tables = vec![
23 "CREATE TABLE IF NOT EXISTS Inventory (
24 product_id STRING PRIMARY KEY,
25 name STRING NOT NULL,
26 amount INTEGER
27 )",
28 "CREATE TABLE IF NOT EXISTS Employee (
29 product_id STRING NOT NULL,
30 employee_id STRING NOT NULL,
31 po STRING NOT NULL,
32 amount INTEGER
33 )",
34 "CREATE TABLE IF NOT EXISTS Customer (
35 product_id STRING NOT NULL,
36 customer_id STRING NOT NULL,
37 po STRING NOT NULL,
38 amount INTEGER
39 )"
40 ];
41 for table in tables {
42 conn.execute(table, &[],).unwrap();
43 }
44 return conn
45 }
46 /// Allows for handling of expected error
47 /// #Panics
48 /// Unexpected Err
49 fn send_query<R, F: Fn()->Result<R>>(&self, query: F, expect_error: Option<Error>) -> Option<R> {
50 let result = query();
51 match (result, expect_error) {
52 (Ok(val), _) => Some(val),
53 (Err(ref err), Some(ref expect_err)) if variant_eq(err, expect_err) => None,
54 (Err(err), _) => panic!("An unexpected error has occured: {}", err)
55 }
56 }
57 /// Adds product to db
58 /// #Panics
59 /// If product already exists
60 pub fn add_product(&self, product: &Product) -> Result<()>{
61 let addr = product.get_address();
62 if let "Inventory" = addr.table {
63 let query_string = make_insert_query("Inventory", vec![addr.column, "name", "amount"]);
64 let command = || { self.conn.execute(&query_string, &[&product.id, &product.name, &0,]) };
65 self.send_query(command, Some(QueryReturnedNoRows));
66 } else {
67 let query_string = make_insert_query(addr.table, vec!["product_id", addr.column, "po", "amount"]);
68 let command = || { self.conn.execute(&query_string, &[&product.id, &addr.id, &product.po.unwrap(), &0,]) };
69 self.send_query(command, Some(QueryReturnedNoRows));
70 };
71 Ok(())
72 }
73 /// Removes product from db
74 /// #Panics
75 /// If product does not exist
76 pub fn remove_product(&self, product: &Product) -> Result<()> {
77 let addr = product.get_address();
78 let query = format!("DELETE FROM {} WHERE {}=?1", addr.table, addr.column);
79 self.send_query( || {
80 self.conn.execute(&query, &[&addr.id],)
81 }, None
82 );
83 Ok(())
84 }
85 /// Adds amount to product stock
86 /// #Panics
87 /// If product does not exist
88 pub fn add_stock(&self, product: &Product, amount: i64) -> Result<()> {
89 let addr = product.get_address();
90 let query = format!("UPDATE {} SET amount = amount+?2 WHERE {} = ?1", addr.table, addr.column);
91 self.send_query(|| {
92 self.conn.execute(&query, &[&addr.id, &amount],)
93 }, None
94 );
95 Ok(())
96 }
97 /// Removes amount from product stock
98 /// #Panics
99 /// If product does not exist
100 pub fn remove_stock(&self, product: &Product, amount: i64) -> Result<()>{
101 self.add_stock(&product, -amount)
102 }
103
104 /// Gets stock of product
105 /// #Expects
106 /// QueryReturnedNoRows
107 /// #Panics
108 /// Anything else
109 //TODO account for multiple PO
110 pub fn get_amount(&self, product: &Product) -> Option<i64> {
111 let addr = product.get_address();
112 let query = format!("SELECT amount FROM {} WHERE {}=?", addr.table, addr.column);
113 let mut stmnt = self.conn.prepare(&query).expect("Could not prepare statement");
114 let command = stmnt.query_map_named::<i64, _>(&[(&addr.id, &"one")], |row| row.get(0),);
115 //let result = self.send_query(command, Some(QueryReturnedNoRows));
116 if let Ok(r) = command {
117 let mut total = 0;
118 for n in r {
119 println!("found amount: {:?}", &n);
120 total += n.expect("Invalid Stock Type");
121 }
122 Some(total)
123
124 } else { None }
125 }
126 /// Checks if a product exists in db
127 /// #Expects
128 /// QueryReturnedNoRows
129 /// #Panics
130 /// Anything else
131 pub fn check_exists(&self, product: &Product) -> bool {
132 self.get_amount(product).is_some()
133 }
134
135 pub fn close(self) -> Result<()>{
136 self.conn.close().expect("Unable to close connection");
137 Ok(())
138 }
139}
140
141fn make_insert_query(table: &str, args: Vec<&str>) -> String {
142 let placeholders: Vec<String> = (0..args.len())
143 .map(|_| String::from("?"))
144 .collect();
145
146 format!(
147 "INSERT INTO {} ({}) VALUES ({})",
148 table,
149 args.join(","),
150 placeholders.join(",")
151 )
152}