1mod config;
2mod db;
3
4use sqlx::Executor;
5
6pub use crate::config::Config as DbConfig;
7pub use crate::db::DB;
8
9pub async fn ensure(app_name: &str, cfgs: &[&DbConfig]) -> anyhow::Result<()> {
10 for cfg in cfgs {
11 let db = DB::new_root(app_name, cfg).await?;
12 let query_args = ::core::result::Result::<_, ::sqlx::error::BoxDynError>::Ok(
13 <sqlx::postgres::Postgres as ::sqlx::database::Database>::Arguments::<'_>::default(),
14 );
15 let databases: Vec<String> =
16 sqlx::__query_with_result("SELECT datname FROM pg_database;", query_args)
17 .try_map(|v: sqlx::postgres::PgRow| {
18 use ::sqlx::Row as _;
19 v.try_get_unchecked::<String, _>(0usize)
20 })
21 .fetch_all(db.pool())
22 .await?;
23
24 if let Some(database) = cfg.database() {
25 if !databases.iter().any(|datname| datname == database) {
26 db.pool()
27 .execute(format!("CREATE DATABASE {database}").as_str())
28 .await?;
29 }
30 }
31
32 if let Some((username, password)) = cfg.username().zip(cfg.password()) {
33 let query_args = ::core::result::Result::<_, ::sqlx::error::BoxDynError>::Ok(
34 <sqlx::postgres::Postgres as ::sqlx::database::Database>::Arguments::<'_>::default(
35 ),
36 );
37 let users: Vec<Option<String>> =
38 sqlx::__query_with_result("SELECT usename FROM pg_catalog.pg_user;", query_args)
39 .try_map(|v: sqlx::postgres::PgRow| {
40 use ::sqlx::Row as _;
41 v.try_get_unchecked::<Option<String>, _>(0usize)
42 })
43 .fetch_all(db.pool())
44 .await?;
45 if !users
46 .iter()
47 .any(|usename| usename.as_deref() == Some(username))
48 {
49 db.pool()
50 .execute(
51 format!("CREATE USER {username} WITH SUPERUSER PASSWORD '{password}'")
52 .as_str(),
53 )
54 .await?;
55 }
56 }
57 }
58 Ok(())
59}