use anyhow::anyhow; use app_error::AppError; use chrono::{DateTime, Utc}; use database_entity::dto::{ AFAccessLevel, AFRole, AFUserProfile, AFWebUser, AFWorkspace, AFWorkspaceInvitationStatus, AccessRequestMinimal, AccessRequestStatus, AccessRequestWithViewId, AccessRequesterInfo, AccountLink, GlobalComment, Reaction, Template, TemplateCategory, TemplateCategoryMinimal, TemplateCategoryType, TemplateCreator, TemplateCreatorMinimal, TemplateGroup, TemplateMinimal, }; use serde::{Deserialize, Serialize}; use sqlx::FromRow; use uuid::Uuid; /// Represent the row of the af_workspace table #[derive(Debug, Clone, FromRow, Serialize, Deserialize, sqlx::Type)] pub struct AFWorkspaceRow { pub workspace_id: Uuid, pub database_storage_id: Option, pub owner_uid: Option, pub owner_name: Option, pub owner_email: Option, pub created_at: Option>, pub workspace_type: i32, pub deleted_at: Option>, pub workspace_name: Option, pub icon: Option, } impl TryFrom for AFWorkspace { type Error = AppError; fn try_from(value: AFWorkspaceRow) -> Result { let owner_uid = value .owner_uid .ok_or(AppError::Internal(anyhow!("Unexpected empty owner_uid")))?; let database_storage_id = value .database_storage_id .ok_or(AppError::Internal(anyhow!("Unexpected empty workspace_id")))?; let workspace_name = value.workspace_name.unwrap_or_default(); let created_at = value.created_at.unwrap_or_else(Utc::now); let icon = value.icon.unwrap_or_default(); Ok(Self { workspace_id: value.workspace_id, database_storage_id, owner_uid, owner_name: value.owner_name.unwrap_or_default(), owner_email: value.owner_email.unwrap_or_default(), workspace_type: value.workspace_type, workspace_name, created_at, icon, member_count: None, }) } } #[derive(Debug, Clone, FromRow, Serialize, Deserialize, sqlx::Type)] pub struct AFWorkspaceWithMemberCountRow { pub workspace_id: Uuid, pub database_storage_id: Option, pub owner_uid: Option, pub owner_name: Option, pub owner_email: Option, pub created_at: Option>, pub workspace_type: i32, pub deleted_at: Option>, pub workspace_name: Option, pub icon: Option, pub member_count: i64, } impl TryFrom for AFWorkspace { type Error = AppError; fn try_from(value: AFWorkspaceWithMemberCountRow) -> Result { let owner_uid = value .owner_uid .ok_or(AppError::Internal(anyhow!("Unexpected empty owner_uid")))?; let database_storage_id = value .database_storage_id .ok_or(AppError::Internal(anyhow!("Unexpected empty workspace_id")))?; let workspace_name = value.workspace_name.unwrap_or_default(); let created_at = value.created_at.unwrap_or_else(Utc::now); let icon = value.icon.unwrap_or_default(); Ok(Self { workspace_id: value.workspace_id, database_storage_id, owner_uid, owner_name: value.owner_name.unwrap_or_default(), owner_email: value.owner_email.unwrap_or_default(), workspace_type: value.workspace_type, workspace_name, created_at, icon, member_count: Some(value.member_count), }) } } /// Represent the row of the af_user table #[derive(Debug, FromRow, Deserialize, Serialize, Clone)] pub struct AFUserRow { pub uid: i64, pub uuid: Option, pub email: Option, pub password: Option, pub name: Option, pub metadata: Option, pub encryption_sign: Option, pub deleted_at: Option>, pub updated_at: Option>, pub created_at: Option>, } #[derive(Debug, FromRow)] pub struct AFUserIdRow { pub uid: i64, pub uuid: Uuid, } /// Represent the row of the af_user_profile_view #[derive(Debug, FromRow, Deserialize, Serialize)] pub struct AFUserProfileRow { pub uid: Option, pub uuid: Option, pub email: Option, pub password: Option, pub name: Option, pub metadata: Option, pub encryption_sign: Option, pub deleted_at: Option>, pub updated_at: Option>, pub created_at: Option>, pub latest_workspace_id: Option, } impl TryFrom for AFUserProfile { type Error = AppError; fn try_from(value: AFUserProfileRow) -> Result { let uid = value .uid .ok_or(AppError::Internal(anyhow!("Unexpected empty uid")))?; let uuid = value .uuid .ok_or(AppError::Internal(anyhow!("Unexpected empty uuid")))?; let latest_workspace_id = value.latest_workspace_id.ok_or(AppError::Internal(anyhow!( "Unexpected empty latest_workspace_id" )))?; Ok(Self { uid, uuid, email: value.email, password: value.password, name: value.name, metadata: value.metadata, encryption_sign: value.encryption_sign, latest_workspace_id, updated_at: value.updated_at.map(|v| v.timestamp()).unwrap_or(0), }) } } #[derive(FromRow, Serialize, Deserialize)] pub struct AFWorkspaceMemberPermRow { pub uid: i64, pub role: AFRole, pub workspace_id: Uuid, } #[derive(Debug, FromRow, Serialize, Deserialize)] pub struct AFWorkspaceMemberRow { pub uid: i64, pub name: String, pub email: String, pub role: AFRole, } #[derive(FromRow)] pub struct AFCollabMemberAccessLevelRow { pub uid: i64, pub oid: String, pub access_level: AFAccessLevel, } #[derive(FromRow, Clone, Debug, Serialize, Deserialize)] pub struct AFCollabMemberRow { pub uid: i64, pub oid: String, pub permission_id: i64, } #[derive(Debug, FromRow, Serialize, Deserialize)] pub struct AFBlobMetadataRow { pub workspace_id: Uuid, pub file_id: String, pub file_type: String, pub file_size: i64, pub modified_at: DateTime, } #[derive(Debug, Deserialize, Serialize, Clone)] pub struct AFUserNotification { pub payload: Option, } #[derive(FromRow, Debug, Clone)] pub struct AFPermissionRow { pub id: i32, pub name: String, pub access_level: AFAccessLevel, pub description: Option, } #[derive(FromRow, Serialize, Deserialize)] pub struct AFSnapshotRow { pub sid: i64, pub oid: String, pub blob: Vec, pub len: Option, pub encrypt: Option, pub deleted_at: Option>, pub created_at: DateTime, pub workspace_id: Uuid, } #[derive(Debug, FromRow, Deserialize, Serialize)] pub struct AFWorkspaceInvitationMinimal { pub workspace_id: Uuid, pub inviter_uid: i64, pub invitee_uid: Option, pub status: AFWorkspaceInvitationStatus, pub role: AFRole, } #[derive(FromRow, Clone, Debug)] pub struct AFCollabRowMeta { pub oid: String, pub workspace_id: Uuid, pub deleted_at: Option>, pub created_at: Option>, } #[derive(Debug, Clone, FromRow, Serialize, Deserialize)] pub struct AFChatRow { pub chat_id: Uuid, pub name: String, pub created_at: DateTime, pub deleted_at: Option>, pub rag_ids: serde_json::Value, pub workspace_id: Uuid, pub meta_data: serde_json::Value, } #[derive(Debug, Clone, FromRow, Serialize, Deserialize)] pub struct AFChatMessageRow { pub message_id: i64, pub chat_id: Uuid, pub content: String, pub created_at: DateTime, } #[derive(sqlx::Type, Serialize, Debug)] pub struct AFWebUserColumn { uuid: Uuid, name: String, avatar_url: Option, } impl From for AFWebUser { fn from(val: AFWebUserColumn) -> Self { AFWebUser { uuid: val.uuid, name: val.name, avatar_url: val.avatar_url, } } } pub struct AFGlobalCommentRow { pub user: Option, pub created_at: DateTime, pub last_updated_at: DateTime, pub content: String, pub reply_comment_id: Option, pub comment_id: Uuid, pub is_deleted: bool, pub can_be_deleted: bool, } impl From for GlobalComment { fn from(val: AFGlobalCommentRow) -> Self { GlobalComment { user: val.user.map(|x| x.into()), created_at: val.created_at, last_updated_at: val.last_updated_at, content: val.content, reply_comment_id: val.reply_comment_id, comment_id: val.comment_id, is_deleted: val.is_deleted, can_be_deleted: val.can_be_deleted, } } } pub struct AFReactionRow { pub reaction_type: String, pub react_users: Vec, pub comment_id: Uuid, } impl From for Reaction { fn from(val: AFReactionRow) -> Self { Reaction { reaction_type: val.reaction_type, react_users: val.react_users.into_iter().map(|x| x.into()).collect(), comment_id: val.comment_id, } } } #[derive(Debug, FromRow, Serialize, sqlx::Type)] pub struct AFTemplateCategoryRow { pub category_id: Uuid, pub name: String, pub icon: String, pub bg_color: String, pub description: String, pub category_type: AFTemplateCategoryTypeColumn, pub priority: i32, } impl From for TemplateCategory { fn from(value: AFTemplateCategoryRow) -> Self { Self { id: value.category_id, name: value.name, icon: value.icon, bg_color: value.bg_color, description: value.description, category_type: value.category_type.into(), priority: value.priority, } } } #[derive(Debug, FromRow, Serialize, sqlx::Type)] #[sqlx(type_name = "template_category_minimal_type")] pub struct AFTemplateCategoryMinimalRow { pub category_id: Uuid, pub name: String, pub icon: String, pub bg_color: String, } impl From for TemplateCategoryMinimal { fn from(value: AFTemplateCategoryMinimalRow) -> Self { Self { id: value.category_id, name: value.name, icon: value.icon, bg_color: value.bg_color, } } } #[derive(sqlx::Type, Serialize, Debug)] #[repr(i32)] pub enum AFTemplateCategoryTypeColumn { UseCase = 0, Feature = 1, } impl From for TemplateCategoryType { fn from(value: AFTemplateCategoryTypeColumn) -> Self { match value { AFTemplateCategoryTypeColumn::UseCase => TemplateCategoryType::UseCase, AFTemplateCategoryTypeColumn::Feature => TemplateCategoryType::Feature, } } } impl From for AFTemplateCategoryTypeColumn { fn from(val: TemplateCategoryType) -> Self { match val { TemplateCategoryType::UseCase => AFTemplateCategoryTypeColumn::UseCase, TemplateCategoryType::Feature => AFTemplateCategoryTypeColumn::Feature, } } } #[derive(sqlx::Type, Serialize, Debug)] #[sqlx(type_name = "account_link_type")] pub struct AccountLinkColumn { pub link_type: String, pub url: String, } impl From for AccountLink { fn from(value: AccountLinkColumn) -> Self { Self { link_type: value.link_type, url: value.url, } } } #[derive(Debug, Serialize, sqlx::Type)] #[sqlx(type_name = "template_creator_type")] pub struct AFTemplateCreatorRow { pub id: Uuid, pub name: String, pub avatar_url: String, pub account_links: Option>, pub number_of_templates: i32, } impl From for TemplateCreator { fn from(value: AFTemplateCreatorRow) -> Self { let account_links = value .account_links .unwrap_or_default() .into_iter() .map(|v| v.into()) .collect(); Self { id: value.id, name: value.name, avatar_url: value.avatar_url, account_links, number_of_templates: value.number_of_templates, } } } #[derive(Debug, Serialize, sqlx::Type)] #[sqlx(type_name = "template_creator_minimal_type")] pub struct AFTemplateCreatorMinimalColumn { pub creator_id: Uuid, pub name: String, pub avatar_url: String, } impl From for TemplateCreatorMinimal { fn from(value: AFTemplateCreatorMinimalColumn) -> Self { Self { id: value.creator_id, name: value.name, avatar_url: value.avatar_url, } } } #[derive(Debug, Serialize, FromRow, sqlx::Type)] #[sqlx(type_name = "template_minimal_type")] pub struct AFTemplateMinimalRow { pub view_id: Uuid, pub created_at: DateTime, pub updated_at: DateTime, pub name: String, pub description: String, pub view_url: String, pub creator: AFTemplateCreatorMinimalColumn, pub categories: Vec, pub is_new_template: bool, pub is_featured: bool, } impl From for TemplateMinimal { fn from(value: AFTemplateMinimalRow) -> Self { Self { view_id: value.view_id, created_at: value.created_at, last_updated_at: value.updated_at, name: value.name, description: value.description, creator: value.creator.into(), categories: value.categories.into_iter().map(|x| x.into()).collect(), view_url: value.view_url, is_new_template: value.is_new_template, is_featured: value.is_featured, } } } #[derive(Debug, Serialize, sqlx::Type)] pub struct AFTemplateRow { pub view_id: Uuid, pub created_at: DateTime, pub updated_at: DateTime, pub name: String, pub description: String, pub about: String, pub view_url: String, pub creator: AFTemplateCreatorRow, pub categories: Vec, pub related_templates: Vec, pub is_new_template: bool, pub is_featured: bool, } impl From for Template { fn from(value: AFTemplateRow) -> Self { let mut related_templates: Vec = value .related_templates .into_iter() .map(|v| v.into()) .collect(); related_templates.sort_by_key(|t| t.created_at); related_templates.reverse(); Self { view_id: value.view_id, created_at: value.created_at, last_updated_at: value.updated_at, name: value.name, description: value.description, about: value.about, view_url: value.view_url, creator: value.creator.into(), categories: value.categories.into_iter().map(|v| v.into()).collect(), related_templates, is_new_template: value.is_new_template, is_featured: value.is_featured, } } } #[derive(Debug, Serialize, sqlx::Type)] pub struct AFTemplateGroupRow { pub category: AFTemplateCategoryMinimalRow, pub templates: Vec, } impl From for TemplateGroup { fn from(value: AFTemplateGroupRow) -> Self { let mut templates: Vec = value.templates.into_iter().map(|v| v.into()).collect(); templates.sort_by_key(|t| t.created_at); templates.reverse(); Self { category: value.category.into(), templates, } } } #[derive(Debug, FromRow, Serialize, Deserialize)] pub struct AFImportTask { pub task_id: Uuid, pub file_size: i64, pub workspace_id: String, pub created_by: i64, pub status: i16, pub metadata: serde_json::Value, pub created_at: DateTime, #[serde(default)] pub file_url: Option, } #[derive(sqlx::Type, Serialize, Deserialize, Debug)] #[repr(i32)] pub enum AFAccessRequestStatusColumn { Pending = 0, Approved = 1, Rejected = 2, } impl From for AccessRequestStatus { fn from(value: AFAccessRequestStatusColumn) -> Self { match value { AFAccessRequestStatusColumn::Pending => AccessRequestStatus::Pending, AFAccessRequestStatusColumn::Approved => AccessRequestStatus::Approved, AFAccessRequestStatusColumn::Rejected => AccessRequestStatus::Rejected, } } } #[derive(sqlx::Type, Serialize, Debug)] pub struct AFAccessRequesterColumn { pub uid: i64, pub uuid: Uuid, pub name: String, pub email: String, pub avatar_url: Option, } impl From for AccessRequesterInfo { fn from(value: AFAccessRequesterColumn) -> Self { Self { uid: value.uid, uuid: value.uuid, name: value.name, email: value.email, avatar_url: value.avatar_url, } } } #[derive(sqlx::Type, Serialize, Debug)] pub struct AFAccessRequestMinimalColumn { pub request_id: Uuid, pub workspace_id: Uuid, pub requester_id: Uuid, pub view_id: Uuid, } impl From for AccessRequestMinimal { fn from(value: AFAccessRequestMinimalColumn) -> Self { Self { request_id: value.request_id, workspace_id: value.workspace_id, requester_id: value.requester_id, view_id: value.view_id, } } } #[derive(Serialize, Deserialize, Debug)] pub struct AFAccessRequestWithViewIdColumn { pub request_id: Uuid, pub workspace: AFWorkspaceWithMemberCountRow, pub requester: AccessRequesterInfo, pub view_id: Uuid, pub status: AFAccessRequestStatusColumn, pub created_at: DateTime, } impl TryFrom for AccessRequestWithViewId { type Error = anyhow::Error; fn try_from(value: AFAccessRequestWithViewIdColumn) -> Result { Ok(Self { request_id: value.request_id, workspace: value.workspace.try_into()?, requester: value.requester, view_id: value.view_id, status: value.status.into(), created_at: value.created_at, }) } }