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
//! A Rust client for the IntegreSQL Postgres testing tool
//!
//! IntegreSQL makes it easy and fast to write integration tests that require a
//! Postgres database, letting you give each test its own fresh, isolated
//! database containing all the schema resources the test requires, with minimal
//! performance overhead. It does this by leveraging Postgres's support for
//! template databases- databases that can be cloned cheaply to create new
//! databases. By combining the use of template databases with a pre-populated
//! pool of test databases, IntegreSQL lets you spin up and destroy large
//! numbers of ephemeral test databases in roughly 10-50 milliseconds each on
//! modern development machines.
//!
//! Example usage:
//! ```rust
//! use integresql::{DbManager, TemplateDb, ConnectionSettings};
//! use tokio_postgres::{Client, NoTls};
//! use std::time::Instant;
//! use std::error::Error;
//! use tokio::task;
//! use futures::future::join_all;
//!
//! const SCHEMA_SQL: &str = "CREATE SCHEMA test_schema;
//!
//! CREATE TABLE test_schema.pet_owners (
//! id SERIAL PRIMARY KEY,
//! name TEXT NOT NULL,
//! pet_count INTEGER NOT NULL
//! );
//! ";
//!
//! async fn connect(conn_str: impl AsRef<str>) -> Result<Client, tokio_postgres::Error> {
//! let (client, connection) = tokio_postgres::connect(conn_str.as_ref(), NoTls).await?;
//! tokio::spawn(async move {
//! if let Err(e) = connection.await {
//! eprintln!("Connection error: {}", e);
//! }
//! });
//! Ok(client)
//! }
//!
//! /// Sets up the template database with your schema
//! async fn setup_template(config: ConnectionSettings) -> Result<(), Box<dyn Error + 'static>> {
//! let conn_str = config.to_libpq_url();
//! let client = connect(&conn_str).await?;
//!
//! client.batch_execute(SCHEMA_SQL).await?;
//!
//! drop(client);
//! tokio::task::yield_now().await; // Yield to ensure the connection is closed
//! Ok(())
//! }
//!
//! #[tokio::main]
//! async fn main() {
//! let db_manager = DbManager::from_env();
//! let template_db = db_manager.get_template_db_async(SCHEMA_SQL, setup_template).await
//! .expect("Error creating template database");
//!
//! let start = Instant::now();
//! let mut handles = Vec::new();
//! for i in 0..20 {
//! let test_db = template_db.get_writable_test_db()
//! .expect("Error getting test database");
//! handles.push(task::spawn(async move {
//! let conn_str = test_db.to_libpq_url();
//! let client = connect(&conn_str).await
//! .expect("Error connecting to test database");
//!
//! let insert_sql = "
//! INSERT INTO test_schema.pet_owners (name, pet_count)
//! VALUES ($1, $2), $($3, $4);";
//! client.execute(insert_sql, &[&"Alice", &1, &"Bob", &2]).await.unwrap();
//! let row_count: i64 = client.query_one("SELECT COUNT(*) FROM test_schema.pet_owners", &[]).await
//! .map(|row| row.get(0))
//! .unwrap();
//! assert_eq!(row_count, 2);
//! }));
//! }
//! join_all(handles).await;
//!
//! let elapsed = start.elapsed().as_secs_f64();
//! eprintln!("Created and used 20 test databases in {:.2} seconds", elapsed);
//! }
//! ```
pub use IntegresqlError;
pub use ;