From c92ee309a91d5ca3bb7a75913074cde597094fd0 Mon Sep 17 00:00:00 2001 From: Waylon Cude Date: Mon, 18 May 2026 14:54:57 -0700 Subject: [PATCH] Initial implementation of db stuffs Got the migrations and datastructures in. Next step is building db utility function into the db module or client module --- .gitignore | 1 + Cargo.lock | 28 ++++++++ Cargo.toml | 3 +- diesel.toml | 9 +++ migrations/.diesel_lock | 0 migrations/.keep | 0 .../down.sql | 6 ++ .../up.sql | 36 ++++++++++ .../down.sql | 2 + .../up.sql | 6 ++ .../down.sql | 3 + .../up.sql | 11 +++ .../down.sql | 3 + .../up.sql | 14 ++++ .../down.sql | 2 + .../up.sql | 7 ++ src/db/mod.rs | 2 + src/db/models.rs | 68 +++++++++++++++++++ src/db/schema.rs | 58 ++++++++++++++++ src/main.rs | 1 + src/state.rs | 3 + 21 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 diesel.toml create mode 100644 migrations/.diesel_lock create mode 100644 migrations/.keep create mode 100644 migrations/00000000000000_diesel_initial_setup/down.sql create mode 100644 migrations/00000000000000_diesel_initial_setup/up.sql create mode 100644 migrations/2026-05-18-182001-0000_create_users/down.sql create mode 100644 migrations/2026-05-18-182001-0000_create_users/up.sql create mode 100644 migrations/2026-05-18-182012-0000_create_groups/down.sql create mode 100644 migrations/2026-05-18-182012-0000_create_groups/up.sql create mode 100644 migrations/2026-05-18-182028-0000_create_messages/down.sql create mode 100644 migrations/2026-05-18-182028-0000_create_messages/up.sql create mode 100644 migrations/2026-05-18-182143-0000_create_roles/down.sql create mode 100644 migrations/2026-05-18-182143-0000_create_roles/up.sql create mode 100644 src/db/mod.rs create mode 100644 src/db/models.rs create mode 100644 src/db/schema.rs diff --git a/.gitignore b/.gitignore index f07bb8c..cdde1f0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target confetti.toml +.env diff --git a/Cargo.lock b/Cargo.lock index a4223ed..30c3ea3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -229,6 +229,7 @@ dependencies = [ "ctrlc-async", "diesel", "diesel-async", + "diesel-derive-composite", "fedichat", "quinn", "rmp-serde", @@ -246,6 +247,15 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" +[[package]] +name = "convert_case" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -390,6 +400,18 @@ dependencies = [ "tokio-postgres", ] +[[package]] +name = "diesel-derive-composite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a634241e758e588c8deb76cc44f0b605b46536aa769946446b6afd4956c7f2e8" +dependencies = [ + "convert_case", + "darling", + "quote", + "syn", +] + [[package]] name = "diesel_derives" version = "2.3.9" @@ -1778,6 +1800,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" +[[package]] +name = "unicode-segmentation" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" + [[package]] name = "unicode-xid" version = "0.2.6" diff --git a/Cargo.toml b/Cargo.toml index 26a98c6..8efe6b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] -diesel = { version = "2.3.9" } +diesel = { version = "2.3.9", features = ["postgres_backend"] } quinn = "0.11.9" fedichat = {git = "https://git.firechicken.net/fedichat/fedichat-lib"} #fedichat = {path = "../fedichat-lib"} @@ -18,3 +18,4 @@ toml = "1.1.2" diesel-async = { version = "0.9.0", features = ["postgres","deadpool"] } ctrlc-async = { version = "3.2.2", features = ["termination"] } rmp-serde = "1.3.1" +diesel-derive-composite = "0.1.0" diff --git a/diesel.toml b/diesel.toml new file mode 100644 index 0000000..bb1d1f7 --- /dev/null +++ b/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/db/schema.rs" +custom_type_derives = ["diesel::query_builder::QueryId", "Clone"] + +[migrations_directory] +dir = "migrations" diff --git a/migrations/.diesel_lock b/migrations/.diesel_lock new file mode 100644 index 0000000..e69de29 diff --git a/migrations/.keep b/migrations/.keep new file mode 100644 index 0000000..e69de29 diff --git a/migrations/00000000000000_diesel_initial_setup/down.sql b/migrations/00000000000000_diesel_initial_setup/down.sql new file mode 100644 index 0000000..a9f5260 --- /dev/null +++ b/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/migrations/00000000000000_diesel_initial_setup/up.sql b/migrations/00000000000000_diesel_initial_setup/up.sql new file mode 100644 index 0000000..d68895b --- /dev/null +++ b/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/migrations/2026-05-18-182001-0000_create_users/down.sql b/migrations/2026-05-18-182001-0000_create_users/down.sql new file mode 100644 index 0000000..dc3714b --- /dev/null +++ b/migrations/2026-05-18-182001-0000_create_users/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +DROP TABLE users; diff --git a/migrations/2026-05-18-182001-0000_create_users/up.sql b/migrations/2026-05-18-182001-0000_create_users/up.sql new file mode 100644 index 0000000..7b6b5cf --- /dev/null +++ b/migrations/2026-05-18-182001-0000_create_users/up.sql @@ -0,0 +1,6 @@ +-- Your SQL goes here +CREATE TABLE users ( + id SERIAL PRIMARY KEY, + username TEXT NOT NULL UNIQUE, + password TEXT NOT NULL +) diff --git a/migrations/2026-05-18-182012-0000_create_groups/down.sql b/migrations/2026-05-18-182012-0000_create_groups/down.sql new file mode 100644 index 0000000..9e75b52 --- /dev/null +++ b/migrations/2026-05-18-182012-0000_create_groups/down.sql @@ -0,0 +1,3 @@ +-- This file should undo anything in `up.sql` +DROP TABLE groups; +DROP TYPE user_t; diff --git a/migrations/2026-05-18-182012-0000_create_groups/up.sql b/migrations/2026-05-18-182012-0000_create_groups/up.sql new file mode 100644 index 0000000..097aa6c --- /dev/null +++ b/migrations/2026-05-18-182012-0000_create_groups/up.sql @@ -0,0 +1,11 @@ +-- Your SQL goes here +CREATE TYPE user_t AS ( + name TEXT, + server TEXT +); +CREATE TABLE groups ( + id SERIAL PRIMARY KEY, + groupname TEXT NOT NULL, + role TEXT, + username user_t NOT NULL +) diff --git a/migrations/2026-05-18-182028-0000_create_messages/down.sql b/migrations/2026-05-18-182028-0000_create_messages/down.sql new file mode 100644 index 0000000..d3f569b --- /dev/null +++ b/migrations/2026-05-18-182028-0000_create_messages/down.sql @@ -0,0 +1,3 @@ +-- This file should undo anything in `up.sql` +DROP TABLE messages; +DROP TYPE room_id; diff --git a/migrations/2026-05-18-182028-0000_create_messages/up.sql b/migrations/2026-05-18-182028-0000_create_messages/up.sql new file mode 100644 index 0000000..636a76f --- /dev/null +++ b/migrations/2026-05-18-182028-0000_create_messages/up.sql @@ -0,0 +1,14 @@ +-- Your SQL goes here +CREATE TYPE room_id AS ( + coordinates bigint[], + server text +); +CREATE TABLE messages ( + id BIGSERIAL PRIMARY KEY, + room room_id NOT NULL, + body TEXT NOT NULL, + signature TEXT NOT NULL, + client_timestamp BIGINT NOT NULL, + server_timestamp BIGINT NOT NULL, + username user_t NOT NULL +) diff --git a/migrations/2026-05-18-182143-0000_create_roles/down.sql b/migrations/2026-05-18-182143-0000_create_roles/down.sql new file mode 100644 index 0000000..45b220f --- /dev/null +++ b/migrations/2026-05-18-182143-0000_create_roles/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +DROP TABLE roles; diff --git a/migrations/2026-05-18-182143-0000_create_roles/up.sql b/migrations/2026-05-18-182143-0000_create_roles/up.sql new file mode 100644 index 0000000..f4684e2 --- /dev/null +++ b/migrations/2026-05-18-182143-0000_create_roles/up.sql @@ -0,0 +1,7 @@ +-- Your SQL goes here +CREATE TABLE roles ( + id SERIAL PRIMARY KEY, + rolename TEXT NOT NULL, + groupname TEXT NOT NULL, + permission TEXT NOT NULL +) diff --git a/src/db/mod.rs b/src/db/mod.rs new file mode 100644 index 0000000..d5cbad7 --- /dev/null +++ b/src/db/mod.rs @@ -0,0 +1,2 @@ +pub mod models; +pub mod schema; diff --git a/src/db/models.rs b/src/db/models.rs new file mode 100644 index 0000000..7635197 --- /dev/null +++ b/src/db/models.rs @@ -0,0 +1,68 @@ +use diesel::prelude::*; +use diesel::deserialize::FromSqlRow; +use diesel::expression::AsExpression; +// Man this library is brittle +use diesel_derive_composite::Composite; + +use diesel::pg::Pg; + +// Gets around broken macro in diesel_derive_composite +type MyArr = diesel::sql_types::Array; + +#[derive(Debug, Composite, FromSqlRow, AsExpression)] +#[diesel(sql_type = crate::db::schema::sql_types::UserT)] +pub struct UserT { + #[diesel_composite(sql_type = diesel::sql_types::Text)] + pub name: String, + #[diesel_composite(sql_type = diesel::sql_types::Text)] + pub server: String +} + +#[derive(Debug, Composite, FromSqlRow, AsExpression)] +#[diesel(sql_type = crate::db::schema::sql_types::UserT)] +pub struct RoomId { + #[diesel_composite(sql_type = MyArr)] + pub coordinates: Vec, + #[diesel_composite(sql_type = diesel::sql_types::Text)] + pub server: String +} + +#[derive(Queryable, Selectable)] +#[diesel(table_name = crate::db::schema::groups)] +pub struct Group { + pub id: i32, + pub groupname: String, + pub role: Option, + pub username: UserT +} + + +#[derive(Queryable, Selectable)] +#[diesel(table_name = crate::db::schema::roles)] +pub struct Role { + pub id: i32, + pub rolename: String, + pub groupname: String, + pub permission: String +} + + +#[derive(Queryable, Selectable)] +#[diesel(table_name = crate::db::schema::users)] +pub struct User { + pub id: i32, + pub username: String, + pub password: String, +} + +#[derive(Queryable, Selectable)] +#[diesel(table_name = crate::db::schema::messages)] +pub struct Messages { + pub id: i64, + pub room: RoomId, + pub body: String, + pub signature: String, + pub client_timestamp: i64, + pub server_timestamp: i64, + pub username: UserT +} diff --git a/src/db/schema.rs b/src/db/schema.rs new file mode 100644 index 0000000..1e10d53 --- /dev/null +++ b/src/db/schema.rs @@ -0,0 +1,58 @@ +// @generated automatically by Diesel CLI. + +pub mod sql_types { + #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "room_id"))] + pub struct RoomId; + + #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "user_t"))] + pub struct UserT; +} + +diesel::table! { + use diesel::sql_types::*; + use super::sql_types::UserT; + + groups (id) { + id -> Int4, + groupname -> Text, + role -> Nullable, + username -> UserT, + } +} + +diesel::table! { + use diesel::sql_types::*; + use super::sql_types::RoomId; + use super::sql_types::UserT; + + messages (id) { + id -> Int8, + room -> RoomId, + body -> Text, + signature -> Text, + client_timestamp -> Int8, + server_timestamp -> Int8, + username -> UserT, + } +} + +diesel::table! { + roles (id) { + id -> Int4, + rolename -> Text, + groupname -> Text, + permission -> Text, + } +} + +diesel::table! { + users (id) { + id -> Int4, + username -> Text, + password -> Text, + } +} + +diesel::allow_tables_to_appear_in_same_query!(groups, messages, roles, users,); diff --git a/src/main.rs b/src/main.rs index 38530b6..9727ec7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ mod client; mod config; mod connection; +mod db; mod state; use diesel_async::pooled_connection::AsyncDieselConnectionManager; diff --git a/src/state.rs b/src/state.rs index b804236..15a82aa 100644 --- a/src/state.rs +++ b/src/state.rs @@ -40,6 +40,9 @@ impl State { } pub fn write_to_file(&mut self, path: &str) -> Result<(),io::Error> { + // Should write to state.next file, then move to actual state file + // Uses twice as much space but won't corrupt state if the program crashes + // during an autosave unimplemented!() } pub fn load_from_file(path: &str) -> Result {