Skip to content

Instantly share code, notes, and snippets.

@vinaysshenoy
Last active December 24, 2023 08:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vinaysshenoy/0e42f2dbfd95dde4767aec351fd0c3a2 to your computer and use it in GitHub Desktop.
Save vinaysshenoy/0e42f2dbfd95dde4767aec351fd0c3a2 to your computer and use it in GitHub Desktop.
PostgreSQL Testcontainer that allows restting the database without dropping the schema in between test runs
import { PostgreSqlContainer, StartedPostgreSqlContainer } from "@testcontainers/postgresql"
class ResettablePostgreSqlContainer extends PostgreSqlContainer {
private dumpSaveDirectory: string = ""
override async start(): Promise<StartedResettablePostgreSqlContainer> {
const container = await super.start()
return new StartedResettablePostgreSqlContainer(this.dumpSaveDirectory, container)
}
withDumpSaveLocation(dir: string): ResettablePostgreSqlContainer {
this.withBindMounts([
{
source: dir,
target: "/tmp"
}
])
this.dumpSaveDirectory = dir
return this
}
}
class StartedResettablePostgreSqlContainer extends StartedPostgreSqlContainer {
private readonly dbDumpPath: string
constructor(
dumpSaveDirectory: string,
container: StartedPostgreSqlContainer
) {
if (dumpSaveDirectory.length === 0) {
throw new Error(`Cannot save DB schema without a path, provide a location using "withDumpSaveLocation(string)" when starting the container!`)
}
super(container, container.getDatabase(), container.getUsername(), container.getPassword())
this.dbDumpPath = `${dumpSaveDirectory}/pg_container_${this.getId()}.dump`
}
private async runPostgresCommand(
cmd: string
): Promise<void> {
const result = await this.exec(cmd.split(' '))
if (result.exitCode > 0) {
throw new Error(JSON.stringify(result.output))
}
}
public async saveDatabaseSchema(
dbPort: number = 5432
): Promise<void> {
const dbConnectionPart = `-h localhost -p ${dbPort} -U ${this.getUsername()}`
const dbName = this.getDatabase()
await this.runPostgresCommand(`pg_dump ${dbConnectionPart} -s -f ${this.dbDumpPath} -F tar ${dbName}`)
}
public async resetDatabaseToSavedSchema(
dbPort: number = 5432
): Promise<void> {
const dbConnectionPart = `-h localhost -p ${dbPort} -U ${this.getUsername()}`
const dbName = this.getDatabase()
await this.runPostgresCommand(`dropdb ${dbConnectionPart} ${dbName}`)
await this.runPostgresCommand(`createdb ${dbConnectionPart} ${dbName}`)
await this.runPostgresCommand(`pg_restore ${dbConnectionPart} -s -d ${dbName} ${this.dbDumpPath}`)
}
}
export { ResettablePostgreSqlContainer, StartedResettablePostgreSqlContainer }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment