Skip to main content

stormchaser_api/db/
storage.rs

1use crate::UpdateStorageBackendRequest;
2use serde_json::Value;
3use sqlx::{PgPool, Postgres, Transaction};
4use stormchaser_model::BackendId;
5
6use stormchaser_model::storage;
7
8/// Unsets the default Stormchaser File System.
9/// Unset default sfs.
10pub async fn unset_default_sfs(tx: &mut Transaction<'_, Postgres>) -> Result<(), sqlx::Error> {
11    sqlx::query("UPDATE storage_backends SET is_default_sfs = FALSE WHERE is_default_sfs = TRUE")
12        .execute(&mut **tx)
13        .await?;
14    Ok(())
15}
16
17/// Creates a new storage backend.
18/// Create storage backend.
19#[allow(clippy::too_many_arguments)]
20pub async fn create_storage_backend(
21    tx: &mut Transaction<'_, Postgres>,
22    id: BackendId,
23    name: &str,
24    description: &Option<String>,
25    backend_type: &storage::BackendType,
26    config: &Value,
27    aws_assume_role_arn: &Option<String>,
28    is_default_sfs: bool,
29) -> Result<(), sqlx::Error> {
30    sqlx::query(
31        r#"
32        INSERT INTO storage_backends (id, name, description, backend_type, config, aws_assume_role_arn, is_default_sfs)
33        VALUES ($1, $2, $3, $4, $5, $6, $7)
34        "#,
35    )
36    .bind(id)
37    .bind(name)
38    .bind(description)
39    .bind(backend_type)
40    .bind(config)
41    .bind(aws_assume_role_arn)
42    .bind(is_default_sfs)
43    .execute(&mut **tx)
44    .await?;
45    Ok(())
46}
47
48/// Retrieves all storage backends.
49/// List storage backends.
50pub async fn list_storage_backends(
51    pool: &PgPool,
52) -> Result<Vec<storage::StorageBackend>, sqlx::Error> {
53    sqlx::query_as("SELECT * FROM storage_backends ORDER BY name ASC")
54        .fetch_all(pool)
55        .await
56}
57
58/// Retrieves a storage backend by ID.
59/// Get storage backend.
60pub async fn get_storage_backend(
61    pool: &PgPool,
62    id: BackendId,
63) -> Result<Option<storage::StorageBackend>, sqlx::Error> {
64    sqlx::query_as("SELECT * FROM storage_backends WHERE id = $1")
65        .bind(id)
66        .fetch_optional(pool)
67        .await
68}
69
70/// Updates an existing storage backend.
71/// Update storage backend.
72pub async fn update_storage_backend(
73    tx: &mut Transaction<'_, Postgres>,
74    id: BackendId,
75    payload: &UpdateStorageBackendRequest,
76) -> Result<(), sqlx::Error> {
77    let mut query = sqlx::QueryBuilder::new("UPDATE storage_backends SET ");
78    let mut separated = query.separated(", ");
79
80    if let Some(name) = &payload.name {
81        separated.push("name = ").push_bind_unseparated(name);
82    }
83    if let Some(desc) = &payload.description {
84        separated.push("description = ").push_bind_unseparated(desc);
85    }
86    if let Some(bt) = &payload.backend_type {
87        separated.push("backend_type = ").push_bind_unseparated(bt);
88    }
89    if let Some(cfg) = &payload.config {
90        separated.push("config = ").push_bind_unseparated(cfg);
91    }
92    if let Some(role) = &payload.aws_assume_role_arn {
93        // An empty string is treated as a request to clear the ARN (set to NULL).
94        let value: Option<&str> = if role.is_empty() {
95            None
96        } else {
97            Some(role.as_str())
98        };
99        separated
100            .push("aws_assume_role_arn = ")
101            .push_bind_unseparated(value);
102    }
103    if let Some(is_default) = payload.is_default_sfs {
104        separated
105            .push("is_default_sfs = ")
106            .push_bind_unseparated(is_default);
107    }
108
109    query.push(" WHERE id = ").push_bind(id);
110
111    query.build().execute(&mut **tx).await?;
112    Ok(())
113}
114
115/// Deletes a storage backend from the database.
116/// Delete storage backend.
117pub async fn delete_storage_backend(pool: &PgPool, id: BackendId) -> Result<(), sqlx::Error> {
118    sqlx::query("DELETE FROM storage_backends WHERE id = $1")
119        .bind(id)
120        .execute(pool)
121        .await?;
122    Ok(())
123}