Class: SchemaEvolutionManager::Db
- Inherits:
-
Object
- Object
- SchemaEvolutionManager::Db
- Defined in:
- lib/schema-evolution-manager/db.rb
Instance Attribute Summary collapse
-
#psql_executable_with_options ⇒ Object
readonly
Returns the value of attribute psql_executable_with_options.
-
#url ⇒ Object
readonly
Returns the value of attribute url.
Class Method Summary collapse
- .attribute_values(path) ⇒ Object
- .from_args(args, opts = {}) ⇒ Object
-
.parse_command_line_config(arg_string) ⇒ Object
Parses command line arguments returning an instance of Db.
- .password_to_tempfile(contents) ⇒ Object
-
.schema_name ⇒ Object
Returns the name of the schema_evolution_manager schema.
Instance Method Summary collapse
-
#bootstrap! ⇒ Object
Installs schema_evolution_manager.
-
#initialize(url, opts = {}) ⇒ Db
constructor
A new instance of Db.
-
#psql_command(sql_command) ⇒ Object
executes a simple sql command.
-
#psql_file(filename, path) ⇒ Object
executes sql commands from a file in a single transaction.
-
#sanitized_url ⇒ Object
Returns a sanitized version of the URL with the password removed to prevent passwords from being logged or displayed in error messages.
-
#schema_schema_evolution_manager_exists? ⇒ Boolean
True if the specific schema exists; false otherwise.
Constructor Details
#initialize(url, opts = {}) ⇒ Db
Returns a new instance of Db.
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/schema-evolution-manager/db.rb', line 7 def initialize(url, opts={}) @url = Preconditions.check_not_blank(url, "url cannot be blank") password = opts.delete(:password) @psql_executable_with_options = "psql" (opts.delete(:set) || []).each do |arg| @psql_executable_with_options << " --set #{arg}" end Preconditions.assert_empty_opts(opts) connection_data = ConnectionData.parse_url(@url) if password ENV['PGPASSFILE'] = Db.password_to_tempfile(connection_data.pgpass(password)) end end |
Instance Attribute Details
#psql_executable_with_options ⇒ Object (readonly)
Returns the value of attribute psql_executable_with_options.
5 6 7 |
# File 'lib/schema-evolution-manager/db.rb', line 5 def @psql_executable_with_options end |
#url ⇒ Object (readonly)
Returns the value of attribute url.
5 6 7 |
# File 'lib/schema-evolution-manager/db.rb', line 5 def url @url end |
Class Method Details
.attribute_values(path) ⇒ Object
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 |
# File 'lib/schema-evolution-manager/db.rb', line 43 def Db.attribute_values(path) Preconditions.assert_class(path, String) = [] ['quiet', 'no-align', 'tuples-only'].each do |v| << "--#{v}" end SchemaEvolutionManager::MigrationFile.new(path).attribute_values.map do |value| if value.attribute.name == "transaction" if value.value == "single" << "--single-transaction" elsif value.value == "none" # No-op else raise "File[%s] - attribute[%s] unsupported value[%s]" % [path, value.attribute.name, value.value] end else raise "File[%s] - unsupported attribute named[%s]" % [path, value.attribute.name] end end end |
.from_args(args, opts = {}) ⇒ Object
110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/schema-evolution-manager/db.rb', line 110 def Db.from_args(args, opts={}) Preconditions.assert_class(args, Args) password = opts.delete(:password) Preconditions.assert_empty_opts(opts) = { :password => password, :set => args.set } if args.url Db.new(args.url, ) else base = "%s:%s/%s" % [args.host || "localhost", args.port || ConnectionData::DEFAULT_PORT, args.name] url = args.user ? "%s@%s" % [args.user, base] : base Db.new("postgres://" + url, ) end end |
.parse_command_line_config(arg_string) ⇒ Object
Parses command line arguments returning an instance of Db. Exists if invalid config.
103 104 105 106 107 |
# File 'lib/schema-evolution-manager/db.rb', line 103 def Db.parse_command_line_config(arg_string) Preconditions.assert_class(arg_string, String) args = Args.new(arg_string, :optional => ['url', 'host', 'user', 'name', 'port', 'set']) Db.from_args(args) end |
.password_to_tempfile(contents) ⇒ Object
130 131 132 133 134 135 |
# File 'lib/schema-evolution-manager/db.rb', line 130 def Db.password_to_tempfile(contents) file = Tempfile.new("sem-db") file.write(contents) file.rewind file.path end |
.schema_name ⇒ Object
Returns the name of the schema_evolution_manager schema
126 127 128 |
# File 'lib/schema-evolution-manager/db.rb', line 126 def Db.schema_name "schema_evolution_manager" end |
Instance Method Details
#bootstrap! ⇒ Object
Installs schema_evolution_manager. Automatically upgrades schema_evolution_manager.
25 26 27 28 29 30 31 32 |
# File 'lib/schema-evolution-manager/db.rb', line 25 def bootstrap! scripts = Scripts.new(self, Scripts::BOOTSTRAP_SCRIPTS) dir = File.join(Library.base_dir, "scripts") scripts.each_pending(dir) do |filename, path| psql_file(filename, path) scripts.record_as_run!(filename) end end |
#psql_command(sql_command) ⇒ Object
executes a simple sql command.
35 36 37 38 39 40 41 |
# File 'lib/schema-evolution-manager/db.rb', line 35 def psql_command(sql_command) Preconditions.assert_class(sql_command, String) template = "#{@psql_executable_with_options} --no-align --tuples-only --no-psqlrc --command \"%s\" %s" command = template % [sql_command, Shellwords.escape(@url)] command_to_log = template % [sql_command, sanitized_url] Library.system_or_error(command, command_to_log) end |
#psql_file(filename, path) ⇒ Object
executes sql commands from a file in a single transaction
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/schema-evolution-manager/db.rb', line 70 def psql_file(filename, path) Preconditions.assert_class(path, String) Preconditions.check_state(File.exist?(path), "File[%s] not found" % path) = Db.attribute_values(path).join(" ") Library.with_temp_file(:prefix => File.basename(path)) do |tmp| File.open(tmp, "w") do |out| out << "\\set ON_ERROR_STOP true\n\n" out << IO.read(path) end command = "#{@psql_executable_with_options} --file \"%s\" #{} %s" % [tmp, Shellwords.escape(@url)] Library.with_temp_file do |output| result = `#{command} > #{output} 2>&1`.strip status = $? if status.to_i > 0 errors = File.exist?(output) ? IO.read(output) : result raise ScriptError.new(self, filename, path, errors) end end end end |
#sanitized_url ⇒ Object
Returns a sanitized version of the URL with the password removed to prevent passwords from being logged or displayed in error messages
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/schema-evolution-manager/db.rb', line 139 def sanitized_url # Parse the URL to extract components if @url.include?("://") protocol, rest = @url.split("://", 2) lead, name = rest.split("/", 2) # Check if there's a username:password@ pattern if lead.include?("@") # Take the last element as host_part to handle passwords with @ symbols host_part = lead.split("@").last # Take everything before the last @ as user_part user_part = lead.split("@")[0..-2].join("@") if user_part.include?(":") # Remove password, keep only username (everything before the first colon) username = user_part.split(":", 2)[0] sanitized_lead = "#{username}:[REDACTED]@#{host_part}" else sanitized_lead = lead end "#{protocol}://#{sanitized_lead}/#{name}" else @url end else @url end end |
#schema_schema_evolution_manager_exists? ⇒ Boolean
True if the specific schema exists; false otherwise
96 97 98 99 |
# File 'lib/schema-evolution-manager/db.rb', line 96 def schema_schema_evolution_manager_exists? sql = "select count(*) from pg_namespace where nspname='%s'" % Db.schema_name psql_command(sql).to_i > 0 end |