diff --git a/Cargo.lock b/Cargo.lock index c4150d6..754bbc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1244,6 +1244,8 @@ dependencies = [ "deadpool-postgres", "env_logger", "log", + "r2d2", + "r2d2_sqlite", "rusqlite", "serde", "sqlx", @@ -1644,6 +1646,27 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r2d2" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +dependencies = [ + "log", + "parking_lot 0.12.1", + "scheduled-thread-pool", +] + +[[package]] +name = "r2d2_sqlite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4f5d0337e99cd5cacd91ffc326c6cc9d8078def459df560c4f9bf9ba4a51034" +dependencies = [ + "r2d2", + "rusqlite", +] + [[package]] name = "rand" version = "0.8.5" @@ -1786,6 +1809,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "scheduled-thread-pool" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "977a7519bff143a44f842fd07e80ad1329295bd71686457f18e496736f4bf9bf" +dependencies = [ + "parking_lot 0.12.1", +] + [[package]] name = "scopeguard" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 9265f8d..b1389b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,8 @@ serde = "1.0.8" deadpool-postgres = { version = "0.10.2", features = ["serde"] } tokio-postgres = "0.7.6" rusqlite = { version = "0.28.0", features = ["bundled"] } +r2d2 = "0.8" +r2d2_sqlite = "0.21" actix-files = "0.6" env_logger = "0.9.0" log = "0.4" \ No newline at end of file diff --git a/src/cats/db/mod.rs b/src/cats/db/mod.rs index 608a82a..075c636 100644 --- a/src/cats/db/mod.rs +++ b/src/cats/db/mod.rs @@ -1,8 +1,7 @@ -use rusqlite::{Connection, Error, Result}; +use rusqlite::{Error, Result}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; - #[derive(Debug, Serialize, Deserialize)] pub struct Cat { id: i32, @@ -20,64 +19,69 @@ pub type CatsResult = Result, Error>; pub type ColorsResult = Result, Error>; pub type CatResult = Result; pub type ColorResult = Result; +pub type Pool = r2d2::Pool; // Сервис базы данных - -pub struct Service { - db: rusqlite::Connection, +#[derive(std::clone::Clone)] +pub struct Db { + pool: Pool, } -impl Service { + +impl Db { + pub async fn new(pool: Pool) -> Db { + return Db { pool: pool }; + } // Создание сервиса - pub fn new() -> Service { - let conn = Connection::open("cats.db"); - let db_con = match conn { + pub async fn init(&self) { + let conn = match self.pool.get() { Ok(conn) => conn, - Err(error) => panic!("Problem opening the db: {:?}", error), + Err(err) => panic!("{}", err), }; - db_con - .execute( - "create table if not exists cat_colors ( + + conn.execute( + "create table if not exists cat_colors ( id integer primary key, name text not null unique )", - [], - ) - .ok(); - db_con - .execute( - "create table if not exists cats ( + [], + ) + .ok(); + conn.execute( + "create table if not exists cats ( id integer primary key, name text not null, color_id integer not null references cat_colors(id) )", - [], - ) - .ok(); + [], + ) + .ok(); let mut cat_colors = HashMap::new(); cat_colors.insert(String::from("Blue"), vec!["Tigger", "Sammy"]); cat_colors.insert(String::from("Black"), vec!["Oreo", "Biscuit"]); for (color, catnames) in &cat_colors { - db_con - .execute( - "INSERT INTO cat_colors (name) values (?1)", - &[&color.to_string()], + conn.execute( + "INSERT INTO cat_colors (name) values (?1)", + &[&color.to_string()], + ) + .ok(); + let last_id: String = conn.last_insert_rowid().to_string(); + for cat in catnames { + conn.execute( + "INSERT INTO cats (name, color_id) values (?1, ?2)", + &[&cat.to_string(), &last_id], ) .ok(); - let last_id: String = db_con.last_insert_rowid().to_string(); - for cat in catnames { - db_con - .execute( - "INSERT INTO cats (name, color_id) values (?1, ?2)", - &[&cat.to_string(), &last_id], - ) - .ok(); } } - return Service { db: db_con }; } + // Получение кошек pub fn get_cats(&self) -> CatsResult { - let mut stmt = self.db.prepare( + let conn = match self.pool.get() { + Ok(conn) => conn, + Err(err) => panic!("{}", err), + }; + let mut stmt = conn.prepare( "SELECT c.id, c.name, cc.name from cats c INNER JOIN cat_colors cc ON cc.id = c.color_id;", )?; return stmt @@ -93,7 +97,11 @@ impl Service { // Получение цветов pub fn get_colors(&self) -> ColorsResult { - let mut stmt = self.db.prepare("SELECT id, name from cat_colors")?; + let conn = match self.pool.get() { + Ok(conn) => conn, + Err(err) => panic!("{}", err), + }; + let mut stmt = conn.prepare("SELECT id, name from cat_colors")?; return stmt .query_map([], |row| { Ok(Color { @@ -106,7 +114,11 @@ impl Service { // Добавление кошки pub fn add_cat(&self, cat_name: String, cat_color: String) -> CatResult { - return self.db.query_row("INSERT INTO cats (name, color_id) SELECT ?1, id FROM cat_colors cc WHERE name = ?2 RETURNING id, name, ?2", + let conn = match self.pool.get() { + Ok(conn) => conn, + Err(err) => panic!("{}", err), + }; + return conn.query_row("INSERT INTO cats (name, color_id) SELECT ?1, id FROM cat_colors cc WHERE name = ?2 RETURNING id, name, ?2", [cat_name, cat_color], |row| { Ok(Cat { @@ -119,7 +131,11 @@ impl Service { } // Добавление цвета pub fn add_color(&self, color_name: String) -> ColorResult { - return self.db.query_row( + let conn = match self.pool.get() { + Ok(conn) => conn, + Err(err) => panic!("{}", err), + }; + return conn.query_row( "INSERT INTO cat_colors (name) VALUES (?1) RETURNING id, name", [color_name], |row| { diff --git a/src/cats/mod.rs b/src/cats/mod.rs index 2b018f6..f652aca 100644 --- a/src/cats/mod.rs +++ b/src/cats/mod.rs @@ -1,35 +1,32 @@ pub mod db; -use actix_web::{get,post, web, HttpResponse, Responder, Result}; +use db::{Db}; +use actix_web::{get, post, web, HttpResponse, Responder, Result}; use serde::{Deserialize, Serialize}; -pub struct Service { - pub db: db::Service, -} - #[derive(Serialize)] struct ArrayResponse { result: Vec, } - #[derive(Debug, Serialize, Deserialize)] pub struct AddColorRequest { pub name: String, } #[get("/cats")] -pub async fn get_cats(ctx: web::Data) -> Result { - let cats = ctx.db.get_cats(); +pub async fn get_cats(db: web::Data) -> Result { + + let cats = db.get_cats(); let res = match cats { - Ok(v) => ArrayResponse{ result: v }, + Ok(v) => ArrayResponse { result: v }, Err(_err) => ArrayResponse { result: vec![] }, }; return Ok(HttpResponse::Ok().json(res)); } #[get("/colors")] -pub async fn get_colors(ctx: web::Data) -> Result { - let colors = ctx.db.get_colors(); +pub async fn get_colors(db: web::Data) -> Result { + let colors = db.get_colors(); let res = match colors { Ok(v) => ArrayResponse { result: v }, Err(_err) => ArrayResponse { result: vec![] }, @@ -43,14 +40,13 @@ pub struct AddCatRequest { pub color: String, } - #[post("/add/cat")] pub async fn add_cat( - ctx: web::Data, + db: web::Data, cat: web::Json, ) -> Result { let _cat = cat.into_inner(); - let cat = ctx.db.add_cat(_cat.name, _cat.color); + let cat = db.add_cat(_cat.name, _cat.color); let res = match cat { Ok(v) => ArrayResponse { result: vec![v] }, Err(_err) => panic!("{:?}", _err), @@ -60,15 +56,14 @@ pub async fn add_cat( #[post("/add/color")] pub async fn add_color( - ctx: web::Data, + db: web::Data, cat: web::Json, ) -> Result { let _color = cat.into_inner(); - let cat = ctx.db.add_color(_color.name); + let cat = db.add_color(_color.name); let res = match cat { Ok(v) => ArrayResponse { result: vec![v] }, Err(_err) => panic!("{:?}", _err), }; return Ok(HttpResponse::Ok().json(res)); } - diff --git a/src/main.rs b/src/main.rs index 43fb783..6c00969 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,10 @@ use config::Config; -mod cfg; mod cats; +mod cfg; use actix_files::Files; -use actix_web::{web, App, HttpServer}; +use actix_web::{middleware, web, App, HttpServer}; +use cats::db::{Db, Pool}; +use r2d2_sqlite::{self, SqliteConnectionManager}; #[actix_web::main] pub async fn main() -> std::io::Result<()> { @@ -18,11 +20,15 @@ pub async fn main() -> std::io::Result<()> { env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); log::info!("starting HTTP server at http://{}:{}", app.host, app.port); - HttpServer::new(|| { + let manager = SqliteConnectionManager::file("cats.db"); + let pool = Pool::new(manager).unwrap(); + let db = Db::new(pool.clone()).await; + db.init().await; + + HttpServer::new(move || { App::new() - .app_data(web::Data::new(cats::Service { - db: cats::db::Service::new(), - })) + .app_data(web::Data::new(db.clone())) + .wrap(middleware::Logger::default()) .service(cats::get_cats) .service(cats::get_colors) .service(cats::add_cat)