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)]
9pub struct Tenant {
10    /// Unique ID for the tenant
11    pub id: TenantId,
12    /// Name of the tenant database
13    pub db_name: String,
14    /// Name for the AWS secret used for the database user
15    pub db_secret_name: String,
16    /// Name of the tenant s3 bucket
17    pub s3_name: String,
18    /// Name of the tenant search index
19    pub os_index_name: String,
20    /// Environment for the tenant
21    pub env: String,
22    /// Optional event queue (SQS) to send docbox events to
23    pub event_queue_url: Option<String>,
24}
25
26pub struct CreateTenant {
27    pub id: TenantId,
28    pub db_name: String,
29    pub db_secret_name: String,
30    pub s3_name: String,
31    pub os_index_name: String,
32    pub event_queue_url: Option<String>,
33    pub env: String,
34}
35
36impl Tenant {
37    /// Create a new tenant
38    pub async fn create(db: impl DbExecutor<'_>, create: CreateTenant) -> DbResult<Tenant> {
39        sqlx::query(
40            r#"
41            INSERT INTO "docbox_tenants" (
42                "id", 
43                "db_name", 
44                "db_secret_name", 
45                "s3_name", 
46                "os_index_name", 
47                "env", 
48                "event_queue_url"
49            )
50            VALUES ($1, $2, $3, $4, $5, $6, $7)
51        "#,
52        )
53        .bind(create.id)
54        .bind(create.db_name.as_str())
55        .bind(create.db_secret_name.as_str())
56        .bind(create.s3_name.as_str())
57        .bind(create.os_index_name.as_str())
58        .bind(create.env.as_str())
59        .bind(create.event_queue_url.as_ref())
60        .execute(db)
61        .await?;
62
63        Ok(Tenant {
64            id: create.id,
65            db_name: create.db_name,
66            db_secret_name: create.db_secret_name,
67            s3_name: create.s3_name,
68            os_index_name: create.os_index_name,
69            env: create.env,
70            event_queue_url: create.event_queue_url,
71        })
72    }
73
74    /// Find a tenant by `id` within a specific `env`
75    pub async fn find_by_id(
76        db: impl DbExecutor<'_>,
77        id: TenantId,
78        env: &str,
79    ) -> DbResult<Option<Tenant>> {
80        sqlx::query_as(r#"SELECT * FROM "docbox_tenants" WHERE "id" = $1 AND "env" = $2"#)
81            .bind(id)
82            .bind(env)
83            .fetch_optional(db)
84            .await
85    }
86
87    /// Find a tenant using its S3 bucket
88    pub async fn find_by_bucket(db: impl DbExecutor<'_>, bucket: &str) -> DbResult<Option<Tenant>> {
89        sqlx::query_as(r#"SELECT * FROM "docbox_tenants" WHERE "s3_name" = $1"#)
90            .bind(bucket)
91            .fetch_optional(db)
92            .await
93    }
94
95    /// Finds all tenants for the specified environment
96    pub async fn find_by_env(db: impl DbExecutor<'_>, env: &str) -> DbResult<Vec<Tenant>> {
97        sqlx::query_as(r#"SELECT * FROM "docbox_tenants" WHERE "env" = $1"#)
98            .bind(env)
99            .fetch_all(db)
100            .await
101    }
102
103    /// Finds all tenants
104    pub async fn all(db: impl DbExecutor<'_>) -> DbResult<Vec<Tenant>> {
105        sqlx::query_as(r#"SELECT * FROM "docbox_tenants""#)
106            .fetch_all(db)
107            .await
108    }
109
110    /// Update the open search index for the tenant
111    pub async fn update_os_index(
112        &mut self,
113        db: impl DbExecutor<'_>,
114        os_index_name: String,
115    ) -> DbResult<()> {
116        sqlx::query(
117            r#"UPDATE "docbox_tenants" SET "os_index_name" = $1 WHERE "id" = $2 AND "env" = $3"#,
118        )
119        .bind(&os_index_name)
120        .bind(self.id)
121        .bind(&self.env)
122        .execute(db)
123        .await?;
124
125        self.os_index_name = os_index_name;
126        Ok(())
127    }
128
129    /// Deletes the tenant
130    pub async fn delete(self, db: impl DbExecutor<'_>) -> DbResult<()> {
131        sqlx::query(r#"DELETE "docbox_tenants" WHERE "id" = $1 AND "env" = $2"#)
132            .bind(self.id)
133            .bind(&self.env)
134            .execute(db)
135            .await?;
136        Ok(())
137    }
138}