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