1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use crate::{runtime::run_with_thread_local_runtime as tok, AnyError, Tags};
use enumflags2::BitFlags;
use quaint::{prelude::Queryable, single::Quaint};
use url::Url;

pub(crate) fn get_postgres_tags(database_url: &str) -> Result<BitFlags<Tags>, String> {
    let fut = async {
        let quaint = Quaint::new(database_url).await.map_err(|err| err.to_string())?;
        let mut tags = Tags::Postgres.into();
        let version = quaint.version().await.map_err(|err| err.to_string())?;

        match version {
            None => Ok(tags),
            Some(version) => {
                eprintln!("version: {version:?}");

                if version.contains("PostgreSQL 9") {
                    tags |= Tags::Postgres9;
                }

                if version.contains("PostgreSQL 12") {
                    tags |= Tags::Postgres12;
                }

                if version.contains("PostgreSQL 14") {
                    tags |= Tags::Postgres14;
                }

                if version.contains("PostgreSQL 15") {
                    tags |= Tags::Postgres15;
                }

                if version.contains("PostgreSQL 16") {
                    tags |= Tags::Postgres16;
                }

                if version.contains("CockroachDB") {
                    if version.contains("v23.1") {
                        tags |= Tags::CockroachDb231;
                    } else if version.contains("v22.2") {
                        tags |= Tags::CockroachDb222;
                    } else if version.contains("v21.2") {
                        tags |= Tags::CockroachDb221;
                    }

                    tags |= Tags::CockroachDb;
                }

                eprintln!("Inferred tags: {tags:?}");

                Ok(tags)
            }
        }
    };

    tok(fut)
}

pub async fn create_postgres_database(database_url: &str, db_name: &str) -> Result<(Quaint, String), AnyError> {
    let mut url: Url = database_url.parse()?;
    let mut postgres_db_url = url.clone();

    url.set_path(db_name);
    postgres_db_url.set_path("/postgres");

    let drop = format!(
        r#"
        DROP DATABASE IF EXISTS "{db_name}";
        "#,
    );

    let recreate = format!(
        r#"
        CREATE DATABASE "{db_name}";
        "#,
    );

    let conn = Quaint::new(postgres_db_url.as_str()).await?;

    // The two commands have to be run separately on postgres.
    conn.raw_cmd(&drop).await?;
    conn.raw_cmd(&recreate).await?;

    url.query_pairs_mut()
        .append_pair("statement_cache_size", "0")
        .append_pair("schema", "prisma-tests");

    let url_str = url.to_string();

    let conn = Quaint::new(&url_str).await?;

    conn.raw_cmd("CREATE SCHEMA \"prisma-tests\"").await?;

    Ok((conn, url_str))
}