use std::time::Duration;
use crate::{
Container, ExposedPort, HealthCheck, ImageName, Port, PortError, RunnableContainer,
RunnableContainerBuilder, ToRunnableContainer,
};
const POSTGRES_IMAGE: &ImageName = &ImageName::new("docker.io/postgres");
const PORT: Port = Port(5432);
const POSTGRES_USER: &str = "postgres";
const POSTGRES_PASSWORD: &str = "passwd";
const POSTGRES_DATABASE: &str = POSTGRES_USER;
#[derive(Debug)]
pub struct Postgres {
image: ImageName,
user: String,
password: String,
db: String,
port: ExposedPort,
}
impl Postgres {
#[must_use]
pub fn with_tag(self, tag: impl Into<String>) -> Self {
let Self { mut image, .. } = self;
image.set_tag(tag);
Self { image, ..self }
}
#[must_use]
pub fn with_digest(self, digest: impl Into<String>) -> Self {
let Self { mut image, .. } = self;
image.set_digest(digest);
Self { image, ..self }
}
#[must_use]
pub fn with_user(self, user: impl Into<String>) -> Self {
let user = user.into();
Self { user, ..self }
}
#[must_use]
pub fn with_password(self, password: impl Into<String>) -> Self {
let password = password.into();
Self { password, ..self }
}
#[must_use]
pub fn with_db(self, db: impl Into<String>) -> Self {
let db = db.into();
Self { db, ..self }
}
#[must_use]
pub fn with_port(mut self, port: ExposedPort) -> Self {
self.port = port;
self
}
}
impl Default for Postgres {
fn default() -> Self {
Self {
image: POSTGRES_IMAGE.clone(),
user: String::from(POSTGRES_USER),
password: String::from(POSTGRES_PASSWORD),
db: String::from(POSTGRES_DATABASE),
port: ExposedPort::new(PORT),
}
}
}
impl Container<Postgres> {
pub async fn config(&self) -> Result<String, PortError> {
let user = &self.user;
let password = &self.password;
let host_ip = self.runner.container_host_ip().await?;
let port = self.port.host_port().await?;
let database = &self.db;
let config =
format!("host={host_ip} user={user} password={password} port={port} dbname={database}");
Ok(config)
}
pub async fn url(&self) -> Result<String, PortError> {
let user = &self.user;
let password = &self.password;
let port = self.port.host_port().await?;
let host_ip = self.runner.container_host_ip().await?;
let database = &self.db;
let url = format!("postgresql://{user}:{password}@{host_ip}:{port}/{database}");
Ok(url)
}
}
impl ToRunnableContainer for Postgres {
fn to_runnable(&self, builder: RunnableContainerBuilder) -> RunnableContainer {
builder
.with_image(self.image.clone())
.with_wait_strategy({
let db = &self.db;
let user = &self.user;
HealthCheck::builder()
.with_command(format!("pg_isready --dbname={db} --username={user}"))
.with_interval(Duration::from_millis(250))
.build()
})
.with_env([
("POSTGRES_USER", &self.user),
("POSTGRES_PASSWORD", &self.password),
("POSTGRES_DB", &self.db),
])
.with_port_mappings([self.port.clone()])
.build()
}
}