diff --git a/api/Cargo.toml b/api/Cargo.toml index 0c7cf6c..376ff91 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -38,6 +38,7 @@ sqlx = { version = "0.8", features = [ "postgres", "runtime-tokio", "rust_decimal", + "uuid" ] } syslog-tracing = "0.3.1" time = { version = "0.3", features = ["formatting", "macros"] } diff --git a/api/migrations/20231221181946_create-tables.down.sql b/api/migrations/20231221181946_create-tables.down.sql index 690d092..6de353b 100644 --- a/api/migrations/20231221181946_create-tables.down.sql +++ b/api/migrations/20231221181946_create-tables.down.sql @@ -1,3 +1,5 @@ +DROP FUNCTION IF EXISTS uuidv7; + DROP INDEX IF EXISTS user_username_uniq_idx; DROP INDEX IF EXISTS user_email_uniq_idx; DROP INDEX IF EXISTS permission_category_idx; diff --git a/api/migrations/20231221181946_create-tables.up.sql b/api/migrations/20231221181946_create-tables.up.sql index 489564e..35a5af7 100644 --- a/api/migrations/20231221181946_create-tables.up.sql +++ b/api/migrations/20231221181946_create-tables.up.sql @@ -1,3 +1,19 @@ +CREATE FUNCTION uuidv7() RETURNS uuid +AS $$ + -- Replace the first 48 bits of a uuidv4 with the current + -- number of milliseconds since 1970-01-01 UTC + -- and set the "ver" field to 7 by setting additional bits + SELECT encode( + set_bit( + set_bit( + overlay(uuid_send(gen_random_uuid()) placing + substring(int8send((extract(epoch FROM clock_timestamp())*1000)::bigint) FROM 3) + FROM 1 FOR 6), + 52, 1), + 53, 1), 'hex')::uuid; +$$ LANGUAGE sql volatile; + + CREATE TYPE public.status AS ENUM @@ -18,7 +34,8 @@ CREATE TYPE AS ENUM ('Account'); -CREATE TABLE IF NOT EXISTS public.user ( +CREATE TABLE IF NOT EXISTS + public.user ( id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, email TEXT NOT NULL, password TEXT NOT NULL, @@ -58,7 +75,7 @@ INSERT INTO CREATE TABLE IF NOT EXISTS public.account ( - id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + id UUID PRIMARY KEY DEFAULT uuidv7(), account_type account_type NOT NULL, name TEXT NOT NULL, description TEXT NULL, @@ -72,7 +89,7 @@ CREATE TABLE IF NOT EXISTS public.user_account_permission ( id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, user_id INT NOT NULL REFERENCES public.user(id), - account_id INT NOT NULL REFERENCES public.account(id), + account_id UUID NOT NULL REFERENCES public.account(id), permission_id INT NOT NULL REFERENCES public.permission(id), status status NOT NULL DEFAULT 'Active', created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), @@ -84,7 +101,7 @@ CREATE INDEX IF NOT EXISTS user_account_permission_account_id_idx ON public.user CREATE TABLE IF NOT EXISTS public.budget ( - id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + id UUID PRIMARY KEY DEFAULT uuidv7(), name TEXT NOT NULL, description TEXT NULL, icon TEXT NULL, @@ -95,9 +112,9 @@ CREATE TABLE IF NOT EXISTS CREATE TABLE IF NOT EXISTS public.transaction ( - id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + id UUID PRIMARY KEY DEFAULT uuidv7(), description TEXT NOT NULL, - budget_id INT NOT NULL REFERENCES public.budget(id), + budget_id UUID NOT NULL REFERENCES public.budget(id), status status NOT NULL DEFAULT 'Active', created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), updated_at TIMESTAMP WITH TIME ZONE NULL @@ -107,9 +124,9 @@ CREATE INDEX IF NOT EXISTS transaction_budget_id_idx ON public.transaction(budge CREATE TABLE IF NOT EXISTS public.transaction_line_item ( - id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, - transaction_id INT NOT NULL REFERENCES public.transaction(id), - account_id INT NOT NULL REFERENCES public.account(id), + id UUID PRIMARY KEY DEFAULT uuidv7(), + transaction_id UUID NOT NULL REFERENCES public.transaction(id), + account_id UUID NOT NULL REFERENCES public.account(id), entry_type entry_type NOT NULL, value NUMERIC(12, 2) NOT NULL, status status NOT NULL DEFAULT 'Active', diff --git a/api/src/db/account.rs b/api/src/db/account.rs index 3150ff9..75035ba 100644 --- a/api/src/db/account.rs +++ b/api/src/db/account.rs @@ -1,5 +1,6 @@ use sqlx::prelude::*; use tracing::error; +use uuid::Uuid; use crate::models::AppError; @@ -19,7 +20,7 @@ pub struct NewAccountEntity { #[allow(dead_code)] #[derive(Debug, FromRow)] pub struct AccountEntity { - pub id: i32, + pub id: Uuid, pub account_type: AccountType, pub name: String, pub description: Option, @@ -30,7 +31,7 @@ pub struct AccountEntity { #[allow(dead_code)] #[derive(Debug, Default, FromRow)] pub struct AccountWithPermissionValueEntity { - pub id: i32, + pub id: Uuid, pub account_type: AccountType, pub name: String, pub description: Option, diff --git a/api/src/db/user_account_permission.rs b/api/src/db/user_account_permission.rs index fae7bbd..b815b0c 100644 --- a/api/src/db/user_account_permission.rs +++ b/api/src/db/user_account_permission.rs @@ -1,5 +1,6 @@ use sqlx::prelude::*; use tracing::error; +use uuid::Uuid; use crate::models::AppError; @@ -12,7 +13,7 @@ use super::{ #[derive(Clone)] pub struct NewUserAccountPermissionEntity { pub user_id: i32, - pub account_id: i32, + pub account_id: Uuid, pub permission_id: i32, } @@ -21,20 +22,20 @@ pub struct NewUserAccountPermissionEntity { pub struct UserAccountPermissionEntity { pub id: i32, pub user_id: i32, - pub account_id: i32, + pub account_id: Uuid, pub permission_id: i32, pub status: StatusType, } pub async fn associate_account_with_user_as_owner( pool: &DbPool, - account_id: i32, + account_id: Uuid, user_id: i32, ) -> Result, AppError> { let values = get_all_permissions_by_category(pool, PermissionCategoryType::Account) .await? .into_iter() - .map(|permission| format!("({user_id}, {account_id}, {})", permission.id)) + .map(|permission| format!("({user_id}, '{account_id}', {})", permission.id)) .collect::>() .join(","); @@ -48,7 +49,7 @@ pub async fn associate_account_with_user_as_owner( .inspect_err(|err| { error!( ?err, - account_id, user_id, "Cannot associate account with user as owner" + %account_id, user_id, "Cannot associate account with user as owner" ) }) .map_err(|err| AppError::from(err)) diff --git a/api/src/requests/account/create/models/response.rs b/api/src/requests/account/create/models/response.rs index 1e7f65d..ed5b232 100644 --- a/api/src/requests/account/create/models/response.rs +++ b/api/src/requests/account/create/models/response.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use uuid::Uuid; use crate::db::{AccountEntity, PermissionEntity}; @@ -6,7 +7,7 @@ use super::AccountType; #[derive(Debug, Serialize)] pub struct AccountCreationResponse { - pub id: i32, + pub id: Uuid, pub r#type: AccountType, pub name: String, pub description: Option, diff --git a/api/src/requests/account/read/models/response.rs b/api/src/requests/account/read/models/response.rs index b9a7580..03b9f2e 100644 --- a/api/src/requests/account/read/models/response.rs +++ b/api/src/requests/account/read/models/response.rs @@ -1,10 +1,11 @@ use serde::Serialize; +use uuid::Uuid; use crate::db::{AccountType, AccountWithPermissionValueEntity}; #[derive(Debug, Serialize)] pub struct AccountsReadAllResponse { - pub id: i32, + pub id: Uuid, pub account_type: AccountType, pub name: String, pub description: Option,