M Cargo.lock => Cargo.lock +89 -0
@@ 417,6 417,8 @@ version = "0.1.0"
 dependencies = [
  "actix-session",
  "actix-web",
+ "diesel",
+ "diesel_migrations",
  "log",
  "pretty_env_logger",
 ]
@@ 2027,6 2029,43 @@ dependencies = [
 ]
 
 [[package]]
+name = "diesel"
+version = "2.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4391a22b19c916e50bec4d6140f29bdda3e3bb187223fe6e3ea0b6e4d1021c04"
+dependencies = [
+ "bitflags",
+ "byteorder",
+ "diesel_derives",
+ "itoa",
+ "pq-sys",
+ "r2d2",
+]
+
+[[package]]
+name = "diesel_derives"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "143b758c91dbc3fe1fdcb0dba5bd13276c6a66422f2ef5795b58488248a310aa"
+dependencies = [
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "diesel_migrations"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9ae22beef5e9d6fab9225ddb073c1c6c1a7a6ded5019d5da11d1e5c5adc34e2"
+dependencies = [
+ "diesel",
+ "migrations_internals",
+ "migrations_macros",
+]
+
+[[package]]
 name = "digest"
 version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 3271,6 3310,27 @@ dependencies = [
 ]
 
 [[package]]
+name = "migrations_internals"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c493c09323068c01e54c685f7da41a9ccf9219735c3766fbfd6099806ea08fbc"
+dependencies = [
+ "serde",
+ "toml 0.5.11",
+]
+
+[[package]]
+name = "migrations_macros"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a8ff27a350511de30cdabb77147501c36ef02e0451d957abea2f30caffb2b58"
+dependencies = [
+ "migrations_internals",
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
 name = "mime"
 version = "0.3.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 3896,6 3956,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
+name = "pq-sys"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b845d6d8ec554f972a2c5298aad68953fd64e7441e846075450b44656a016d1"
+dependencies = [
+ "vcpkg",
+]
+
+[[package]]
 name = "pretty-type-name"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 3996,6 4065,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "r2d2"
+version = "0.8.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93"
+dependencies = [
+ "log",
+ "parking_lot",
+ "scheduled-thread-pool",
+]
+
+[[package]]
 name = "radsort"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 4268,6 4348,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "scheduled-thread-pool"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "977a7519bff143a44f842fd07e80ad1329295bd71686457f18e496736f4bf9bf"
+dependencies = [
+ "parking_lot",
+]
+
+[[package]]
 name = "scoped_threadpool"
 version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
M api/Cargo.toml => api/Cargo.toml +7 -0
@@ 13,6 13,8 @@ publish = false
 log = "0.4.17"
 pretty_env_logger = "0.4.0"
 
+diesel_migrations = "2.0.0"
+
 [dependencies.actix-web]
 version = "4.3.0"
 default-features = false
@@ 22,3 24,8 @@ features = ["cookies", "macros", "compress-gzip"]
 version = "0.7.2"
 default-features = false
 features = ["redis-actor-session"]
+
+[dependencies.diesel]
+version = "2.0.3"
+default-features = false
+features = ["with-deprecated", "32-column-tables", "postgres", "r2d2"]
 
A api/diesel.toml => api/diesel.toml +8 -0
@@ 0,0 1,8 @@
+# For documentation on how to configure this file,
+# see https://diesel.rs/guides/configuring-diesel-cli
+
+[print_schema]
+file = "src/schema.rs"
+
+[migrations_directory]
+dir = "migrations"
 
A api/docker-compose.dev.yaml => api/docker-compose.dev.yaml +25 -0
@@ 0,0 1,25 @@
+version: "3.0"
+
+networks:
+  internal:
+    external: false
+
+volumes:
+  laurelindb_data:
+    driver: local
+
+services:
+  laurelindb:
+    image: postgres:alpine
+    container_name: laurelindb
+    restart: always
+    networks:
+      - internal
+    ports:
+      - 5432:5432
+    volumes:
+      - laurelindb_data:/var/lib/postgresql/data
+    environment:
+      POSTGRES_USER: laurelin
+      POSTGRES_PASSWORD: laurelin
+      POSTGRES_DB: laurelin
 
A api/migrations/00000000000000_diesel_initial_setup/down.sql => api/migrations/00000000000000_diesel_initial_setup/down.sql +6 -0
@@ 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();
 
A api/migrations/00000000000000_diesel_initial_setup/up.sql => api/migrations/00000000000000_diesel_initial_setup/up.sql +36 -0
@@ 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;
 
A api/scripts/dev-migr.sh => api/scripts/dev-migr.sh +2 -0
@@ 0,0 1,2 @@
+#!/bin/sh
+~/.cargo/bin/diesel migration run --database-url postgres://laurelin:laurelin@localhost:5432/laurelin
 
A api/scripts/dev-start-db.sh => api/scripts/dev-start-db.sh +25 -0
@@ 0,0 1,25 @@
+#!/bin/bash
+
+export COMPOSE_PROJECT_NAME=laurelin
+
+function confirm() {
+  echo -n "$@ [y/N]: "
+    read -e answer
+    for response in y Y
+    do
+        if [ "_$answer" == "_$response" ]
+        then
+            return 0
+        fi
+    done
+
+    # default to no
+    return 1
+}
+
+confirm reset containers? && docker compose --file docker-compose.dev.yaml down
+confirm reset database? && docker volume rm laurelin_laurelindb_data
+
+confirm rebuild api? && docker compose --file docker-compose.dev.yaml build
+
+confirm launch? && docker compose --file docker-compose.dev.yaml up
 
A api/src/schema.rs => api/src/schema.rs +2 -0
@@ 0,0 1,2 @@
+// @generated automatically by Diesel CLI.
+