1use crate::{DbExecutor, DbResult};
2use serde::{Deserialize, Serialize};
3use sqlx::prelude::FromRow;
4use uuid::Uuid;
5
6pub type TenantId = Uuid;
7
8use crate::utils::update_if_some;
9
10#[derive(Debug, Clone, FromRow, Serialize, PartialEq, Eq)]
11pub struct Tenant {
12 pub id: TenantId,
14 pub name: String,
16 pub db_name: String,
18 pub db_secret_name: Option<String>,
21 #[sqlx(default)]
24 pub db_iam_user_name: Option<String>,
25 pub s3_name: String,
27 pub os_index_name: String,
29 pub env: String,
31 pub event_queue_url: Option<String>,
33}
34
35pub struct CreateTenant {
38 pub id: TenantId,
39 pub name: String,
40 pub db_name: String,
41 pub db_iam_user_name: Option<String>,
42 pub db_secret_name: Option<String>,
43 pub s3_name: String,
44 pub os_index_name: String,
45 pub event_queue_url: Option<String>,
46 pub env: String,
47}
48
49#[derive(Debug, Default, Clone, Serialize, Deserialize)]
51#[serde(default)]
52pub struct UpdateTenant {
53 pub id: Option<TenantId>,
54 pub name: Option<String>,
55 pub db_name: Option<String>,
56 pub db_secret_name: Option<Option<String>>,
57 pub db_iam_user_name: Option<Option<String>>,
58 pub s3_name: Option<String>,
59 pub os_index_name: Option<String>,
60 pub env: Option<String>,
61 pub event_queue_url: Option<Option<String>>,
62}
63
64impl Tenant {
65 pub async fn create(db: impl DbExecutor<'_>, create: CreateTenant) -> DbResult<Tenant> {
67 sqlx::query(
68 r#"
69 INSERT INTO "docbox_tenants" (
70 "id",
71 "name",
72 "db_name",
73 "db_iam_user_name",
74 "db_secret_name",
75 "s3_name",
76 "os_index_name",
77 "env",
78 "event_queue_url"
79 )
80 VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
81 "#,
82 )
83 .bind(create.id)
84 .bind(create.name.as_str())
85 .bind(create.db_name.as_str())
86 .bind(create.db_iam_user_name.clone())
87 .bind(create.db_secret_name.clone())
88 .bind(create.s3_name.as_str())
89 .bind(create.os_index_name.as_str())
90 .bind(create.env.as_str())
91 .bind(create.event_queue_url.as_ref())
92 .execute(db)
93 .await?;
94
95 Ok(Tenant {
96 id: create.id,
97 name: create.name,
98 db_name: create.db_name,
99 db_iam_user_name: create.db_iam_user_name,
100 db_secret_name: create.db_secret_name,
101 s3_name: create.s3_name,
102 os_index_name: create.os_index_name,
103 env: create.env,
104 event_queue_url: create.event_queue_url,
105 })
106 }
107
108 pub async fn update(
110 &mut self,
111 db: impl DbExecutor<'_>,
112 UpdateTenant {
113 id,
114 name,
115 db_name,
116 db_secret_name,
117 db_iam_user_name,
118 s3_name,
119 os_index_name,
120 env,
121 event_queue_url,
122 }: UpdateTenant,
123 ) -> DbResult<()> {
124 sqlx::query(
125 r#"
126 UPDATE "docbox_tenants"
127 SET
128 "id" = COALESCE($3, "id"),
129 "name" = COALESCE($4, "name"),
130 "db_name" = COALESCE($5, "db_name"),
131 "db_secret_name" = COALESCE($6, "db_secret_name"),
132 "db_iam_user_name" = COALESCE($7, "db_iam_user_name"),
133 "s3_name" = COALESCE($8, "s3_name"),
134 "os_index_name" = COALESCE($9, "os_index_name"),
135 "env" = COALESCE($10, "env"),
136 "event_queue_url" = COALESCE($11, "event_queue_url")
137 WHERE "id" = $1 AND "env" = $2
138 "#,
139 )
140 .bind(self.id)
142 .bind(self.env.clone())
143 .bind(id)
145 .bind(name.clone())
146 .bind(db_name.clone())
147 .bind(db_secret_name.clone())
148 .bind(db_iam_user_name.clone())
149 .bind(s3_name.clone())
150 .bind(os_index_name.clone())
151 .bind(env.clone())
152 .bind(event_queue_url.clone())
153 .fetch_optional(db)
154 .await?;
155
156 update_if_some!(
157 self,
158 id,
159 name,
160 db_name,
161 db_secret_name,
162 db_iam_user_name,
163 s3_name,
164 os_index_name,
165 env,
166 event_queue_url,
167 );
168
169 Ok(())
170 }
171
172 pub async fn find_by_id(
174 db: impl DbExecutor<'_>,
175 id: TenantId,
176 env: &str,
177 ) -> DbResult<Option<Tenant>> {
178 sqlx::query_as(r#"SELECT * FROM "docbox_tenants" WHERE "id" = $1 AND "env" = $2"#)
179 .bind(id)
180 .bind(env)
181 .fetch_optional(db)
182 .await
183 }
184
185 pub async fn find_by_bucket(db: impl DbExecutor<'_>, bucket: &str) -> DbResult<Option<Tenant>> {
187 sqlx::query_as(r#"SELECT * FROM "docbox_tenants" WHERE "s3_name" = $1"#)
188 .bind(bucket)
189 .fetch_optional(db)
190 .await
191 }
192
193 pub async fn find_by_env(db: impl DbExecutor<'_>, env: &str) -> DbResult<Vec<Tenant>> {
195 sqlx::query_as(r#"SELECT * FROM "docbox_tenants" WHERE "env" = $1 ORDER BY "name""#)
196 .bind(env)
197 .fetch_all(db)
198 .await
199 }
200
201 pub async fn all(db: impl DbExecutor<'_>) -> DbResult<Vec<Tenant>> {
203 sqlx::query_as(r#"SELECT * FROM "docbox_tenants" ORDER BY "name""#)
204 .fetch_all(db)
205 .await
206 }
207
208 pub async fn delete(self, db: impl DbExecutor<'_>) -> DbResult<()> {
210 sqlx::query(r#"DELETE FROM "docbox_tenants" WHERE "id" = $1 AND "env" = $2"#)
211 .bind(self.id)
212 .bind(&self.env)
213 .execute(db)
214 .await?;
215 Ok(())
216 }
217}