Module: RubyPgExtras

Defined in:
lib/ruby-pg-extras.rb,
lib/ruby_pg_extras/version.rb,
lib/ruby_pg_extras/index_info.rb,
lib/ruby_pg_extras/table_info.rb,
lib/ruby_pg_extras/size_parser.rb,
lib/ruby_pg_extras/diagnose_data.rb,
lib/ruby_pg_extras/diagnose_print.rb,
lib/ruby_pg_extras/index_info_print.rb,
lib/ruby_pg_extras/table_info_print.rb

Defined Under Namespace

Classes: DiagnoseData, DiagnosePrint, IndexInfo, IndexInfoPrint, SizeParser, TableInfo, TableInfoPrint

Constant Summary collapse

NEW_PG_STAT_STATEMENTS =
"1.8"
QUERIES =
%i(
  add_extensions bloat blocking cache_hit db_settings
  calls extensions table_cache_hit tables index_cache_hit
  indexes index_size index_usage index_scans null_indexes locks all_locks
  long_running_queries mandelbrot outliers
  records_rank seq_scans table_index_scans table_indexes_size
  table_size total_index_size total_table_size
  unused_indexes duplicate_indexes vacuum_stats kill_all kill_pid
  pg_stat_statements_reset buffercache_stats
  buffercache_usage ssl_used connections
)
DEFAULT_ARGS =
Hash.new({}).merge({
  calls: { limit: 10 },
  calls_legacy: { limit: 10 },
  long_running_queries: { threshold: "500 milliseconds" },
  locks: { limit: 20 },
  outliers: { limit: 10 },
  outliers_legacy: { limit: 10 },
  buffercache_stats: { limit: 10 },
  buffercache_usage: { limit: 20 },
  unused_indexes: { max_scans: 50, schema: "public" },
  null_indexes: { min_relation_size_mb: 10 },
  index_usage: { schema: "public" },
  index_cache_hit: { schema: "public" },
  table_cache_hit: { schema: "public" },
  index_scans: { schema: "public" },
  cache_hit: { schema: "public" },
  seq_scans: { schema: "public" },
  table_index_scans: { schema: "public" },
  records_rank: { schema: "public" },
  tables: { schema: "public" },
  kill_pid: { pid: 0 }
})
VERSION =
"4.12.2"
@@database_url =
nil

Class Method Summary collapse

Class Method Details

.connectionObject



173
174
175
# File 'lib/ruby-pg-extras.rb', line 173

def self.connection
  @_connection ||= PG.connect(database_url)
end

.database_urlObject



181
182
183
# File 'lib/ruby-pg-extras.rb', line 181

def self.database_url
  @@database_url || ENV.fetch("DATABASE_URL")
end

.database_url=(value) ⇒ Object



177
178
179
# File 'lib/ruby-pg-extras.rb', line 177

def self.database_url=(value)
  @@database_url = value
end

.description_for(query_name:) ⇒ Object



155
156
157
158
159
160
161
# File 'lib/ruby-pg-extras.rb', line 155

def self.description_for(query_name:)
  first_line = File.open(
    sql_path_for(query_name: query_name)
  ) { |f| f.readline }

  first_line[/\/\*(.*?)\*\//m, 1].strip
end

.diagnose(in_format: :display_table) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/ruby-pg-extras.rb', line 88

def self.diagnose(in_format: :display_table)
  data = RubyPgExtras::DiagnoseData.call

  if in_format == :display_table
    RubyPgExtras::DiagnosePrint.call(data)
  elsif in_format == :hash
    data
  elsif in_format == :array
    data.map(&:values)
  else
    raise "Invalid 'in_format' argument!"
  end
end

.display_result(result, title:, in_format:) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/ruby-pg-extras.rb', line 130

def self.display_result(result, title:, in_format:)
  case in_format
  when :array
    result.values
  when :hash
    result.to_a
  when :raw
    result
  when :display_table
    headings = if result.count > 0
      result[0].keys
    else
      ["No results"]
    end

    puts Terminal::Table.new(
      title: title,
      headings: headings,
      rows: result.values
    )
  else
    raise "Invalid in_format option"
  end
end

.index_info(args: {}, in_format: :display_table) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/ruby-pg-extras.rb', line 102

def self.index_info(args: {}, in_format: :display_table)
  data = RubyPgExtras::IndexInfo.call(args[:table_name])

  if in_format == :display_table
    RubyPgExtras::IndexInfoPrint.call(data)
  elsif in_format == :hash
    data
  elsif in_format == :array
    data.map(&:values)
  else
    raise "Invalid 'in_format' argument!"
  end
end

.run_query(query_name:, in_format:, args: {}) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/ruby-pg-extras.rb', line 63

def self.run_query(query_name:, in_format:, args: {})
  if %i(calls outliers).include?(query_name)
    pg_stat_statements_ver = RubyPgExtras.connection.exec("select installed_version from pg_available_extensions where name='pg_stat_statements'")
      .to_a[0].fetch("installed_version", nil)
    if pg_stat_statements_ver != nil
      if Gem::Version.new(pg_stat_statements_ver) < Gem::Version.new(NEW_PG_STAT_STATEMENTS)
        query_name = "#{query_name}_legacy".to_sym
      end
    end
  end

  sql = if (custom_args = DEFAULT_ARGS[query_name].merge(args)) != {}
    sql_for(query_name: query_name) % custom_args
  else
    sql_for(query_name: query_name)
  end
  result = connection.exec(sql)

  display_result(
    result,
    title: description_for(query_name: query_name),
    in_format: in_format
  )
end

.sql_for(query_name:) ⇒ Object



163
164
165
166
167
# File 'lib/ruby-pg-extras.rb', line 163

def self.sql_for(query_name:)
  File.read(
    sql_path_for(query_name: query_name)
  )
end

.sql_path_for(query_name:) ⇒ Object



169
170
171
# File 'lib/ruby-pg-extras.rb', line 169

def self.sql_path_for(query_name:)
  File.join(File.dirname(__FILE__), "/ruby_pg_extras/queries/#{query_name}.sql")
end

.table_info(args: {}, in_format: :display_table) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/ruby-pg-extras.rb', line 116

def self.table_info(args: {}, in_format: :display_table)
  data = RubyPgExtras::TableInfo.call(args[:table_name])

  if in_format == :display_table
    RubyPgExtras::TableInfoPrint.call(data)
  elsif in_format == :hash
    data
  elsif in_format == :array
    data.map(&:values)
  else
    raise "Invalid 'in_format' argument!"
  end
end