Skip to main content

ironflow_ops_postgres/schema/
databases.rs

1//! Database listing operation.
2
3use async_trait::async_trait;
4use ironflow_core::error::OperationError;
5use ironflow_core::operation::{Operation, OperationContext, TypedOperation};
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8use sqlx::{PgPool, Row};
9
10use crate::helpers::{pg_error, to_value};
11
12/// Output of [`ListDatabases`].
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct ListDatabasesOutput {
15    /// Database names.
16    pub databases: Vec<String>,
17}
18
19/// List all databases on the server.
20///
21/// # Examples
22///
23/// ```no_run
24/// use ironflow_ops_postgres::schema::databases::ListDatabases;
25/// use ironflow_core::operation::Operation;
26///
27/// # fn example(pool: sqlx::PgPool) {
28/// let op = ListDatabases::new(pool);
29/// assert_eq!(op.kind(), "postgres");
30/// # }
31/// ```
32pub struct ListDatabases {
33    pool: PgPool,
34}
35
36impl ListDatabases {
37    /// Create a new list-databases operation.
38    pub fn new(pool: PgPool) -> Self {
39        Self { pool }
40    }
41
42    /// Execute and return a typed result.
43    ///
44    /// # Errors
45    ///
46    /// Returns [`OperationError::External`] on connection errors.
47    pub async fn run(
48        &self,
49        _ctx: &OperationContext,
50    ) -> Result<ListDatabasesOutput, OperationError> {
51        let rows = sqlx::query(
52            "SELECT datname FROM pg_database WHERE datistemplate = false ORDER BY datname",
53        )
54        .fetch_all(&self.pool)
55        .await
56        .map_err(pg_error)?;
57        let databases = rows
58            .iter()
59            .map(|r| r.try_get::<String, _>("datname").map_err(pg_error))
60            .collect::<Result<Vec<_>, _>>()?;
61        Ok(ListDatabasesOutput { databases })
62    }
63}
64
65#[async_trait]
66impl Operation for ListDatabases {
67    fn kind(&self) -> &str {
68        "postgres"
69    }
70    async fn execute(&self, ctx: &OperationContext) -> Result<Value, OperationError> {
71        to_value(&self.run(ctx).await?)
72    }
73}
74
75impl TypedOperation for ListDatabases {
76    type Output = ListDatabasesOutput;
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[tokio::test]
84    async fn kind() {
85        let pool = PgPool::connect_lazy("postgres://localhost/test").unwrap();
86        let op = ListDatabases::new(pool);
87        assert_eq!(op.kind(), "postgres");
88    }
89}