diff --git a/.github/workflows/ci-nightly.yml b/.github/workflows/ci-nightly.yml
index d9ff04c7..d86bde1a 100644
--- a/.github/workflows/ci-nightly.yml
+++ b/.github/workflows/ci-nightly.yml
@@ -21,16 +21,21 @@ jobs:
with:
toolchain: ${{ matrix.version }}
+ - name: Install system packages
+ run: |
+ sudo apt-get update
+ sudo apt-get -y install sqlite3
+ sudo apt-get -y install libpq-dev
+
- name: Install DB CLI tools
run: |
cargo install --force sqlx-cli --no-default-features --features=sqlite,rustls
- cargo install --force diesel_cli --no-default-features --features sqlite
+ cargo install --force diesel_cli --no-default-features --features=sqlite,postgres
- name: Create Test DBs
env:
DATABASE_URL: sqlite://./todo.db
run: |
- sudo apt-get update && sudo apt-get install sqlite3
sqlx database create
chmod a+rwx ./todo.db
sqlx migrate run --source=./basics/todo/migrations
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b15551d9..24580c04 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -26,16 +26,21 @@ jobs:
with:
toolchain: ${{ matrix.version }}
+ - name: Install system packages
+ run: |
+ sudo apt-get update
+ sudo apt-get -y install sqlite3
+ sudo apt-get -y install libpq-dev
+
- name: Install DB CLI tools
run: |
cargo install --force sqlx-cli --no-default-features --features=sqlite,rustls
- cargo install --force diesel_cli --no-default-features --features sqlite
+ cargo install --force diesel_cli --no-default-features --features=sqlite,postgres
- name: Create Test DBs
env:
DATABASE_URL: sqlite://./todo.db
run: |
- sudo apt-get update && sudo apt-get install sqlite3
sqlx database create
chmod a+rwx ./todo.db
sqlx migrate run --source=./basics/todo/migrations
diff --git a/Cargo.lock b/Cargo.lock
index adf639d8..98485b84 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1730,6 +1730,18 @@ dependencies = [
"log",
]
+[[package]]
+name = "bb8"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d89aabfae550a5c44b43ab941844ffcd2e993cb6900b342debf59e9ea74acdb8"
+dependencies = [
+ "async-trait",
+ "futures-util",
+ "parking_lot",
+ "tokio",
+]
+
[[package]]
name = "bigdecimal"
version = "0.3.1"
@@ -2633,6 +2645,20 @@ dependencies = [
"uuid",
]
+[[package]]
+name = "db-diesel-async"
+version = "1.0.0"
+dependencies = [
+ "actix-web",
+ "diesel",
+ "diesel-async",
+ "dotenvy",
+ "env_logger",
+ "log",
+ "serde",
+ "uuid",
+]
+
[[package]]
name = "db-mongo"
version = "0.0.0"
@@ -2663,7 +2689,7 @@ version = "0.0.0"
dependencies = [
"actix-web",
"env_logger",
- "redis 0.27.6",
+ "redis 0.28.2",
"serde",
"tracing",
]
@@ -2860,6 +2886,21 @@ dependencies = [
"uuid",
]
+[[package]]
+name = "diesel-async"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51a307ac00f7c23f526a04a77761a0519b9f0eb2838ebf5b905a58580095bdcb"
+dependencies = [
+ "async-trait",
+ "bb8",
+ "diesel",
+ "futures-util",
+ "scoped-futures",
+ "tokio",
+ "tokio-postgres",
+]
+
[[package]]
name = "diesel_derives"
version = "2.2.4"
@@ -6538,6 +6579,29 @@ dependencies = [
"pin-project-lite",
"ryu",
"sha1_smol",
+ "tokio",
+ "tokio-util",
+ "url",
+]
+
+[[package]]
+name = "redis"
+version = "0.28.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e37ec3fd44bea2ec947ba6cc7634d7999a6590aca7c35827c250bc0de502bda6"
+dependencies = [
+ "arc-swap",
+ "backon",
+ "bytes",
+ "combine",
+ "futures-channel",
+ "futures-util",
+ "itoa",
+ "num-bigint",
+ "percent-encoding",
+ "pin-project-lite",
+ "ryu",
+ "sha1_smol",
"socket2",
"tokio",
"tokio-util",
@@ -7154,6 +7218,15 @@ dependencies = [
"parking_lot",
]
+[[package]]
+name = "scoped-futures"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b24aae2d0636530f359e9d5ef0c04669d11c5e756699b27a6a6d845d8329091"
+dependencies = [
+ "pin-project-lite",
+]
+
[[package]]
name = "scopeguard"
version = "1.2.0"
diff --git a/Cargo.toml b/Cargo.toml
index 8eeb0c9d..a234b0e3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,6 +17,7 @@ members = [
"cors/backend",
"data-factory",
"databases/diesel",
+ "databases/diesel-async",
"databases/mongodb",
"databases/mysql",
"databases/postgres",
diff --git a/databases/diesel-async/Cargo.toml b/databases/diesel-async/Cargo.toml
new file mode 100644
index 00000000..fbf35f2f
--- /dev/null
+++ b/databases/diesel-async/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "db-diesel-async"
+version = "1.0.0"
+edition = "2021"
+
+[features]
+postgres_tests = []
+
+[dependencies]
+actix-web.workspace = true
+diesel = { version = "2", default-features = false, features = ["uuid"] }
+diesel-async = { version = "0.5", features = ["postgres", "bb8", "async-connection-wrapper"] }
+serde.workspace = true
+uuid.workspace = true
+dotenvy.workspace = true
+env_logger.workspace = true
+log.workspace = true
diff --git a/databases/diesel-async/README.md b/databases/diesel-async/README.md
new file mode 100644
index 00000000..891e55b5
--- /dev/null
+++ b/databases/diesel-async/README.md
@@ -0,0 +1,113 @@
+# diesel
+
+Basic integration of [Diesel-async](https://github.com/weiznich/diesel_async) using PostgreSQL for Actix Web.
+
+## Usage
+
+### Install PostgreSQL
+
+```sh
+# on any OS
+docker run -d --restart unless-stopped --name postgresql -e POSTGRES_USER=test-user -e POSTGRES_PASSWORD=password -p 5432:5432 -v postgres_data:/var/lib/postgresql/data postgres:alpine
+```
+make sure it has successfully started up and is running
+```sh
+# on any OS
+docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}"
+```
+
+### Initialize PostgreSQL Database
+
+```sh
+cd databases/diesel-async
+cargo install diesel_cli --no-default-features --features postgres
+
+echo DATABASE_URL=postgres://test-user:password@localhost:5432/test_db > .env
+diesel setup
+diesel migration run
+```
+
+The database will now be created in your PostgreSQL instance.
+```sh
+docker exec -i postgresql psql -U test-user -c "\l"
+```
+
+### Running Server
+
+```sh
+cd databases/diesel-async
+cargo run
+
+# Started http server: 127.0.0.1:8080
+```
+
+### Available Routes
+
+#### `POST /items`
+
+Inserts a new item into the PostgreSQL DB.
+
+Provide a JSON payload with a name. Eg:
+
+```json
+{ "name": "thingamajig" }
+```
+
+On success, a response like the following is returned:
+
+```json
+{
+ "id": "01948982-67d0-7a55-b4b1-8b8b962d8c6b",
+ "name": "thingamajig"
+}
+```
+
+
+ Client Examples
+
+Using [HTTPie]:
+
+```sh
+http POST localhost:8080/items name=thingamajig
+```
+
+Using cURL:
+
+```sh
+curl -S -X POST --header "Content-Type: application/json" --data '{"name":"thingamajig"}' http://localhost:8080/items
+```
+
+
+
+#### `GET /items/{item_uid}`
+
+Gets an item from the DB using its UID (returned from the insert request or taken from the DB directly). Returns a 404 when no item exists with that UID.
+
+
+ Client Examples
+
+Using [HTTPie]:
+
+```sh
+http localhost:8080/items/9e46baba-a001-4bb3-b4cf-4b3e5bab5e97
+```
+
+Using cURL:
+
+```sh
+curl -S http://localhost:8080/items/9e46baba-a001-4bb3-b4cf-4b3e5bab5e97
+```
+
+
+
+### Explore The PostgreSQL DB
+
+```sh
+docker exec -i postgresql psql -U test-user -d test_db -c "select * from public.items"
+```
+
+## Using Other Databases
+
+You can find a complete example of Diesel + PostgreSQL at: [https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Rust/actix](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Rust/actix)
+
+[httpie]: https://httpie.io/cli
diff --git a/databases/diesel-async/diesel.toml b/databases/diesel-async/diesel.toml
new file mode 100644
index 00000000..34c0a182
--- /dev/null
+++ b/databases/diesel-async/diesel.toml
@@ -0,0 +1,9 @@
+# For documentation on how to configure this file,
+# see https://diesel.rs/guides/configuring-diesel-cli
+
+[print_schema]
+file = "src/schema.rs"
+custom_type_derives = ["diesel::query_builder::QueryId", "Clone"]
+
+[migrations_directory]
+dir = "/home/alex/CLionProjects/actix-with-async-diesel/migrations"
diff --git a/databases/diesel-async/migrations/.keep b/databases/diesel-async/migrations/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/databases/diesel-async/migrations/00000000000000_diesel_initial_setup/down.sql b/databases/diesel-async/migrations/00000000000000_diesel_initial_setup/down.sql
new file mode 100644
index 00000000..a9f52609
--- /dev/null
+++ b/databases/diesel-async/migrations/00000000000000_diesel_initial_setup/down.sql
@@ -0,0 +1,6 @@
+-- This file was automatically created by Diesel to setup helper functions
+-- and other internal bookkeeping. This file is safe to edit, any future
+-- changes will be added to existing projects as new migrations.
+
+DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass);
+DROP FUNCTION IF EXISTS diesel_set_updated_at();
diff --git a/databases/diesel-async/migrations/00000000000000_diesel_initial_setup/up.sql b/databases/diesel-async/migrations/00000000000000_diesel_initial_setup/up.sql
new file mode 100644
index 00000000..8335c232
--- /dev/null
+++ b/databases/diesel-async/migrations/00000000000000_diesel_initial_setup/up.sql
@@ -0,0 +1,36 @@
+-- This file was automatically created by Diesel to setup helper functions
+-- and other internal bookkeeping. This file is safe to edit, any future
+-- changes will be added to existing projects as new migrations.
+
+
+-- Sets up a trigger for the given table to automatically set a column called
+-- `updated_at` whenever the row is modified (unless `updated_at` was included
+-- in the modified columns)
+--
+-- # Example
+--
+-- ```sql
+-- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW());
+--
+-- SELECT diesel_manage_updated_at('users');
+-- ```
+CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS
+$$
+BEGIN
+ EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s
+ FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl);
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS
+$$
+BEGIN
+ IF (
+ NEW IS DISTINCT FROM OLD AND
+ NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at
+ ) THEN
+ NEW.updated_at := current_timestamp;
+ END IF;
+ RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
diff --git a/databases/diesel-async/migrations/2025-01-18-144029_create_items/down.sql b/databases/diesel-async/migrations/2025-01-18-144029_create_items/down.sql
new file mode 100644
index 00000000..6839ef8e
--- /dev/null
+++ b/databases/diesel-async/migrations/2025-01-18-144029_create_items/down.sql
@@ -0,0 +1,2 @@
+-- This file should undo anything in `up.sql`
+DROP TABLE IF EXISTS items;
diff --git a/databases/diesel-async/migrations/2025-01-18-144029_create_items/up.sql b/databases/diesel-async/migrations/2025-01-18-144029_create_items/up.sql
new file mode 100644
index 00000000..7066001b
--- /dev/null
+++ b/databases/diesel-async/migrations/2025-01-18-144029_create_items/up.sql
@@ -0,0 +1,6 @@
+-- Your SQL goes here
+CREATE TABLE IF NOT EXISTS items
+(
+ id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
+ name VARCHAR NOT NULL
+);
diff --git a/databases/diesel-async/src/actions.rs b/databases/diesel-async/src/actions.rs
new file mode 100644
index 00000000..542f5662
--- /dev/null
+++ b/databases/diesel-async/src/actions.rs
@@ -0,0 +1,52 @@
+use diesel::prelude::*;
+use uuid::{NoContext, Timestamp, Uuid};
+
+use crate::models;
+
+use diesel_async::AsyncPgConnection;
+use diesel_async::RunQueryDsl;
+
+type DbError = Box;
+
+// /// Run query using Diesel to find item by uid and return it.
+pub async fn find_item_by_id(
+ conn: &mut AsyncPgConnection,
+ uid: Uuid,
+) -> Result