Skip to content

Commit 180d57b

Browse files
committed
feat: Added create_database() to create a new database from a migrated template
1 parent 752f282 commit 180d57b

5 files changed

Lines changed: 331 additions & 7 deletions

File tree

src/asynchronous.rs

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::convert::TryInto;
2-
use std::path::Path;
2+
use std::path::{Path, PathBuf};
33
use std::process::Stdio;
44
use std::sync::{Arc, OnceLock};
55

@@ -115,6 +115,7 @@ pub(crate) async fn exec_create_db(
115115
port: u32,
116116
owner: &str,
117117
dbname: &str,
118+
template_db: Option<&str>,
118119
) -> TmpPostgrustResult<()> {
119120
let mut command = Command::new(createdb_bin);
120121
command
@@ -126,10 +127,35 @@ pub(crate) async fn exec_create_db(
126127
.arg("postgres")
127128
.arg("-O")
128129
.arg(owner)
130+
.arg("--echo");
131+
if let Some(template_db) = template_db {
132+
command.arg("-T").arg(template_db);
133+
}
134+
command.arg(dbname);
135+
cmd_as_non_root(&mut command);
136+
exec_process(&mut command, TmpPostgrustError::CreateDBFailed).await
137+
}
138+
139+
#[instrument]
140+
pub(crate) async fn exec_drop_db(
141+
dropdb_bin: &Path,
142+
socket: &Path,
143+
port: u32,
144+
dbname: &str,
145+
) -> TmpPostgrustResult<()> {
146+
let mut command = Command::new(dropdb_bin);
147+
command
148+
.arg("-h")
149+
.arg(socket)
150+
.arg("-p")
151+
.arg(port.to_string())
152+
.arg("-U")
153+
.arg("postgres")
154+
.arg("--if-exists")
129155
.arg("--echo")
130156
.arg(dbname);
131157
cmd_as_non_root(&mut command);
132-
exec_process(&mut command, TmpPostgrustError::CreateDBFailed).await
158+
exec_process(&mut command, TmpPostgrustError::DropDBFailed).await
133159
}
134160

135161
#[instrument]
@@ -199,6 +225,7 @@ pub struct ProcessGuard {
199225
pub(crate) _cache_directory: Arc<TempDir>,
200226
/// Socket directory for connection to the running process.
201227
pub(crate) socket_dir: Arc<TempDir>,
228+
pub(crate) createdb_bin: PathBuf,
202229
pub(crate) postgres_process: Child,
203230
// Limit the total concurrent processes.
204231
pub(crate) _process_permit: SemaphorePermit<'static>,
@@ -224,17 +251,47 @@ impl ProcessGuard {
224251
/// Panics if a string file path cannot be obtained from the socket directory.
225252
#[must_use]
226253
pub fn connection_string(&self) -> String {
254+
self.connection_string_for_db(&self.db_name)
255+
}
256+
257+
/// Get a Postgresql format connection string for a database on this running instance.
258+
///
259+
/// # Panics
260+
///
261+
/// Panics if a string file path cannot be obtained from the socket directory.
262+
#[must_use]
263+
pub fn connection_string_for_db(&self, db_name: &str) -> String {
227264
format!(
228265
"postgresql:///?host={}&port={}&dbname={}&user={}",
229266
self.socket_dir
230267
.path()
231268
.to_str()
232269
.expect("Failed to convert socket directory to a path"),
233270
self.port,
234-
self.db_name,
271+
db_name,
235272
self.user_name,
236273
)
237274
}
275+
276+
/// Create a new database in this running instance from the preserved template database.
277+
///
278+
/// The returned connection string points at the newly-created database.
279+
///
280+
/// # Errors
281+
///
282+
/// Returns an error if `createdb` fails to clone the template database.
283+
pub async fn create_database(&self, db_name: &str) -> TmpPostgrustResult<String> {
284+
exec_create_db(
285+
&self.createdb_bin,
286+
self.socket_dir.path(),
287+
self.port,
288+
&self.user_name,
289+
db_name,
290+
Some(crate::TMP_POSTGRUST_TEMPLATE_DB_NAME),
291+
)
292+
.await?;
293+
Ok(self.connection_string_for_db(db_name))
294+
}
238295
}
239296

240297
fn cmd_as_non_root(command: &mut Command) {

src/errors.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ pub enum TmpPostgrustError {
4646
/// Error when `createdb` fails to execute.
4747
#[error("createdb failed")]
4848
CreateDBFailed(ProcessCapture),
49+
/// Error when `dropdb` fails to execute.
50+
#[error("dropdb failed")]
51+
DropDBFailed(ProcessCapture),
4952
/// Error when `postgresql.conf` cannot be written.
5053
#[error("failed to write postgresql.conf")]
5154
CreateConfigFailed(#[source] std::io::Error),

0 commit comments

Comments
 (0)