Skip to main content

docbox_database/models/
tenant.rs

1use crate::{DbExecutor, DbResult};
2use serde::Serialize;
3use sqlx::prelude::FromRow;
4use uuid::Uuid;
5
6pub type TenantId = Uuid;
7
8#[derive(Debug, Clone, FromRow, Serialize, PartialEq, Eq)]
9pub struct Tenant {
10    /// Unique ID for the tenant
11    pub id: TenantId,
12    /// Name for the tenant
13    pub name: String,
14    /// Name of the tenant database
15    pub db_name: String,
16    /// Name for the AWS secret used for the database user if
17    /// using secret based authentication
18    pub db_secret_name: Option<String>,
19    /// Name for the database user username if using IAM based
20    /// authentication
21    #[sqlx(default)]
22    pub db_iam_user_name: Option<String>,
23    /// Name of the tenant s3 bucket
24    pub s3_name: String,
25    /// Name of the tenant search index
26    pub os_index_name: String,
27    /// Environment for the tenant
28    pub env: String,
29    /// Optional event queue (SQS) to send docbox events to
30    pub event_queue_url: Option<String>,
31}
32
33pub struct CreateTenant {
34    pub id: TenantId,
35    pub name: String,
36    pub db_name: String,
37    pub db_iam_user_name: Option<String>,
38    pub db_secret_name: Option<String>,
39    pub s3_name: String,
40    pub os_index_name: String,
41    pub event_queue_url: Option<String>,
42    pub env: String,
43}
44
45impl Tenant {
46    /// Create a new tenant
47    pub async fn create(db: impl DbExecutor<'_>, create: CreateTenant) -> DbResult<Tenant> {
48        sqlx::query(
49            r#"
50            INSERT INTO "docbox_tenants" (
51                "id",
52                "name",
53                "db_name",
54                "db_iam_user_name",
55                "db_secret_name",
56                "s3_name",
57                "os_index_name",
58                "env",
59                "event_queue_url"
60            )
61            VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
62        "#,
63        )
64        .bind(create.id)
65        .bind(create.name.as_str())
66        .bind(create.db_name.as_str())
67        .bind(create.db_iam_user_name.clone())
68        .bind(create.db_secret_name.clone())
69        .bind(create.s3_name.as_str())
70        .bind(create.os_index_name.as_str())
71        .bind(create.env.as_str())
72        .bind(create.event_queue_url.as_ref())
73        .execute(db)
74        .await?;
75
76        Ok(Tenant {
77            id: create.id,
78            name: create.name,
79            db_name: create.db_name,
80            db_iam_user_name: create.db_iam_user_name,
81            db_secret_name: create.db_secret_name,
82            s3_name: create.s3_name,
83            os_index_name: create.os_index_name,
84            env: create.env,
85            event_queue_url: create.event_queue_url,
86        })
87    }
88
89    /// Update the "db_iam_user_name" property of the tenant
90    pub async fn set_db_iam_user_name(
91        &mut self,
92        db: impl DbExecutor<'_>,
93        iam_user_name: Option<String>,
94    ) -> DbResult<Option<Tenant>> {
95        sqlx::query_as(
96            r#"UPDATE "docbox_tenants" SET "db_iam_user_name" = $3 WHERE "id" = $1 AND "env" = $2"#,
97        )
98        .bind(self.id)
99        .bind(self.env.clone())
100        .bind(iam_user_name)
101        .fetch_optional(db)
102        .await
103    }
104
105    /// Update the "db_secret_name" property of the tenant
106    pub async fn set_db_secret_name(
107        &mut self,
108        db: impl DbExecutor<'_>,
109        db_secret_name: Option<String>,
110    ) -> DbResult<Option<Tenant>> {
111        sqlx::query_as(
112            r#"UPDATE "docbox_tenants" SET "db_secret_name" = $3 WHERE "id" = $1 AND "env" = $2"#,
113        )
114        .bind(self.id)
115        .bind(self.env.clone())
116        .bind(db_secret_name)
117        .fetch_optional(db)
118        .await
119    }
120
121    /// Find a tenant by `id` within a specific `env`
122    pub async fn find_by_id(
123        db: impl DbExecutor<'_>,
124        id: TenantId,
125        env: &str,
126    ) -> DbResult<Option<Tenant>> {
127        sqlx::query_as(r#"SELECT * FROM "docbox_tenants" WHERE "id" = $1 AND "env" = $2"#)
128            .bind(id)
129            .bind(env)
130            .fetch_optional(db)
131            .await
132    }
133
134    /// Find a tenant using its S3 bucket
135    pub async fn find_by_bucket(db: impl DbExecutor<'_>, bucket: &str) -> DbResult<Option<Tenant>> {
136        sqlx::query_as(r#"SELECT * FROM "docbox_tenants" WHERE "s3_name" = $1"#)
137            .bind(bucket)
138            .fetch_optional(db)
139            .await
140    }
141
142    /// Finds all tenants for the specified environment
143    pub async fn find_by_env(db: impl DbExecutor<'_>, env: &str) -> DbResult<Vec<Tenant>> {
144        sqlx::query_as(r#"SELECT * FROM "docbox_tenants" WHERE "env" = $1 ORDER BY "name""#)
145            .bind(env)
146            .fetch_all(db)
147            .await
148    }
149
150    /// Finds all tenants
151    pub async fn all(db: impl DbExecutor<'_>) -> DbResult<Vec<Tenant>> {
152        sqlx::query_as(r#"SELECT * FROM "docbox_tenants" ORDER BY "name""#)
153            .fetch_all(db)
154            .await
155    }
156
157    /// Deletes the tenant
158    pub async fn delete(self, db: impl DbExecutor<'_>) -> DbResult<()> {
159        sqlx::query(r#"DELETE FROM "docbox_tenants" WHERE "id" = $1 AND "env" = $2"#)
160            .bind(self.id)
161            .bind(&self.env)
162            .execute(db)
163            .await?;
164        Ok(())
165    }
166}