Class: DbGui::Model::Db

Inherits:
Struct
  • Object
show all
Defined in:
app/db_gui/model/db.rb

Constant Summary collapse

DIR_DB_GUI =
File.expand_path(File.join('~', '.db_gui'))
FILE_DB_CONFIGS =
File.expand_path(File.join(DIR_DB_GUI, '.db_configs'))
FILE_DB_COMMANDS =
File.expand_path(File.join(DIR_DB_GUI, '.db_commands'))
COUNT_RETRIES =
ENV.fetch('DB_COMMAND_COUNT_RETRIES', 7)
REGEX_ROW_COUNT =
/^\((\d+) row/
ERROR_PREFIX =
'ERROR:'
NEW_LINE =
OS.windows? ? "\r\n" : "\n"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeDb

Returns a new instance of Db.



24
25
26
27
28
29
30
31
32
# File 'app/db_gui/model/db.rb', line 24

def initialize
  load_db_config
  load_db_command
  self.port ||= 5432 # PostgreSQL default port
  self.db_command_result = ''
  self.db_command_timeout ||= ENV.fetch('DB_COMMAND_TIMEOUT_IN_MILLISECONDS', 300).to_i
  self.db_command_result_selection = 0
  connect if to_h.except(:password).none? {|value| value.nil? || (value.respond_to?(:empty?) && value.empty?) }
end

Instance Attribute Details

#connectedObject Also known as: connected?

Returns the value of attribute connected.



18
19
20
# File 'app/db_gui/model/db.rb', line 18

def connected
  @connected
end

#db_commandObject

Returns the value of attribute db_command.



21
22
23
# File 'app/db_gui/model/db.rb', line 21

def db_command
  @db_command
end

#db_command_resultObject

Returns the value of attribute db_command_result.



20
21
22
# File 'app/db_gui/model/db.rb', line 20

def db_command_result
  @db_command_result
end

#db_command_result_selectionObject

Returns the value of attribute db_command_result_selection.



22
23
24
# File 'app/db_gui/model/db.rb', line 22

def db_command_result_selection
  @db_command_result_selection
end

#db_command_timeoutObject

Returns the value of attribute db_command_timeout

Returns:

  • (Object)

    the current value of db_command_timeout



7
8
9
# File 'app/db_gui/model/db.rb', line 7

def db_command_timeout
  @db_command_timeout
end

#dbnameObject

Returns the value of attribute dbname

Returns:

  • (Object)

    the current value of dbname



7
8
9
# File 'app/db_gui/model/db.rb', line 7

def dbname
  @dbname
end

#hostObject

Returns the value of attribute host

Returns:

  • (Object)

    the current value of host



7
8
9
# File 'app/db_gui/model/db.rb', line 7

def host
  @host
end

#passwordObject

Returns the value of attribute password

Returns:

  • (Object)

    the current value of password



7
8
9
# File 'app/db_gui/model/db.rb', line 7

def password
  @password
end

#portObject

Returns the value of attribute port

Returns:

  • (Object)

    the current value of port



7
8
9
# File 'app/db_gui/model/db.rb', line 7

def port
  @port
end

#usernameObject

Returns the value of attribute username

Returns:

  • (Object)

    the current value of username



7
8
9
# File 'app/db_gui/model/db.rb', line 7

def username
  @username
end

Instance Method Details

#connectObject



42
43
44
45
46
# File 'app/db_gui/model/db.rb', line 42

def connect
  io
  self.connected = true
  save_db_config
end

#copy_selected_rowObject



116
117
118
119
# File 'app/db_gui/model/db.rb', line 116

def copy_selected_row
  return if db_command_result_rows.empty?
  Clipboard.copy(formatted_selected_row_string)
end

#copy_selected_row_with_headersObject



121
122
123
124
# File 'app/db_gui/model/db.rb', line 121

def copy_selected_row_with_headers
  return if db_command_result_rows.empty?
  Clipboard.copy(formatted_selected_row_string(include_headers: true))
end

#copy_tableObject



101
102
103
104
# File 'app/db_gui/model/db.rb', line 101

def copy_table
  return if db_command_result_rows.empty?
  Clipboard.copy(formatted_table_string)
end

#copy_table_with_headersObject



106
107
108
109
# File 'app/db_gui/model/db.rb', line 106

def copy_table_with_headers
  return if db_command_result_rows.empty?
  Clipboard.copy(formatted_table_string(include_headers: true))
end

#copy_table_with_query_and_headersObject



111
112
113
114
# File 'app/db_gui/model/db.rb', line 111

def copy_table_with_query_and_headers
  return if db_command_result_rows.empty?
  Clipboard.copy(formatted_table_string(include_query: true, include_headers: true))
end

#db_command_result_countObject



85
86
87
# File 'app/db_gui/model/db.rb', line 85

def db_command_result_count
  db_command_result_count_headers_rows[0]
end

#db_command_result_error?Boolean

Returns:

  • (Boolean)


97
98
99
# File 'app/db_gui/model/db.rb', line 97

def db_command_result_error?
  db_command_result.to_s.strip.start_with?(ERROR_PREFIX)
end

#db_command_result_headersObject



89
90
91
# File 'app/db_gui/model/db.rb', line 89

def db_command_result_headers
  db_command_result_count_headers_rows[1]
end

#db_command_result_rowsObject



93
94
95
# File 'app/db_gui/model/db.rb', line 93

def db_command_result_rows
  db_command_result_count_headers_rows[2]
end

#disconnectObject



48
49
50
51
52
# File 'app/db_gui/model/db.rb', line 48

def disconnect
  io.close
  @io = nil
  self.connected = false
end

#formatted_selected_row_string(include_headers: false) ⇒ Object



140
141
142
143
144
145
# File 'app/db_gui/model/db.rb', line 140

def formatted_selected_row_string(include_headers: false)
  selected_row = db_command_result_rows[db_command_result_selection]
  selected_row.join(' | ')
  rows = [selected_row]
  formatted_table_string(rows, include_headers:)
end

#formatted_table_string(rows = nil, include_query: false, include_headers: false) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'app/db_gui/model/db.rb', line 126

def formatted_table_string(rows = nil, include_query: false, include_headers: false)
  rows ||= db_command_result_rows
  rows = rows.dup
  rows.prepend(db_command_result_headers) if include_headers
  column_max_lengths = row_column_max_lengths(rows) # TODO calculate those after prepending headers
  formatted_string = rows.map do |row|
    row.each_with_index.map do |data, column_index|
      data.ljust(column_max_lengths[column_index])
    end.join(" | ")
  end.join(NEW_LINE)
  formatted_string.prepend("#{db_command}\n\n") if include_query
  formatted_string
end

#ioObject



54
55
56
57
# File 'app/db_gui/model/db.rb', line 54

def io
  db_connection_command = "PGPASSWORD=\"#{password}\" psql --host=#{host} --port=#{port} --username=#{username} --dbname=#{dbname}"
  @io ||= IO.popen(db_connection_command, 'r+', err: [:child, :out])
end

#run_db_commandObject



79
80
81
82
83
# File 'app/db_gui/model/db.rb', line 79

def run_db_command
  run_io_command(db_command)
  save_db_config
  save_db_command
end

#run_io_command(command) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'app/db_gui/model/db.rb', line 59

def run_io_command(command)
  command = command.strip
  command = "#{command};" unless command.end_with?(';')
  @io_command_try ||= 0
  @io_command_try += 1
  io.puts(command)
  read_io_into_db_command_result
  @io_command_try = nil
rescue Timeout::Error, Errno::EPIPE => e
  puts e.message
  @io = nil
  if @io_command_try > COUNT_RETRIES
    @io_command_try = nil
  else
    self.db_command_timeout *= 2
    puts "Retrying DB Command...  {try: #{@io_command_try + 1}, db_command_timeout: #{db_command_timeout}}"
    run_io_command(command) unless db_command_result_error?
  end
end

#toggle_connectionObject



34
35
36
37
38
39
40
# File 'app/db_gui/model/db.rb', line 34

def toggle_connection
  if connected?
    disconnect
  else
    connect
  end
end