From a72663ed26f5b330e35ccf6f7087c68a36af8324 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 6 Feb 2022 07:09:35 +0000 Subject: [PATCH] remove db/sqlx_todo example --- Cargo.toml | 1 - database_interactions/sqlx_todo/.env.example | 4 - database_interactions/sqlx_todo/.gitignore | 3 - database_interactions/sqlx_todo/Cargo.toml | 17 -- database_interactions/sqlx_todo/README.md | 43 ----- database_interactions/sqlx_todo/schema.sql | 5 - database_interactions/sqlx_todo/setup_db.sh | 2 - database_interactions/sqlx_todo/src/main.rs | 65 ------- .../sqlx_todo/src/todo/mod.rs | 5 - .../sqlx_todo/src/todo/model.rs | 177 ------------------ .../sqlx_todo/src/todo/routes.rs | 94 ---------- 11 files changed, 416 deletions(-) delete mode 100644 database_interactions/sqlx_todo/.env.example delete mode 100644 database_interactions/sqlx_todo/.gitignore delete mode 100644 database_interactions/sqlx_todo/Cargo.toml delete mode 100644 database_interactions/sqlx_todo/README.md delete mode 100644 database_interactions/sqlx_todo/schema.sql delete mode 100755 database_interactions/sqlx_todo/setup_db.sh delete mode 100644 database_interactions/sqlx_todo/src/main.rs delete mode 100644 database_interactions/sqlx_todo/src/todo/mod.rs delete mode 100644 database_interactions/sqlx_todo/src/todo/model.rs delete mode 100644 database_interactions/sqlx_todo/src/todo/routes.rs diff --git a/Cargo.toml b/Cargo.toml index 1c8bb569..e1cc88cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,6 @@ members = [ "database_interactions/r2d2", "database_interactions/redis", "database_interactions/simple-auth-server", - "database_interactions/sqlx_todo", "forms/form", "forms/multipart-s3", "forms/multipart", diff --git a/database_interactions/sqlx_todo/.env.example b/database_interactions/sqlx_todo/.env.example deleted file mode 100644 index 442b38c3..00000000 --- a/database_interactions/sqlx_todo/.env.example +++ /dev/null @@ -1,4 +0,0 @@ -HOST=127.0.0.1 -PORT=8080 -DATABASE_URL=sqlite://${CARGO_MANIFEST_DIR}/test.db -RUST_LOG=sqlx_todo=info,actix=info diff --git a/database_interactions/sqlx_todo/.gitignore b/database_interactions/sqlx_todo/.gitignore deleted file mode 100644 index 348583bc..00000000 --- a/database_interactions/sqlx_todo/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target -.env -test.db* diff --git a/database_interactions/sqlx_todo/Cargo.toml b/database_interactions/sqlx_todo/Cargo.toml deleted file mode 100644 index db07eced..00000000 --- a/database_interactions/sqlx_todo/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "sqlx_todo" -version = "1.0.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -actix-web = "4.0.0-rc.1" -serde = "1.0.106" -serde_json = "1.0.51" -sqlx = { version = "0.5.9", features = ["sqlite", "runtime-actix-rustls"] } -dotenv = "0.15.0" -env_logger = "0.9.0" -log = "0.4.8" -anyhow = "1.0.28" -futures = "0.3.13" diff --git a/database_interactions/sqlx_todo/README.md b/database_interactions/sqlx_todo/README.md deleted file mode 100644 index 3d0aaecf..00000000 --- a/database_interactions/sqlx_todo/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# actix-sqlx-todo - -Example Todo application using Actix-web and [SQLx](https://github.com/launchbadge/sqlx) with sqlite - -# Usage - -## Prerequisites - -* Rust -* SQLite - -## Change into the project sub-directory - -All instructions assume you have changed into this directory: - -```bash -$ cd database_interactions/sqlx_todo -``` - -## Set up the database - -* Create new database: - -```bash -./setup_db.sh -``` - -* Copy `.env.example` into `.env` and adjust `DATABASE_URL` to match your SQLite address, if needed - -```sh -cat schema.sql | sqlite3 test.db -cp .env.example .env -``` - -## Run the application - -To run the application execute: - -```bash -cargo run -``` - -By default the application will be available on `http://localhost:8080`. If you wish to change address or port you can do it inside the `.env` file diff --git a/database_interactions/sqlx_todo/schema.sql b/database_interactions/sqlx_todo/schema.sql deleted file mode 100644 index 30a6cdc3..00000000 --- a/database_interactions/sqlx_todo/schema.sql +++ /dev/null @@ -1,5 +0,0 @@ -CREATE TABLE IF NOT EXISTS todos ( - id INTEGER PRIMARY KEY NOT NULL, - description TEXT NOT NULL, - done BOOLEAN NOT NULL DEFAULT FALSE -); diff --git a/database_interactions/sqlx_todo/setup_db.sh b/database_interactions/sqlx_todo/setup_db.sh deleted file mode 100755 index 22b5aa19..00000000 --- a/database_interactions/sqlx_todo/setup_db.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -sqlite3 test.db < schema.sql diff --git a/database_interactions/sqlx_todo/src/main.rs b/database_interactions/sqlx_todo/src/main.rs deleted file mode 100644 index 04a62a49..00000000 --- a/database_interactions/sqlx_todo/src/main.rs +++ /dev/null @@ -1,65 +0,0 @@ -#[macro_use] -extern crate log; - -use std::env; - -use actix_web::{middleware, web, App, HttpResponse, HttpServer, Responder}; -use anyhow::Result; -use dotenv::dotenv; -use sqlx::SqlitePool; - -// import todo module (routes and model) -mod todo; - -// root (/) handler -async fn index() -> impl Responder { - HttpResponse::Ok().body( - r#" - Welcome to Actix-web with SQLx Todos example. - Available routes: - GET /todos -> list of all todos - POST /todo -> create new todo, example: { "description": "learn actix and sqlx", "done": false } - GET /todo/{id} -> show one todo with requested id - PUT /todo/{id} -> update todo with requested id, example: { "description": "learn actix and sqlx", "done": true } - DELETE /todo/{id} -> delete todo with requested id - "# - ) -} - -#[actix_web::main] -async fn main() -> Result<()> { - dotenv().ok(); - env_logger::init(); - - let database_url = - env::var("DATABASE_URL").expect("DATABASE_URL is not set in .env file"); - let host = env::var("HOST").expect("HOST is not set in .env file"); - let port = env::var("PORT") - .expect("PORT is not set in .env file") - .parse::() - .expect("PORT should be a u16"); - - info!("using sqlite database at: {}", &database_url); - let db_pool = SqlitePool::connect(&database_url).await?; - - // startup connection+schema check - sqlx::query!("SELECT * FROM todos") - .fetch_optional(&db_pool) - .await - .expect("no connection to database"); - - let server = HttpServer::new(move || { - App::new() - // pass database pool to application so we can access it inside handlers - .app_data(web::Data::new(db_pool.clone())) - .wrap(middleware::Logger::default()) - .route("/", web::get().to(index)) - .configure(todo::init) // init todo routes - }) - .bind((host, port))?; - - info!("Starting server"); - server.run().await?; - - Ok(()) -} diff --git a/database_interactions/sqlx_todo/src/todo/mod.rs b/database_interactions/sqlx_todo/src/todo/mod.rs deleted file mode 100644 index d660aadb..00000000 --- a/database_interactions/sqlx_todo/src/todo/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod model; -mod routes; - -pub use model::*; -pub use routes::init; diff --git a/database_interactions/sqlx_todo/src/todo/model.rs b/database_interactions/sqlx_todo/src/todo/model.rs deleted file mode 100644 index 4e90e79c..00000000 --- a/database_interactions/sqlx_todo/src/todo/model.rs +++ /dev/null @@ -1,177 +0,0 @@ -use actix_web::{body::BoxBody, HttpRequest, HttpResponse, Responder}; -use anyhow::Result; -use serde::{Deserialize, Serialize}; -use sqlx::sqlite::SqliteRow; -use sqlx::{FromRow, Row, SqlitePool}; - -// this struct will use to receive user input -#[derive(Serialize, Deserialize)] -pub struct TodoRequest { - pub description: String, - pub done: bool, -} - -// this struct will be used to represent database record -#[derive(Serialize, FromRow)] -pub struct Todo { - pub id: i64, - pub description: String, - pub done: bool, -} - -// implementation of Actix Responder for Todo struct so we can return Todo from action handler -impl Responder for Todo { - type Body = BoxBody; - - fn respond_to(self, _req: &HttpRequest) -> HttpResponse { - // create response and set content type - HttpResponse::Ok().json(&self) - } -} - -// Implementation for Todo struct, functions for read/write/update and delete todo from database -impl Todo { - pub async fn find_all(pool: &SqlitePool) -> Result> { - let todos = sqlx::query!( - r#" - SELECT id, description, done - FROM todos - ORDER BY id - "# - ) - .fetch_all(pool) - .await? - .into_iter() - .map(|rec| Todo { - id: rec.id, - description: rec.description, - done: rec.done, - }) - .collect(); - - Ok(todos) - } - - pub async fn find_by_id(id: i32, pool: &SqlitePool) -> Result> { - let rec = sqlx::query!( - r#" - SELECT id, description, done - FROM todos - WHERE id = $1 - "#, - id - ) - .fetch_optional(&*pool) - .await?; - - Ok(rec.map(|rec| Todo { - id: rec.id, - description: rec.description, - done: rec.done, - })) - } - - pub async fn create(todo: TodoRequest, pool: &SqlitePool) -> Result { - let mut tx = pool.begin().await?; - - sqlx::query!( - r#" - INSERT INTO todos (description, done) - VALUES ($1, $2) - "#, - todo.description, - todo.done, - ) - .execute(&mut tx) - .await?; - - // TODO: this can be replaced with RETURNING with sqlite v3.35+ and/or sqlx v0.5+ - let row_id: i32 = sqlx::query("SELECT last_insert_rowid()") - .map(|row: SqliteRow| row.get(0)) - .fetch_one(&mut tx) - .await?; - - let rec = sqlx::query!( - r#" - SELECT id, description, done - FROM todos - WHERE id = $1 - "#, - row_id, - ) - .fetch_one(&mut tx) - .await?; - - tx.commit().await?; - - Ok(Todo { - id: rec.id, - description: rec.description, - done: rec.done, - }) - } - - pub async fn update( - id: i32, - todo: TodoRequest, - pool: &SqlitePool, - ) -> Result> { - let mut tx = pool.begin().await.unwrap(); - - let n = sqlx::query!( - r#" - UPDATE todos - SET description = $1, done = $2 - WHERE id = $3 - "#, - todo.description, - todo.done, - id, - ) - .execute(&mut tx) - .await? - .rows_affected(); - - if n == 0 { - return Ok(None); - } - - // TODO: this can be replaced with RETURNING with sqlite v3.35+ and/or sqlx v0.5+ - let todo = sqlx::query!( - r#" - SELECT id, description, done - FROM todos - WHERE id = $1 - "#, - id, - ) - .fetch_one(&mut tx) - .await - .map(|rec| Todo { - id: rec.id, - description: rec.description, - done: rec.done, - })?; - - tx.commit().await.unwrap(); - Ok(Some(todo)) - } - - pub async fn delete(id: i32, pool: &SqlitePool) -> Result { - let mut tx = pool.begin().await?; - - let n_deleted = sqlx::query!( - r#" - DELETE FROM todos - WHERE id = $1 - "#, - id, - ) - .execute(&mut tx) - .await? - .rows_affected(); - - tx.commit().await?; - Ok(n_deleted) - } -} diff --git a/database_interactions/sqlx_todo/src/todo/routes.rs b/database_interactions/sqlx_todo/src/todo/routes.rs deleted file mode 100644 index be0eab2a..00000000 --- a/database_interactions/sqlx_todo/src/todo/routes.rs +++ /dev/null @@ -1,94 +0,0 @@ -use actix_web::{delete, get, post, put, web, HttpResponse, Responder}; -use sqlx::SqlitePool; - -use crate::todo::{Todo, TodoRequest}; - -// function that will be called on new Application to configure routes for this module -pub fn init(cfg: &mut web::ServiceConfig) { - cfg.service(find_all) - .service(find) - .service(create) - .service(update) - .service(delete); -} - -#[get("/todos")] -async fn find_all(db_pool: web::Data) -> impl Responder { - let result = Todo::find_all(db_pool.get_ref()).await; - match result { - Ok(todos) => HttpResponse::Ok().json(todos), - Err(err) => { - error!("error fetching todos: {}", err); - HttpResponse::InternalServerError() - .body("Error trying to read all todos from database") - } - } -} - -#[get("/todo/{id}")] -async fn find(id: web::Path, db_pool: web::Data) -> impl Responder { - let result = Todo::find_by_id(id.into_inner(), db_pool.get_ref()).await; - - match result { - Ok(Some(todo)) => HttpResponse::Ok().json(todo), - Ok(None) => HttpResponse::NotFound().body("Todo not found"), - Err(err) => { - error!("error fetching todo: {}", err); - HttpResponse::InternalServerError() - .body("Error trying to read todo from database") - } - } -} - -#[post("/todo")] -async fn create( - todo: web::Json, - db_pool: web::Data, -) -> impl Responder { - let result = Todo::create(todo.into_inner(), db_pool.get_ref()).await; - match result { - Ok(todo) => HttpResponse::Ok().json(todo), - Err(err) => { - error!("error creating todo: {}", err); - HttpResponse::InternalServerError().body("Error trying to create new todo") - } - } -} - -#[put("/todo/{id}")] -async fn update( - id: web::Path, - todo: web::Json, - db_pool: web::Data, -) -> impl Responder { - let result = Todo::update(*id, todo.into_inner(), &db_pool).await; - - match result { - Ok(Some(todo)) => HttpResponse::Ok().json(todo), - Ok(None) => HttpResponse::NotFound().body("Todo not found"), - Err(err) => { - error!("error updating todo: {}", err); - HttpResponse::InternalServerError().body("Error trying to update todo") - } - } -} - -#[delete("/todo/{id}")] -async fn delete(id: web::Path, db_pool: web::Data) -> impl Responder { - let result = Todo::delete(*id, db_pool.get_ref()).await; - - match result { - Ok(rows_deleted) => { - if rows_deleted > 0 { - let msg = format!("Successfully deleted {} record(s)", rows_deleted); - HttpResponse::Ok().body(msg) - } else { - HttpResponse::NotFound().body("Todo not found") - } - } - Err(err) => { - error!("error deleting todo: {}", err); - HttpResponse::InternalServerError().body("Todo not found") - } - } -}