pghero 3.7.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -2
  3. data/LICENSE.txt +1 -1
  4. data/README.md +4 -3
  5. data/app/assets/javascripts/pghero/Chart.bundle.js +2228 -5320
  6. data/app/assets/javascripts/pghero/application.js +104 -68
  7. data/app/assets/javascripts/pghero/highlight.min.js +330 -341
  8. data/app/assets/javascripts/pghero/nouislider.js +64 -5
  9. data/app/assets/stylesheets/pghero/application.css +7 -1
  10. data/app/controllers/pg_hero/home_controller.rb +75 -41
  11. data/app/views/layouts/pg_hero/application.html.erb +1 -1
  12. data/app/views/pg_hero/home/_live_queries_table.html.erb +4 -2
  13. data/app/views/pg_hero/home/_queries_table.html.erb +8 -7
  14. data/app/views/pg_hero/home/_query_stats_slider.html.erb +1 -0
  15. data/app/views/pg_hero/home/_suggested_index.html.erb +3 -3
  16. data/app/views/pg_hero/home/explain.html.erb +2 -1
  17. data/app/views/pg_hero/home/index.html.erb +17 -18
  18. data/app/views/pg_hero/home/index_bloat.html.erb +2 -2
  19. data/app/views/pg_hero/home/live_queries.html.erb +7 -3
  20. data/app/views/pg_hero/home/queries.html.erb +31 -6
  21. data/app/views/pg_hero/home/show_query.html.erb +5 -5
  22. data/app/views/pg_hero/home/space.html.erb +5 -4
  23. data/app/views/pg_hero/home/tune.html.erb +1 -1
  24. data/lib/generators/pghero/templates/config.yml.tt +6 -1
  25. data/lib/generators/pghero/templates/query_stats.rb.tt +7 -1
  26. data/lib/generators/pghero/templates/upgrade_query_stats.rb.tt +23 -0
  27. data/lib/generators/pghero/upgrade_query_stats_generator.rb +19 -0
  28. data/lib/pghero/database.rb +6 -9
  29. data/lib/pghero/engine.rb +3 -10
  30. data/lib/pghero/methods/basic.rb +28 -27
  31. data/lib/pghero/methods/connections.rb +16 -32
  32. data/lib/pghero/methods/explain.rb +13 -20
  33. data/lib/pghero/methods/indexes.rb +8 -5
  34. data/lib/pghero/methods/kill.rb +4 -1
  35. data/lib/pghero/methods/maintenance.rb +14 -20
  36. data/lib/pghero/methods/queries.rb +7 -5
  37. data/lib/pghero/methods/query_stats.rb +264 -238
  38. data/lib/pghero/methods/replication.rb +9 -20
  39. data/lib/pghero/methods/sequences.rb +1 -1
  40. data/lib/pghero/methods/settings.rb +6 -11
  41. data/lib/pghero/methods/space.rb +11 -8
  42. data/lib/pghero/methods/suggested_indexes.rb +15 -16
  43. data/lib/pghero/methods/system.rb +6 -106
  44. data/lib/pghero/methods/tables.rb +7 -3
  45. data/lib/pghero/query.rb +8 -0
  46. data/lib/pghero/query_stats.rb +3 -0
  47. data/lib/pghero/version.rb +1 -1
  48. data/lib/pghero.rb +10 -42
  49. data/licenses/LICENSE-chart.js.txt +1 -1
  50. metadata +8 -8
  51. data/app/assets/javascripts/pghero/jquery.js +0 -10993
  52. data/lib/pghero/methods/users.rb +0 -95
  53. data/licenses/LICENSE-jquery.txt +0 -20
@@ -93,7 +93,7 @@ module PgHero
93
93
  SELECT
94
94
  n.nspname AS schema,
95
95
  c.relname AS sequence,
96
- has_sequence_privilege(c.oid, 'SELECT') AS readable
96
+ has_sequence_privilege(c.oid, 'SELECT') AND (c.relpersistence <> 'u' OR NOT pg_is_in_recovery()) AS readable
97
97
  FROM
98
98
  pg_class c
99
99
  INNER JOIN
@@ -3,24 +3,19 @@ module PgHero
3
3
  module Settings
4
4
  def settings
5
5
  names =
6
- if server_version_num >= 100000
6
+ if server_version_num >= 180000
7
7
  %i(
8
8
  max_connections shared_buffers effective_cache_size maintenance_work_mem
9
9
  checkpoint_completion_target wal_buffers default_statistics_target
10
10
  random_page_cost effective_io_concurrency work_mem huge_pages
11
- min_wal_size max_wal_size
12
- )
13
- elsif server_version_num >= 90500
14
- %i(
15
- max_connections shared_buffers effective_cache_size work_mem
16
- maintenance_work_mem min_wal_size max_wal_size checkpoint_completion_target
17
- wal_buffers default_statistics_target
11
+ jit wal_compression io_method min_wal_size max_wal_size
18
12
  )
19
13
  else
20
14
  %i(
21
- max_connections shared_buffers effective_cache_size work_mem
22
- maintenance_work_mem checkpoint_segments checkpoint_completion_target
23
- wal_buffers default_statistics_target
15
+ max_connections shared_buffers effective_cache_size maintenance_work_mem
16
+ checkpoint_completion_target wal_buffers default_statistics_target
17
+ random_page_cost effective_io_concurrency work_mem huge_pages
18
+ jit wal_compression min_wal_size max_wal_size
24
19
  )
25
20
  end
26
21
  fetch_settings(names)
@@ -52,7 +52,7 @@ module PgHero
52
52
  sizes = relation_sizes.to_h { |r| [[r[:schema], r[:relation]], r[:size_bytes]] }
53
53
  start_at = days.days.ago
54
54
 
55
- stats = select_all_stats <<~SQL
55
+ sql = <<~SQL
56
56
  WITH t AS (
57
57
  SELECT
58
58
  schema,
@@ -61,8 +61,8 @@ module PgHero
61
61
  FROM
62
62
  pghero_space_stats
63
63
  WHERE
64
- database = #{quote(id)}
65
- AND captured_at >= #{quote(start_at)}
64
+ database = :id
65
+ AND captured_at >= :start_at
66
66
  GROUP BY
67
67
  1, 2
68
68
  )
@@ -75,6 +75,7 @@ module PgHero
75
75
  ORDER BY
76
76
  1, 2
77
77
  SQL
78
+ stats = select_all_stats(sql, {id: id, start_at: start_at})
78
79
 
79
80
  stats.each do |r|
80
81
  relation = [r[:schema], r[:relation]]
@@ -95,20 +96,22 @@ module PgHero
95
96
  sizes = relation_sizes.map { |r| [[r[:schema], r[:relation]], r[:size_bytes]] }.to_h
96
97
  start_at = 30.days.ago
97
98
 
98
- stats = select_all_stats <<~SQL
99
+ sql = <<~SQL
99
100
  SELECT
100
101
  captured_at,
101
102
  size AS size_bytes
102
103
  FROM
103
104
  pghero_space_stats
104
105
  WHERE
105
- database = #{quote(id)}
106
- AND captured_at >= #{quote(start_at)}
107
- AND schema = #{quote(schema)}
108
- AND relation = #{quote(relation)}
106
+ database = :id
107
+ AND captured_at >= :start_at
108
+ AND schema = :schema
109
+ AND relation = :relation
109
110
  ORDER BY
110
111
  1 ASC
111
112
  SQL
113
+ binds = {id: id, start_at: start_at, schema: schema, relation: relation}
114
+ stats = select_all_stats(sql, binds)
112
115
 
113
116
  stats << {
114
117
  captured_at: Time.now,
@@ -2,7 +2,7 @@ module PgHero
2
2
  module Methods
3
3
  module SuggestedIndexes
4
4
  def suggested_indexes_enabled?
5
- defined?(PgQuery) && Gem::Version.new(PgQuery::VERSION) >= Gem::Version.new("2") && query_stats_enabled?
5
+ defined?(PgQuery) && Gem::Version.new(PgQuery::VERSION) >= Gem::Version.new("6") && query_stats_enabled?
6
6
  end
7
7
 
8
8
  # TODO clean this mess
@@ -102,9 +102,9 @@ module PgHero
102
102
  end
103
103
 
104
104
  # get stats about columns for relevant tables
105
- tables = parts.values.map { |t| t[:table] }.uniq
105
+ tables = parts.values.filter_map { |t| t[:table] }.uniq
106
106
  # TODO get schema from query structure, then try search path
107
- schema = PgHero.connection_config(connection_model)[:schema] || "public"
107
+ schema = connection_model.connection_db_config.configuration_hash[:schema] || "public"
108
108
  if tables.any?
109
109
  row_stats = table_stats(table: tables, schema: schema).to_h { |i| [i[:table], i[:estimated_rows]] }
110
110
  col_stats = column_stats(table: tables, schema: schema).group_by { |i| i[:table] }
@@ -287,33 +287,29 @@ module PgHero
287
287
  if tree.bool_expr.boolop == :AND_EXPR
288
288
  tree.bool_expr.args.flat_map { |v| parse_where(v) }
289
289
  else
290
- raise "Not Implemented"
290
+ raise Error, "Not Implemented"
291
291
  end
292
- elsif aexpr && ["=", "<>", ">", ">=", "<", "<=", "~~", "~~*", "BETWEEN"].include?(aexpr.name.first.string.send(str_method))
293
- [{column: aexpr.lexpr.column_ref.fields.last.string.send(str_method), op: aexpr.name.first.string.send(str_method)}]
292
+ elsif aexpr && ["=", "<>", ">", ">=", "<", "<=", "~~", "~~*", "BETWEEN"].include?(aexpr.name.first.string.sval)
293
+ [{column: aexpr.lexpr.column_ref.fields.last.string.sval, op: aexpr.name.first.string.sval}]
294
294
  elsif tree.null_test
295
295
  op = tree.null_test.nulltesttype == :IS_NOT_NULL ? "not_null" : "null"
296
- [{column: tree.null_test.arg.column_ref.fields.last.string.send(str_method), op: op}]
296
+ [{column: tree.null_test.arg.column_ref.fields.last.string.sval, op: op}]
297
297
  else
298
- raise "Not Implemented"
298
+ raise Error, "Not Implemented"
299
299
  end
300
300
  end
301
301
 
302
- def str_method
303
- @str_method ||= Gem::Version.new(PgQuery::VERSION) >= Gem::Version.new("4") ? :sval : :str
304
- end
305
-
306
302
  def parse_sort(sort_clause)
307
303
  sort_clause.map do |v|
308
304
  {
309
- column: v.sort_by.node.column_ref.fields.last.string.send(str_method),
305
+ column: v.sort_by.node.column_ref.fields.last.string.sval,
310
306
  direction: v.sort_by.sortby_dir == :SORTBY_DESC ? "desc" : "asc"
311
307
  }
312
308
  end
313
309
  end
314
310
 
315
311
  def column_stats(schema: nil, table: nil)
316
- select_all <<~SQL
312
+ sql = <<~SQL
317
313
  SELECT
318
314
  schemaname AS schema,
319
315
  tablename AS table,
@@ -323,11 +319,14 @@ module PgHero
323
319
  FROM
324
320
  pg_stats
325
321
  WHERE
326
- schemaname = #{quote(schema)}
327
- #{table ? "AND tablename IN (#{Array(table).map { |t| quote(t) }.join(", ")})" : ""}
322
+ schemaname = :schema
323
+ #{"AND tablename IN (:table)" if table}
328
324
  ORDER BY
329
325
  1, 2, 3
330
326
  SQL
327
+ binds = {schema: schema}
328
+ binds[:table] = Array(table) if table
329
+ select_all(sql, binds)
331
330
  end
332
331
  end
333
332
  end
@@ -10,8 +10,6 @@ module PgHero
10
10
  :aws
11
11
  elsif gcp_database_id
12
12
  :gcp
13
- elsif azure_resource_id
14
- :azure
15
13
  end
16
14
  end
17
15
 
@@ -77,54 +75,6 @@ module PgHero
77
75
  end
78
76
  end
79
77
 
80
- def azure_stats(metric_name, duration: nil, period: nil, offset: nil, series: false)
81
- # TODO DRY with RDS stats
82
- duration = (duration || 1.hour).to_i
83
- period = (period || 1.minute).to_i
84
- offset = (offset || 0).to_i
85
- end_time = Time.at(((Time.now - offset).to_f / period).ceil * period)
86
- start_time = end_time - duration
87
-
88
- interval =
89
- case period
90
- when 60
91
- "PT1M"
92
- when 300
93
- "PT5M"
94
- when 900
95
- "PT15M"
96
- when 1800
97
- "PT30M"
98
- when 3600
99
- "PT1H"
100
- else
101
- raise Error, "Unsupported period"
102
- end
103
-
104
- client = Azure::Monitor::Profiles::Latest::Mgmt::Client.new
105
- # call utc to convert +00:00 to Z
106
- timespan = "#{start_time.utc.iso8601}/#{end_time.utc.iso8601}"
107
- results = client.metrics.list(
108
- azure_resource_id,
109
- metricnames: metric_name,
110
- aggregation: "Average",
111
- timespan: timespan,
112
- interval: interval
113
- )
114
-
115
- data = {}
116
- result = results.value.first
117
- if result
118
- result.timeseries.first.data.each do |point|
119
- data[point.time_stamp.to_time] = point.average
120
- end
121
- end
122
-
123
- add_missing_data(data, start_time, end_time, period) if series
124
-
125
- data
126
- end
127
-
128
78
  private
129
79
 
130
80
  def gcp_stats(metric_name, duration: nil, period: nil, offset: nil, series: false)
@@ -139,25 +89,19 @@ module PgHero
139
89
  raise Error, "Invalid metric name" unless /\A[a-z\/_]+\z/i.match?(metric_name)
140
90
  raise Error, "Invalid database id" unless /\A[a-z0-9\-:]+\z/i.match?(gcp_database_id)
141
91
 
142
- # we handle four situations:
92
+ # we handle three situations:
143
93
  # 1. google-cloud-monitoring-v3
144
- # 2. google-cloud-monitoring >= 1
145
- # 3. google-cloud-monitoring < 1
146
- # 4. google-apis-monitoring_v3
94
+ # 2. google-cloud-monitoring
95
+ # 3. google-apis-monitoring_v3
147
96
  begin
148
97
  require "google/cloud/monitoring/v3"
149
98
  rescue LoadError
150
- begin
151
- require "google/cloud/monitoring"
152
- rescue LoadError
153
- require "google/apis/monitoring_v3"
154
- end
99
+ require "google/apis/monitoring_v3"
155
100
  end
156
101
 
157
102
  # for situations 1 and 2
158
- # Google::Cloud::Monitoring.metric_service is documented
159
- # but doesn't work for situation 1
160
- if defined?(Google::Cloud::Monitoring::V3::MetricService::Client)
103
+ # Google::Cloud::Monitoring.metric_service doesn't work for situation 1
104
+ if defined?(Google::Cloud::Monitoring::V3)
161
105
  client = Google::Cloud::Monitoring::V3::MetricService::Client.new
162
106
 
163
107
  interval = Google::Cloud::Monitoring::V3::TimeInterval.new
@@ -178,29 +122,6 @@ module PgHero
178
122
  view: Google::Cloud::Monitoring::V3::ListTimeSeriesRequest::TimeSeriesView::FULL,
179
123
  aggregation: aggregation
180
124
  })
181
- elsif defined?(Google::Cloud::Monitoring)
182
- require "google/cloud/monitoring"
183
-
184
- client = Google::Cloud::Monitoring::Metric.new
185
-
186
- interval = Google::Monitoring::V3::TimeInterval.new
187
- interval.end_time = Google::Protobuf::Timestamp.new(seconds: end_time.to_i)
188
- # subtract period to make sure we get first data point
189
- interval.start_time = Google::Protobuf::Timestamp.new(seconds: (start_time - period).to_i)
190
-
191
- aggregation = Google::Monitoring::V3::Aggregation.new
192
- # may be better to use ALIGN_NEXT_OLDER for space stats to show most recent data point
193
- # stick with average for now to match AWS
194
- aggregation.per_series_aligner = Google::Monitoring::V3::Aggregation::Aligner::ALIGN_MEAN
195
- aggregation.alignment_period = period
196
-
197
- results = client.list_time_series(
198
- "projects/#{gcp_database_id.split(":").first}",
199
- "metric.type = \"cloudsql.googleapis.com/database/#{metric_name}\" AND resource.label.database_id = \"#{gcp_database_id}\"",
200
- interval,
201
- Google::Monitoring::V3::ListTimeSeriesRequest::TimeSeriesView::FULL,
202
- aggregation: aggregation
203
- )
204
125
  else
205
126
  client = Google::Apis::MonitoringV3::MonitoringService.new
206
127
 
@@ -264,32 +185,11 @@ module PgHero
264
185
  }
265
186
  gcp_stats(metrics[metric_key], **options)
266
187
  end
267
- when :azure
268
- if metric_key == :free_space
269
- quota = azure_stats("storage_limit", **options)
270
- used = azure_stats("storage_used", **options)
271
- free_space(quota, used)
272
- else
273
- replication_lag_stat = azure_flexible_server? ? "physical_replication_delay_in_seconds" : "pg_replica_log_delay_in_seconds"
274
- metrics = {
275
- cpu: "cpu_percent",
276
- connections: "active_connections",
277
- replication_lag: replication_lag_stat,
278
- read_iops: "read_iops", # flexible server only
279
- write_iops: "write_iops" # flexible server only
280
- }
281
- raise Error, "Metric not supported" unless metrics[metric_key]
282
- azure_stats(metrics[metric_key], **options)
283
- end
284
188
  else
285
189
  raise NotEnabled, "System stats not enabled"
286
190
  end
287
191
  end
288
192
 
289
- def azure_flexible_server?
290
- azure_resource_id.include?("/Microsoft.DBforPostgreSQL/flexibleServers/")
291
- end
292
-
293
193
  # only use data points included in both series
294
194
  # this also eliminates need to align Time.now
295
195
  def free_space(quota, used)
@@ -44,7 +44,7 @@ module PgHero
44
44
  end
45
45
 
46
46
  def table_stats(schema: nil, table: nil)
47
- select_all <<~SQL
47
+ sql = <<~SQL
48
48
  SELECT
49
49
  nspname AS schema,
50
50
  relname AS table,
@@ -56,11 +56,15 @@ module PgHero
56
56
  pg_namespace ON pg_namespace.oid = pg_class.relnamespace
57
57
  WHERE
58
58
  relkind = 'r'
59
- #{schema ? "AND nspname = #{quote(schema)}" : nil}
60
- #{table ? "AND relname IN (#{Array(table).map { |t| quote(t) }.join(", ")})" : nil}
59
+ #{"AND nspname = :schema" if schema}
60
+ #{"AND relname IN (:table)" if table}
61
61
  ORDER BY
62
62
  1, 2
63
63
  SQL
64
+ binds = {}
65
+ binds[:schema] = schema if schema
66
+ binds[:table] = Array(table) if table
67
+ select_all(sql, binds)
64
68
  end
65
69
  end
66
70
  end
@@ -0,0 +1,8 @@
1
+ module PgHero
2
+ class Query < Stats
3
+ self.table_name = "pghero_queries"
4
+
5
+ # do not use outside of testing since no index on query_id
6
+ has_many :query_stats, class_name: "QueryStats"
7
+ end
8
+ end
@@ -1,5 +1,8 @@
1
1
  module PgHero
2
2
  class QueryStats < Stats
3
3
  self.table_name = "pghero_query_stats"
4
+
5
+ # do not add belongs_to :query
6
+ # as it breaks backfill if query column exists
4
7
  end
5
8
  end
@@ -1,3 +1,3 @@
1
1
  module PgHero
2
- VERSION = "3.7.0"
2
+ VERSION = "4.0.0"
3
3
  end
data/lib/pghero.rb CHANGED
@@ -1,9 +1,6 @@
1
1
  # dependencies
2
2
  require "active_support"
3
3
 
4
- # stdlib
5
- require "forwardable"
6
-
7
4
  # methods
8
5
  require_relative "pghero/methods/basic"
9
6
  require_relative "pghero/methods/connections"
@@ -21,7 +18,6 @@ require_relative "pghero/methods/space"
21
18
  require_relative "pghero/methods/suggested_indexes"
22
19
  require_relative "pghero/methods/system"
23
20
  require_relative "pghero/methods/tables"
24
- require_relative "pghero/methods/users"
25
21
 
26
22
  require_relative "pghero/database"
27
23
  require_relative "pghero/engine" if defined?(Rails)
@@ -30,6 +26,7 @@ require_relative "pghero/version"
30
26
  module PgHero
31
27
  autoload :Connection, "pghero/connection"
32
28
  autoload :Stats, "pghero/stats"
29
+ autoload :Query, "pghero/query"
33
30
  autoload :QueryStats, "pghero/query_stats"
34
31
  autoload :SpaceStats, "pghero/space_stats"
35
32
 
@@ -54,20 +51,6 @@ module PgHero
54
51
  self.filter_data = ENV["PGHERO_FILTER_DATA"].to_s.size > 0
55
52
 
56
53
  class << self
57
- extend Forwardable
58
- def_delegators :primary_database, :aws_access_key_id, :analyze, :analyze_tables, :autoindex, :autovacuum_danger,
59
- :best_index, :blocked_queries, :connections, :connection_sources, :connection_states, :connection_stats,
60
- :cpu_usage, :create_user, :database_size, :aws_db_instance_identifier, :disable_query_stats, :drop_user,
61
- :duplicate_indexes, :enable_query_stats, :explain, :historical_query_stats_enabled?, :index_caching,
62
- :index_hit_rate, :index_usage, :indexes, :invalid_constraints, :invalid_indexes, :kill, :kill_all, :kill_long_running_queries,
63
- :last_stats_reset_time, :long_running_queries, :maintenance_info, :missing_indexes, :query_stats,
64
- :query_stats_available?, :query_stats_enabled?, :query_stats_extension_enabled?, :query_stats_readable?,
65
- :rds_stats, :read_iops_stats, :aws_region, :relation_sizes, :replica?, :replication_lag, :replication_lag_stats,
66
- :reset_query_stats, :reset_stats, :running_queries, :aws_secret_access_key, :sequence_danger, :sequences, :settings,
67
- :slow_queries, :space_growth, :ssl_used?, :suggested_indexes, :suggested_indexes_by_query,
68
- :suggested_indexes_enabled?, :system_stats_enabled?, :table_caching, :table_hit_rate, :table_stats,
69
- :total_connections, :transaction_id_danger, :unused_indexes, :unused_tables, :write_iops_stats
70
-
71
54
  def time_zone=(time_zone)
72
55
  @time_zone = time_zone.is_a?(ActiveSupport::TimeZone) ? time_zone : ActiveSupport::TimeZone[time_zone.to_s]
73
56
  end
@@ -107,6 +90,10 @@ module PgHero
107
90
  @visualize_url ||= config["visualize_url"] || ENV["PGHERO_VISUALIZE_URL"] || "https://tatiyants.com/pev/#/plans/new"
108
91
  end
109
92
 
93
+ def kill_enabled?
94
+ !config["disable_kill"]
95
+ end
96
+
110
97
  def config
111
98
  @config ||= file_config || default_config
112
99
  end
@@ -130,7 +117,7 @@ module PgHero
130
117
  elsif config["databases"] # preferred format
131
118
  config
132
119
  elsif config_file_exists
133
- raise "Invalid config file"
120
+ raise Error, "Invalid config file"
134
121
  else
135
122
  nil
136
123
  end
@@ -144,8 +131,8 @@ module PgHero
144
131
  databases = {}
145
132
 
146
133
  unless ENV["PGHERO_DATABASE_URL"]
147
- ActiveRecord::Base.configurations.configs_for(env_name: env, include_replicas_key => true).each do |db|
148
- databases[db.send(spec_name_key)] = {"spec" => db.send(spec_name_key)}
134
+ ActiveRecord::Base.configurations.configs_for(env_name: env, include_hidden: true).each do |db|
135
+ databases[db.name] = {"spec" => db.name}
149
136
  end
150
137
  end
151
138
 
@@ -158,8 +145,7 @@ module PgHero
158
145
  if databases.size == 1
159
146
  databases.values.first.merge!(
160
147
  "aws_db_instance_identifier" => ENV["PGHERO_DB_INSTANCE_IDENTIFIER"],
161
- "gcp_database_id" => ENV["PGHERO_GCP_DATABASE_ID"],
162
- "azure_resource_id" => ENV["PGHERO_AZURE_RESOURCE_ID"]
148
+ "gcp_database_id" => ENV["PGHERO_GCP_DATABASE_ID"]
163
149
  )
164
150
  end
165
151
 
@@ -184,10 +170,6 @@ module PgHero
184
170
  @databases
185
171
  end
186
172
 
187
- def primary_database
188
- databases.values.first
189
- end
190
-
191
173
  def capture_query_stats(verbose: false)
192
174
  each_database do |database|
193
175
  next unless database.capture_query_stats?
@@ -224,6 +206,7 @@ module PgHero
224
206
  # delete previous stats
225
207
  # go database by database to use an index
226
208
  # stats for old databases are not cleaned up since we can't use an index
209
+ # TODO clean queries
227
210
  def clean_query_stats(before: nil)
228
211
  each_database do |database|
229
212
  database.clean_query_stats(before: before)
@@ -236,21 +219,6 @@ module PgHero
236
219
  end
237
220
  end
238
221
 
239
- # private
240
- def connection_config(model)
241
- model.connection_db_config.configuration_hash
242
- end
243
-
244
- # private
245
- def spec_name_key
246
- :name
247
- end
248
-
249
- # private
250
- def include_replicas_key
251
- :include_hidden
252
- end
253
-
254
222
  private
255
223
 
256
224
  def each_database
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2014-2022 Chart.js Contributors
3
+ Copyright (c) 2014-2024 Chart.js Contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
6
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pghero
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.7.0
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '7.1'
18
+ version: '7.2'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: '7.1'
25
+ version: '7.2'
26
26
  email: andrew@ankane.org
27
27
  executables: []
28
28
  extensions: []
@@ -37,7 +37,6 @@ files:
37
37
  - app/assets/javascripts/pghero/application.js
38
38
  - app/assets/javascripts/pghero/chartkick.js
39
39
  - app/assets/javascripts/pghero/highlight.min.js
40
- - app/assets/javascripts/pghero/jquery.js
41
40
  - app/assets/javascripts/pghero/nouislider.js
42
41
  - app/assets/stylesheets/pghero/application.css
43
42
  - app/assets/stylesheets/pghero/arduino-light.css
@@ -69,6 +68,8 @@ files:
69
68
  - lib/generators/pghero/templates/config.yml.tt
70
69
  - lib/generators/pghero/templates/query_stats.rb.tt
71
70
  - lib/generators/pghero/templates/space_stats.rb.tt
71
+ - lib/generators/pghero/templates/upgrade_query_stats.rb.tt
72
+ - lib/generators/pghero/upgrade_query_stats_generator.rb
72
73
  - lib/pghero.rb
73
74
  - lib/pghero/connection.rb
74
75
  - lib/pghero/database.rb
@@ -89,7 +90,7 @@ files:
89
90
  - lib/pghero/methods/suggested_indexes.rb
90
91
  - lib/pghero/methods/system.rb
91
92
  - lib/pghero/methods/tables.rb
92
- - lib/pghero/methods/users.rb
93
+ - lib/pghero/query.rb
93
94
  - lib/pghero/query_stats.rb
94
95
  - lib/pghero/space_stats.rb
95
96
  - lib/pghero/stats.rb
@@ -100,7 +101,6 @@ files:
100
101
  - licenses/LICENSE-chartkick.js.txt
101
102
  - licenses/LICENSE-date-fns.txt
102
103
  - licenses/LICENSE-highlight.js.txt
103
- - licenses/LICENSE-jquery.txt
104
104
  - licenses/LICENSE-kurkle-color.txt
105
105
  - licenses/LICENSE-nouislider.txt
106
106
  homepage: https://github.com/ankane/pghero
@@ -114,14 +114,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: '3.2'
117
+ version: '3.3'
118
118
  required_rubygems_version: !ruby/object:Gem::Requirement
119
119
  requirements:
120
120
  - - ">="
121
121
  - !ruby/object:Gem::Version
122
122
  version: '0'
123
123
  requirements: []
124
- rubygems_version: 3.6.7
124
+ rubygems_version: 4.0.16
125
125
  specification_version: 4
126
126
  summary: A performance dashboard for Postgres
127
127
  test_files: []