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
67#[derive(Debug)]
68pub struct CreateGeneratedFile {
69 pub id: Uuid,
70 pub file_id: FileId,
71 pub mime: String,
72 pub ty: GeneratedFileType,
73 pub hash: String,
74 pub file_key: String,
75 pub created_at: DateTime<Utc>,
76}
77
78impl GeneratedFile {
79 pub async fn create(
80 db: impl DbExecutor<'_>,
81 CreateGeneratedFile {
82 id,
83 file_id,
84 ty,
85 hash,
86 file_key,
87 mime,
88 created_at,
89 }: CreateGeneratedFile,
90 ) -> DbResult<GeneratedFile> {
91 sqlx::query(
92 r#"
93 INSERT INTO "docbox_generated_files"
94 ("id", "file_id", "mime", "type", "hash", "file_key", "created_at")
95 VALUES ($1, $2, $3, $4, $5, $6, $7)
96 "#,
97 )
98 .bind(id)
99 .bind(file_id)
100 .bind(mime.as_str())
101 .bind(ty.to_string())
102 .bind(hash.as_str())
103 .bind(file_key.as_str())
104 .bind(created_at)
105 .execute(db)
106 .await?;
107
108 Ok(GeneratedFile {
109 id,
110 file_id,
111 mime,
112 ty,
113 hash,
114 file_key,
115 created_at,
116 })
117 }
118
119 pub async fn delete(self, db: impl DbExecutor<'_>) -> DbResult<()> {
121 sqlx::query(r#"DELETE FROM "docbox_generated_files" WHERE "id" = $1"#)
122 .bind(self.id)
123 .execute(db)
124 .await?;
125
126 Ok(())
127 }
128
129 pub async fn find_all(
130 db: impl DbExecutor<'_>,
131 file_id: FileId,
132 ) -> DbResult<Vec<GeneratedFile>> {
133 sqlx::query_as(r#"SELECT * FROM "docbox_generated_files" WHERE "file_id" = $1"#)
134 .bind(file_id)
135 .fetch_all(db)
136 .await
137 }
138
139 pub async fn find(
141 db: impl DbExecutor<'_>,
142 scope: &DocumentBoxScopeRaw,
143 file_id: FileId,
144 ty: GeneratedFileType,
145 ) -> DbResult<Option<GeneratedFile>> {
146 sqlx::query_as(
147 r#"
148 SELECT "gen".*
149 FROM "docbox_generated_files" "gen"
150 -- Join on the file itself
151 INNER JOIN "docbox_files" "file" ON "gen".file_id = "file"."id"
152 -- Join to the file parent folder
153 INNER JOIN "docbox_folders" "folder" ON "file"."folder_id" = "folder"."id"
154 -- Only find the matching type for the specified file
155 WHERE "file"."id" = $1 AND "folder"."document_box" = $2 AND "gen"."type" = $3
156 "#,
157 )
158 .bind(file_id)
159 .bind(scope)
160 .bind(ty.to_string())
161 .fetch_optional(db)
162 .await
163 }
164}