diff --git a/migrations/0003_create_organizations_table.sql b/migrations/0003_create_organizations_table.sql new file mode 100644 index 0000000..e9ab826 --- /dev/null +++ b/migrations/0003_create_organizations_table.sql @@ -0,0 +1,7 @@ +create table organizations ( + id uuid primary key default uuidv4(), + name varchar(255) not null, + slug varchar(255) not null unique, -- acme-corp-a7x9 + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); diff --git a/migrations/0004_create_org_membership_table.sql b/migrations/0004_create_org_membership_table.sql new file mode 100644 index 0000000..375a1eb --- /dev/null +++ b/migrations/0004_create_org_membership_table.sql @@ -0,0 +1,13 @@ + +CREATE TYPE org_role AS ENUM ('owner', 'admin', 'member', 'viewer'); + +CREATE TABLE org_memberships ( + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + org_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, + role org_role NOT NULL, + + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + + PRIMARY KEY (user_id, org_id) +); diff --git a/src/db/model/mod.rs b/src/db/model/mod.rs index 4afde74..e5b0708 100644 --- a/src/db/model/mod.rs +++ b/src/db/model/mod.rs @@ -1,2 +1,3 @@ +pub mod organization; pub mod refresh_token; pub mod user; diff --git a/src/db/model/organization.rs b/src/db/model/organization.rs new file mode 100644 index 0000000..59e5a7c --- /dev/null +++ b/src/db/model/organization.rs @@ -0,0 +1,34 @@ +use sqlx::{ + prelude::FromRow, + types::{ + Uuid, + chrono::{DateTime, Utc}, + }, +}; + +#[derive(Debug, FromRow)] +pub struct Organization { + pub id: Uuid, + pub name: String, + pub slug: String, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +#[derive(sqlx::Type, Debug, Clone, PartialEq)] +#[sqlx(type_name = "org_role", rename_all = "lowercase")] +pub enum OrgRole { + Owner, + Admin, + Member, + Viewer, +} + +#[derive(Debug, FromRow)] +pub struct OrgMember { + pub user_id: Uuid, + pub org_id: Uuid, + pub role: OrgRole, + pub created_at: DateTime, + pub updated_at: DateTime, +} diff --git a/src/db/repository/mod.rs b/src/db/repository/mod.rs index dc277ef..7d60ffb 100644 --- a/src/db/repository/mod.rs +++ b/src/db/repository/mod.rs @@ -1,2 +1,3 @@ +pub mod organization_repository; pub mod refresh_token_repository; pub mod user_repository; diff --git a/src/db/repository/organization_repository.rs b/src/db/repository/organization_repository.rs new file mode 100644 index 0000000..d178880 --- /dev/null +++ b/src/db/repository/organization_repository.rs @@ -0,0 +1,44 @@ +use sqlx::{Executor, Postgres}; +use uuid::Uuid; + +use crate::{db::model::organization::Organization, errors::AppError}; + +pub async fn create_organization<'e, E>( + executor: E, + name: String, + slug: String, +) -> Result +where + E: Executor<'e, Database = Postgres>, +{ + let org = sqlx::query_as!( + Organization, + "insert into organizations (name, slug) values ($1, $2) returning *", + name, + slug + ) + .fetch_one(executor) + .await + .map_err(AppError::from)?; + + Ok(org) +} + +pub async fn get_organizations_by_id_list<'e, E>( + executor: E, + ids: &[Uuid], +) -> Result, AppError> +where + E: Executor<'e, Database = Postgres>, +{ + let org = sqlx::query_as!( + Organization, + "select * from organizations where id = any($1)", + ids + ) + .fetch_all(executor) + .await + .map_err(AppError::from)?; + + Ok(org) +}