docbox_database/models/
generated_file.rs1use std::str::FromStr;
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use sqlx::prelude::FromRow;
6use utoipa::ToSchema;
7use uuid::Uuid;
8
9use super::{document_box::DocumentBoxScopeRaw, file::FileId};
10use crate::{DbExecutor, DbResult};
11
12pub type GeneratedFileId = Uuid;
13
14#[derive(
15 Debug, Clone, Copy, strum::EnumString, strum::Display, Deserialize, Serialize, ToSchema,
16)]
17pub enum GeneratedFileType {
18 Pdf,
20 CoverPage,
22 SmallThumbnail,
24 LargeThumbnail,
26 TextContent,
28 HtmlContent,
30 Metadata,
33}
34
35impl TryFrom<String> for GeneratedFileType {
36 type Error = strum::ParseError;
37 fn try_from(value: String) -> Result<Self, Self::Error> {
38 GeneratedFileType::from_str(&value)
39 }
40}
41
42#[derive(Debug, FromRow, Serialize, ToSchema)]
44pub struct GeneratedFile {
45 #[schema(value_type = Uuid)]
47 pub id: GeneratedFileId,
48 #[schema(value_type = Uuid)]
50 pub file_id: FileId,
51 pub mime: String,
53 #[sqlx(rename = "type")]
55 #[serde(rename = "type")]
56 #[sqlx(try_from = "String")]
57 pub ty: GeneratedFileType,
58 pub hash: String,
60 #[serde(skip)]
62 pub file_key: String,
63 pub created_at: DateTime<Utc>,
65}
66
67pub struct CreateGeneratedFile {
68 pub file_id: FileId,
69 pub mime: String,
70 pub ty: GeneratedFileType,
71 pub hash: String,
72 pub file_key: String,
73}
74
75impl GeneratedFile {
76 pub async fn create(
77 db: impl DbExecutor<'_>,
78 CreateGeneratedFile {
79 file_id,
80 ty,
81 hash,
82 file_key,
83 mime,
84 }: CreateGeneratedFile,
85 ) -> DbResult<GeneratedFile> {
86 let id = Uuid::new_v4();
87 let created_at = Utc::now();
88
89 sqlx::query(
90 r#"
91 INSERT INTO "docbox_generated_files"
92 ("id", "file_id", "mime", "type", "hash", "file_key", "created_at")
93 VALUES ($1, $2, $3, $4, $5, $6, $7)
94 "#,
95 )
96 .bind(id)
97 .bind(file_id)
98 .bind(mime.as_str())
99 .bind(ty.to_string())
100 .bind(hash.as_str())
101 .bind(file_key.as_str())
102 .bind(created_at)
103 .execute(db)
104 .await?;
105
106 Ok(GeneratedFile {
107 id,
108 file_id,
109 mime,
110 ty,
111 hash,
112 file_key,
113 created_at,
114 })
115 }
116
117 pub async fn delete(self, db: impl DbExecutor<'_>) -> DbResult<()> {
119 sqlx::query(r#"DELETE FROM "docbox_generated_files" WHERE "id" = $1"#)
120 .bind(self.id)
121 .execute(db)
122 .await?;
123
124 Ok(())
125 }
126
127 pub async fn find_all(
128 db: impl DbExecutor<'_>,
129 file_id: FileId,
130 ) -> DbResult<Vec<GeneratedFile>> {
131 sqlx::query_as(r#"SELECT * FROM "docbox_generated_files" WHERE "file_id" = $1"#)
132 .bind(file_id)
133 .fetch_all(db)
134 .await
135 }
136
137 pub async fn find(
139 db: impl DbExecutor<'_>,
140 scope: &DocumentBoxScopeRaw,
141 file_id: FileId,
142 ty: GeneratedFileType,
143 ) -> DbResult<Option<GeneratedFile>> {
144 sqlx::query_as(
145 r#"
146 SELECT "gen".*
147 FROM "docbox_generated_files" "gen"
148 -- Join on the file itself
149 INNER JOIN "docbox_files" "file" ON "gen".file_id = "file"."id"
150 -- Join to the file parent folder
151 INNER JOIN "docbox_folders" "folder" ON "file"."folder_id" = "folder"."id"
152 -- Only find the matching type for the specified file
153 WHERE "file"."id" = $1 AND "folder"."document_box" = $2 AND "gen"."type" = $3
154 "#,
155 )
156 .bind(file_id)
157 .bind(scope)
158 .bind(ty.to_string())
159 .fetch_optional(db)
160 .await
161 }
162}