Module: Polyrun::Database::Provision

Defined in:
lib/polyrun/database/provision.rb

Overview

PostgreSQL-only provisioning via psql / createdb (spec2 §5.3). No pg gem. For other adapters, use Rails tasks or vendor CLIs; Polyrun::Database::UrlBuilder still emits DATABASE_URL for supported schemes.

Class Method Summary collapse

Class Method Details

.create_database_from_template!(new_db:, template_db:, host: nil, port: nil, username: nil, maintenance_db: "postgres") ⇒ Object

CREATE DATABASE new_db TEMPLATE template_db — connects to maintenance DB postgres.

Raises:



36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/polyrun/database/provision.rb', line 36

def create_database_from_template!(new_db:, template_db:, host: nil, port: nil, username: nil, maintenance_db: "postgres")
  host ||= ENV["PGHOST"] || "localhost"
  port ||= ENV["PGPORT"] || "5432"
  username ||= ENV["PGUSER"] || "postgres"

  sql = "CREATE DATABASE #{quote_ident(new_db)} TEMPLATE #{quote_ident(template_db)};"
  cmd = ["psql", "-U", username, "-h", host, "-p", port.to_s, "-d", maintenance_db, "-v", "ON_ERROR_STOP=1", "-c", sql]
  _out, err, st = Open3.capture3(*cmd)
  raise Polyrun::Error, "create database failed: #{err}" unless st.success?

  true
end

.drop_database_if_exists!(database:, host: nil, port: nil, username: nil, maintenance_db: "postgres", force: false) ⇒ Object

DROP DATABASE IF EXISTS name; — maintenance DB postgres (or maintenance_db).

Raises:



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/polyrun/database/provision.rb', line 17

def drop_database_if_exists!(database:, host: nil, port: nil, username: nil, maintenance_db: "postgres", force: false)
  host ||= ENV["PGHOST"] || "localhost"
  port ||= ENV["PGPORT"] || "5432"
  username ||= ENV["PGUSER"] || "postgres"

  sql =
    if force
      "DROP DATABASE IF EXISTS #{quote_ident(database)} WITH (FORCE);"
    else
      "DROP DATABASE IF EXISTS #{quote_ident(database)};"
    end
  cmd = ["psql", "-U", username, "-h", host, "-p", port.to_s, "-d", maintenance_db, "-v", "ON_ERROR_STOP=1", "-c", sql]
  _out, err, st = Open3.capture3(*cmd)
  raise Polyrun::Error, "drop database failed: #{err}" unless st.success?

  true
end

.prepare_template!(rails_root:, env:, silent: true) ⇒ Object

Runs bin/rails db:prepare with merged ENV (DATABASE_URL for primary, CACHE_DATABASE_URL, etc.). Multi-DB Rails apps must pass all template URLs in one invocation so each DB uses its own migrations_paths. Uses db:prepare (not db:migrate alone) so empty template databases load schema.rb first; apps that squash or archive migrations and keep only incremental files need that path.

Streams stdout/stderr to the terminal by default. With silent: true, redirects child stdio to File::NULL (no live output; non-interactive).

Raises:



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/polyrun/database/provision.rb', line 56

def prepare_template!(rails_root:, env:, silent: true)
  exe = File.join(rails_root, "bin", "rails")
  raise Polyrun::Error, "Provision: missing #{exe}" unless File.executable?(exe)

  child_env = ENV.to_h.merge(env)
  child_env["RAILS_ENV"] ||= ENV["RAILS_ENV"] || "test"
  st, out, err = Polyrun::ProcessStdio.spawn_wait(
    child_env,
    exe,
    "db:prepare",
    chdir: rails_root,
    silent: silent
  )
  unless st.success?
    raise Polyrun::Error, Polyrun::ProcessStdio.format_failure_message("db:prepare", st, out, err)
  end

  true
end

.quote_ident(name) ⇒ Object



12
13
14
# File 'lib/polyrun/database/provision.rb', line 12

def quote_ident(name)
  '"' + name.to_s.gsub('"', '""') + '"'
end