Use UUIDs for publically-facing exposed primary keys
This commit is contained in:
parent
7f2e7e8e8d
commit
efd9e80633
7 changed files with 42 additions and 18 deletions
|
@ -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"] }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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<String>,
|
||||
|
@ -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<String>,
|
||||
|
|
|
@ -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<Vec<PermissionEntity>, 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::<Vec<_>>()
|
||||
.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))
|
||||
|
|
|
@ -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<String>,
|
||||
|
|
|
@ -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<String>,
|
||||
|
|
Loading…
Add table
Reference in a new issue