Add an error management in db module
[recipes.git] / backend / src / db.rs
1 use std::path::Path;
2 use std::fs;
3
4 //use rusqlite::types::ToSql;
5 //use rusqlite::{Connection, Result, NO_PARAMS};
6
7 //extern crate r2d2;
8 //extern crate r2d2_sqlite;
9 //extern crate rusqlite;
10
11 use r2d2_sqlite::SqliteConnectionManager;
12 use r2d2::Pool;
13
14 #[derive(Debug)]
15 pub enum DbError {
16 SqliteError(rusqlite::Error),
17 R2d2Error(r2d2::Error),
18 UnsupportedVersion(i32),
19 }
20
21 use super::consts;
22
23 const CURRENT_DB_VERSION: u32 = 1;
24
25 pub struct Connection {
26 //con: rusqlite::Connection
27 pool: Pool<SqliteConnectionManager>
28 }
29
30 pub struct Recipe {
31 pub title: String,
32 pub id: i32,
33 }
34
35 impl std::convert::From<rusqlite::Error> for DbError {
36 fn from(error: rusqlite::Error) -> Self {
37 DbError::SqliteError(error)
38 }
39 }
40
41 impl std::convert::From<r2d2::Error> for DbError {
42 fn from(error: r2d2::Error) -> Self {
43 DbError::R2d2Error(error)
44 }
45 }
46
47 impl Connection {
48 pub fn new() -> Result<Connection, DbError> {
49
50 let data_dir = Path::new(consts::DB_DIRECTORY);
51
52 if !data_dir.exists() {
53 fs::DirBuilder::new().create(data_dir).unwrap();
54 }
55
56 let manager = SqliteConnectionManager::file("file.db");
57 let pool = r2d2::Pool::new(manager).unwrap();
58
59 let connection = Connection { pool };
60 connection.create_or_update()?;
61 Ok(connection)
62 }
63
64 /*
65 * Called after the connection has been established for creating or updating the database.
66 * The 'Version' table tracks the current state of the database.
67 */
68 fn create_or_update(self: &Self) -> Result<(), DbError> {
69 // let connection = Connection::new();
70 // let mut stmt = connection.sqlite_con.prepare("SELECT * FROM versions ORDER BY date").unwrap();
71 // let mut stmt = connection.sqlite_con.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='versions'").unwrap();
72
73 // Check the Database version.
74 let mut con = self.pool.get()?;
75 let tx = con.transaction()?;
76
77 let mut version = {
78 match tx.query_row(
79 "SELECT [name] FROM [sqlite_master] WHERE [type] = 'table' AND [name] = 'Version'",
80 rusqlite::NO_PARAMS,
81 |row| row.get::<usize, String>(0)
82 ) {
83 Ok(_) => tx.query_row("SELECT [version] FROM [Version]", rusqlite::NO_PARAMS, |row| row.get(0)).unwrap_or_default(),
84 Err(_) => 0
85 }
86 };
87
88 while Connection::update_to_next_version(version, &tx)? {
89 version += 1;
90 }
91
92 tx.commit()?;
93
94 Ok(())
95 }
96
97 fn update_to_next_version(version: i32, tx: &rusqlite::Transaction) -> Result<bool, DbError> {
98 match version {
99 0 => {
100 println!("Update to version 1...");
101
102 // Initial structure.
103 tx.execute_batch(
104 "
105 CREATE TABLE [Version] (
106 [id] INTEGER PRIMARY KEY,
107 [version] INTEGER NOT NULL UNIQUE,
108 [datetime] INTEGER DATETIME
109 );
110
111 CREATE TABLE [Recipe] (
112 [id] INTEGER PRIMARY KEY,
113 [title] INTEGER NOT NULL,
114 [description] INTEGER DATETIME
115 );
116 "
117 )?;
118
119 /*
120 tx.execute(
121 "
122 INSERT INTO Version
123 ",
124 rusqlite::NO_PARAMS
125 );*/
126
127 Ok(true)
128 }
129
130 // Current version.
131 1 =>
132 Ok(false),
133
134 v =>
135 Err(DbError::UnsupportedVersion(v)),
136 }
137 }
138
139 pub fn get_all_recipes() {
140
141 }
142 }