use derive_builder::Builder; use serde::{Deserialize, Serialize}; use sqlx::query_as; use uuid::Uuid; use crate::client::AppDbClient; /// Assigns an access control permission on a workspace to a user. These are /// derived from the permission grants of the workspace's backing database. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct WorkspaceMembership { /// Primary key (defaults to UUIDv7). pub id: Uuid, /// Workspace to which the permission belongs. pub workspace_id: Uuid, /// **Synthesized field** generated by joining to the `workspaces` table. pub workspace_display_name: String, /// User to which the permission belongs. pub user_id: Uuid, } impl WorkspaceMembership { /// Construct a single-field query to fetch workspace permissions assigned /// to a user. pub fn belonging_to_user(id: Uuid) -> BelongingToUserQuery { BelongingToUserQuery { id } } /// Build an insert statement to create a new object. pub fn insert() -> InsertBuilder { InsertBuilder::default() } } #[derive(Clone, Debug)] pub struct BelongingToUserQuery { id: Uuid, } impl BelongingToUserQuery { pub async fn fetch_all( self, app_db: &mut AppDbClient, ) -> Result, sqlx::Error> { query_as!( WorkspaceMembership, r#" select p.id as id, p.workspace_id as workspace_id, p.user_id as user_id, w.display_name as workspace_display_name from workspace_memberships as p inner join workspaces as w on w.id = p.workspace_id where p.user_id = $1 "#, self.id, ) .fetch_all(app_db.get_conn()) .await } } #[derive(Builder, Clone, Debug)] pub struct Insert { workspace_id: Uuid, user_id: Uuid, } impl Insert { pub async fn execute( self, app_db: &mut AppDbClient, ) -> Result { query_as!( WorkspaceMembership, r#" with p as ( insert into workspace_memberships (workspace_id, user_id) values ($1, $2) returning id, workspace_id, user_id ) select p.id as id, p.workspace_id as workspace_id, p.user_id as user_id, w.display_name as workspace_display_name from p inner join workspaces as w on w.id = p.workspace_id "#, self.workspace_id, self.user_id, ) .fetch_one(app_db.get_conn()) .await } }