easy_sqlite/impls/
table_manager.rs1use rusqlite::Connection;
2use std::marker::PhantomData;
3
4use crate::entities::errors::{DbError, DbResult};
5use crate::entities::types::SStr;
6use crate::traits::repo::{IConnection, IDbRepo, IExecutor, INewDbRepo};
7use crate::traits::table::ITable;
8
9pub struct TableManager<Cnn, Tbl> {
10 pub connection: Cnn,
11 table: PhantomData<Tbl>,
12}
13
14impl<Cnn: Clone, Tbl> Clone for TableManager<Cnn, Tbl> {
15 fn clone(&self) -> Self {
16 Self {
17 connection: self.connection.clone(),
18 table: Default::default(),
19 }
20 }
21}
22
23impl<Cnn, Tbl: ITable> TableManager<Cnn, Tbl> {
24 fn create_query(&self) -> String {
25 let columns = Tbl::COLUMNS
26 .iter()
27 .map(|(c_name, c_type)| format!("`{}` {}", c_name, c_type));
28 let unique = Tbl::UNIQUE.iter().map(Self::wrap_unique);
29 let f_keys = Tbl::FOREIGN_KEYS.iter().map(|(column, table, ext_column)| {
30 format!(
31 "FOREIGN KEY (`{}`) REFERENCES `{}`(`{}`)",
32 column, table, ext_column,
33 )
34 });
35 let attrs = columns
36 .chain(unique)
37 .chain(f_keys)
38 .collect::<Vec<_>>()
39 .join(", ");
40 format!("CREATE TABLE IF NOT EXISTS `{}` ({})", Tbl::NAME, attrs,)
41 }
42
43 fn wrap_unique(fields: &SStr) -> String {
44 let fields = fields
45 .split(',')
46 .map(|field| format!("`{}`", field.trim()))
47 .collect::<Vec<_>>()
48 .join(",");
49 format!("UNIQUE({})", fields)
50 }
51
52 fn make_index_name(&self, field: &str) -> String {
53 format!("{}_{}_index", Tbl::NAME, field)
54 }
55}
56
57impl<Cnn, Tbl: ITable> INewDbRepo<Cnn> for TableManager<Cnn, Tbl> {
58 fn create(connection: Cnn) -> Self {
59 Self {
60 connection,
61 table: Default::default(),
62 }
63 }
64}
65
66impl<Cnn: IConnection + IExecutor, Tbl: ITable> IDbRepo for TableManager<Cnn, Tbl> {
67 fn init(&self) -> DbResult<()> {
68 match self.connection.execute(&self.create_query(), &[]) {
69 Err(DbError::Other(msg)) => Err(DbError::CanNotInitTable(Tbl::NAME, msg)),
70 other => other,
71 }
72 }
73
74 fn drop(&self) -> DbResult<()> {
75 let query = format!("DROP TABLE IF EXISTS `{}`", Tbl::NAME);
76 self.connection.execute(&query, &[])
77 }
78
79 fn set_indexes(&self) -> DbResult<()> {
80 let fun = |cnn: &Connection| -> DbResult<()> {
81 for column in Tbl::INDEXES.iter() {
82 let index = self.make_index_name(column);
83 let query = format!(
84 "CREATE INDEX IF NOT EXISTS {} ON `{}` (`{}`)",
85 index,
86 Tbl::NAME,
87 column,
88 );
89 cnn.execute(&query, ())?;
90 }
91 Ok(())
92 };
93 self.connection.with(fun)
94 }
95
96 fn drop_indexes(&self) -> DbResult<()> {
97 let fun = |cnn: &Connection| -> DbResult<()> {
98 for column in Tbl::INDEXES.iter() {
99 let index = self.make_index_name(column);
100 let query = format!("DROP INDEX IF EXISTS {}", index);
101 cnn.execute(&query, ())?;
102 }
103 Ok(())
104 };
105 self.connection.with(fun)
106 }
107
108 fn get_size(&self) -> DbResult<usize> {
109 let query = format!("SELECT COUNT(*) FROM `{}`", Tbl::NAME);
110 let fun = move |cnn: &Connection| -> DbResult<usize> {
111 let mut stm = cnn.prepare(&query)?;
112 let mut rows = stm.raw_query();
113 Ok(rows.next()?.unwrap().get(0)?)
114 };
115 self.connection.with(fun)
116 }
117}