pg_insights 0.3.2 → 0.4.1

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/pg_insights/application.js +91 -21
  3. data/app/assets/javascripts/pg_insights/plan_performance.js +53 -0
  4. data/app/assets/javascripts/pg_insights/query_comparison.js +1129 -0
  5. data/app/assets/javascripts/pg_insights/results/view_toggles.js +26 -5
  6. data/app/assets/javascripts/pg_insights/results.js +231 -1
  7. data/app/assets/stylesheets/pg_insights/analysis.css +2628 -0
  8. data/app/assets/stylesheets/pg_insights/application.css +51 -1
  9. data/app/assets/stylesheets/pg_insights/results.css +12 -1
  10. data/app/controllers/pg_insights/insights_controller.rb +486 -9
  11. data/app/helpers/pg_insights/application_helper.rb +339 -0
  12. data/app/helpers/pg_insights/insights_helper.rb +567 -0
  13. data/app/jobs/pg_insights/query_analysis_job.rb +142 -0
  14. data/app/models/pg_insights/query_execution.rb +198 -0
  15. data/app/services/pg_insights/query_analysis_service.rb +269 -0
  16. data/app/views/layouts/pg_insights/application.html.erb +2 -0
  17. data/app/views/pg_insights/insights/_compare_view.html.erb +264 -0
  18. data/app/views/pg_insights/insights/_empty_state.html.erb +9 -0
  19. data/app/views/pg_insights/insights/_execution_table_view.html.erb +86 -0
  20. data/app/views/pg_insights/insights/_history_bar.html.erb +33 -0
  21. data/app/views/pg_insights/insights/_perf_view.html.erb +244 -0
  22. data/app/views/pg_insights/insights/_plan_nodes.html.erb +12 -0
  23. data/app/views/pg_insights/insights/_plan_tree.html.erb +30 -0
  24. data/app/views/pg_insights/insights/_plan_tree_modern.html.erb +12 -0
  25. data/app/views/pg_insights/insights/_plan_view.html.erb +159 -0
  26. data/app/views/pg_insights/insights/_query_panel.html.erb +3 -2
  27. data/app/views/pg_insights/insights/_result.html.erb +19 -4
  28. data/app/views/pg_insights/insights/_results_info.html.erb +33 -9
  29. data/app/views/pg_insights/insights/_results_info_empty.html.erb +10 -0
  30. data/app/views/pg_insights/insights/_results_panel.html.erb +7 -9
  31. data/app/views/pg_insights/insights/_results_table.html.erb +0 -5
  32. data/app/views/pg_insights/insights/_visual_view.html.erb +212 -0
  33. data/app/views/pg_insights/insights/index.html.erb +4 -1
  34. data/app/views/pg_insights/timeline/compare.html.erb +3 -3
  35. data/config/routes.rb +6 -0
  36. data/lib/generators/pg_insights/install_generator.rb +20 -14
  37. data/lib/generators/pg_insights/templates/db/migrate/create_pg_insights_query_executions.rb +45 -0
  38. data/lib/pg_insights/engine.rb +8 -0
  39. data/lib/pg_insights/version.rb +1 -1
  40. data/lib/pg_insights.rb +30 -2
  41. metadata +20 -2
@@ -16,6 +16,7 @@ module PgInsights
16
16
  def copy_migrations
17
17
  copy_queries_migration
18
18
  copy_health_check_results_migration
19
+ copy_query_executions_migration
19
20
  end
20
21
 
21
22
  def create_initializer
@@ -53,7 +54,7 @@ module PgInsights
53
54
  puts ""
54
55
  puts "Features available:"
55
56
  puts "• Health Dashboard: '/pg_insights/health' - Monitor database health"
56
- puts "• Query Runner: '/pg_insights' - Run SQL queries with charts"
57
+ puts "• Query Runner: '/pg_insights' - Run SQL queries with charts & EXPLAIN ANALYZE"
57
58
  puts "• Timeline: '/pg_insights/timeline' - Track parameter changes over time"
58
59
  puts ""
59
60
  puts "Useful commands:"
@@ -98,22 +99,17 @@ module PgInsights
98
99
  config.background_job_queue = :pg_insights_health
99
100
 
100
101
  # === Cache and Timeout Settings ===
101
- # How long to cache health check results before considering them stale
102
- # Stale results will trigger background refresh when accessed
103
- #
104
- # Default: 5.minutes
105
102
  config.health_cache_expiry = 5.minutes
106
103
 
107
- # Timeout for individual health check queries to prevent long-running queries
108
- # from blocking the application
109
- #
110
- # Default: 10.seconds
111
- config.health_check_timeout = 10.seconds
104
+ # === Query Execution Timeouts ===
105
+ config.query_execution_timeout = 30.seconds
106
+ config.query_analysis_timeout = 60.seconds
107
+ config.health_check_timeout = 20.seconds
112
108
 
113
- # Maximum execution time for user queries in the insights interface
114
- #
115
- # Default: 30.seconds
116
- config.max_query_execution_time = 30.seconds
109
+ # === Heavy Analytics Environment ===
110
+ # config.query_execution_timeout = 120.seconds
111
+ # config.query_analysis_timeout = 180.seconds
112
+ # config.health_check_timeout = 60.seconds
117
113
 
118
114
  # === Timeline & Snapshot Settings ===
119
115
  #
@@ -217,6 +213,16 @@ module PgInsights
217
213
  end
218
214
  end
219
215
 
216
+ def copy_query_executions_migration
217
+ if migration_exists?("create_pg_insights_query_executions")
218
+ say_status("skipped", "Migration 'create_pg_insights_query_executions' already exists", :yellow)
219
+ else
220
+ puts "Copying PgInsights query executions migration..."
221
+ migration_template "db/migrate/create_pg_insights_query_executions.rb",
222
+ "db/migrate/create_pg_insights_query_executions.rb"
223
+ end
224
+ end
225
+
220
226
  def migration_exists?(migration_name)
221
227
  migrate_path = File.join(destination_root, "db", "migrate")
222
228
  return false unless File.directory?(migrate_path)
@@ -0,0 +1,45 @@
1
+ class CreatePgInsightsQueryExecutions < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :pg_insights_query_executions do |t|
4
+ t.references :query, null: true, foreign_key: { to_table: :pg_insights_queries }
5
+ t.text :sql_text, null: false
6
+ t.string :execution_type, null: false, default: "execute" # 'execute', 'analyze', 'both'
7
+ t.string :status, null: false, default: "pending" # 'pending', 'running', 'completed', 'failed'
8
+
9
+ # Execution Results
10
+ t.json :result_data, null: true # Query results when execution_type includes 'execute'
11
+ t.integer :result_rows_count, null: true
12
+ t.integer :result_columns_count, null: true
13
+
14
+ # Analysis Results
15
+ t.json :execution_plan, null: true # EXPLAIN ANALYZE output
16
+ t.text :plan_summary, null: true # Human-readable summary
17
+
18
+ # Performance Metrics
19
+ t.decimal :planning_time_ms, precision: 10, scale: 3, null: true
20
+ t.decimal :execution_time_ms, precision: 10, scale: 3, null: true
21
+ t.decimal :total_time_ms, precision: 10, scale: 3, null: true
22
+ t.decimal :query_cost, precision: 15, scale: 3, null: true
23
+
24
+ # Analysis Metadata
25
+ t.json :performance_insights, null: true # Optimization suggestions
26
+ t.json :execution_stats, null: true # Buffer usage, cache hits, etc.
27
+
28
+ # Error handling
29
+ t.text :error_message, null: true
30
+ t.text :error_detail, null: true
31
+
32
+ # Audit fields
33
+ t.timestamp :started_at, null: true
34
+ t.timestamp :completed_at, null: true
35
+ t.decimal :duration_ms, precision: 10, scale: 3, null: true
36
+
37
+ t.timestamps
38
+ end
39
+
40
+ add_index :pg_insights_query_executions, :execution_type
41
+ add_index :pg_insights_query_executions, :status
42
+ add_index :pg_insights_query_executions, :created_at
43
+ add_index :pg_insights_query_executions, [ :query_id, :created_at ]
44
+ end
45
+ end
@@ -10,10 +10,18 @@ module PgInsights
10
10
  app.config.assets.precompile += %w[
11
11
  pg_insights/application.css
12
12
  pg_insights/application.js
13
+ pg_insights/analysis.css
13
14
  pg_insights/health.css
14
15
  pg_insights/health.js
15
16
  pg_insights/results.css
16
17
  pg_insights/results.js
18
+ pg_insights/query_comparison.js
19
+ pg_insights/plan_performance.js
20
+ pg_insights/results/view_toggles.js
21
+ pg_insights/results/chart_renderer.js
22
+ pg_insights/results/table_manager.js
23
+ chartkick.js
24
+ Chart.bundle.js
17
25
  ]
18
26
  end
19
27
 
@@ -1,3 +1,3 @@
1
1
  module PgInsights
2
- VERSION = "0.3.2"
2
+ VERSION = "0.4.1"
3
3
  end
data/lib/pg_insights.rb CHANGED
@@ -5,8 +5,10 @@ module PgInsights
5
5
  mattr_accessor :enable_background_jobs, default: true
6
6
  mattr_accessor :health_cache_expiry, default: 5.minutes
7
7
  mattr_accessor :background_job_queue, default: :pg_insights_health
8
- mattr_accessor :max_query_execution_time, default: 30.seconds
9
- mattr_accessor :health_check_timeout, default: 10.seconds
8
+
9
+ mattr_accessor :query_execution_timeout, default: 30.seconds
10
+ mattr_accessor :query_analysis_timeout, default: 60.seconds
11
+ mattr_accessor :health_check_timeout, default: 20.seconds
10
12
 
11
13
  mattr_accessor :enable_snapshots, default: true
12
14
  mattr_accessor :snapshot_frequency, default: 1.day
@@ -17,6 +19,32 @@ module PgInsights
17
19
  yield self
18
20
  end
19
21
 
22
+ def self.query_execution_timeout_ms
23
+ validate_timeout(query_execution_timeout, "query_execution_timeout")
24
+ (query_execution_timeout.to_f * 1000).to_i
25
+ end
26
+
27
+ def self.query_analysis_timeout_ms
28
+ validate_timeout(query_analysis_timeout, "query_analysis_timeout")
29
+ (query_analysis_timeout.to_f * 1000).to_i
30
+ end
31
+
32
+ def self.health_check_timeout_ms
33
+ validate_timeout(health_check_timeout, "health_check_timeout")
34
+ (health_check_timeout.to_f * 1000).to_i
35
+ end
36
+
37
+ private
38
+
39
+ def self.validate_timeout(timeout, setting_name)
40
+ unless timeout.respond_to?(:to_f) && timeout.to_f > 0
41
+ raise ArgumentError, "#{setting_name} must be a positive number (seconds). Got: #{timeout.inspect}"
42
+ end
43
+ if timeout.to_f > 300
44
+ Rails.logger.warn "PgInsights: #{setting_name} is set to #{timeout.to_f}s, which is very high. Consider optimizing queries instead."
45
+ end
46
+ end
47
+
20
48
  def self.background_jobs_available?
21
49
  return false unless enable_background_jobs
22
50
  return false unless defined?(ActiveJob::Base)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_insights
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mezbah Alam
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-07-11 00:00:00.000000000 Z
11
+ date: 2025-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -51,10 +51,13 @@ files:
51
51
  - Rakefile
52
52
  - app/assets/javascripts/pg_insights/application.js
53
53
  - app/assets/javascripts/pg_insights/health.js
54
+ - app/assets/javascripts/pg_insights/plan_performance.js
55
+ - app/assets/javascripts/pg_insights/query_comparison.js
54
56
  - app/assets/javascripts/pg_insights/results.js
55
57
  - app/assets/javascripts/pg_insights/results/chart_renderer.js
56
58
  - app/assets/javascripts/pg_insights/results/table_manager.js
57
59
  - app/assets/javascripts/pg_insights/results/view_toggles.js
60
+ - app/assets/stylesheets/pg_insights/analysis.css
58
61
  - app/assets/stylesheets/pg_insights/application.css
59
62
  - app/assets/stylesheets/pg_insights/health.css
60
63
  - app/assets/stylesheets/pg_insights/results.css
@@ -69,25 +72,39 @@ files:
69
72
  - app/jobs/pg_insights/database_snapshot_job.rb
70
73
  - app/jobs/pg_insights/health_check_job.rb
71
74
  - app/jobs/pg_insights/health_check_scheduler_job.rb
75
+ - app/jobs/pg_insights/query_analysis_job.rb
72
76
  - app/jobs/pg_insights/recurring_health_checks_job.rb
73
77
  - app/models/pg_insights/application_record.rb
74
78
  - app/models/pg_insights/health_check_result.rb
75
79
  - app/models/pg_insights/query.rb
80
+ - app/models/pg_insights/query_execution.rb
76
81
  - app/services/pg_insights/health_check_service.rb
77
82
  - app/services/pg_insights/insight_query_service.rb
83
+ - app/services/pg_insights/query_analysis_service.rb
78
84
  - app/views/layouts/pg_insights/application.html.erb
79
85
  - app/views/pg_insights/health/index.html.erb
80
86
  - app/views/pg_insights/insights/_chart_view.html.erb
81
87
  - app/views/pg_insights/insights/_column_panel.html.erb
88
+ - app/views/pg_insights/insights/_compare_view.html.erb
89
+ - app/views/pg_insights/insights/_empty_state.html.erb
90
+ - app/views/pg_insights/insights/_execution_table_view.html.erb
91
+ - app/views/pg_insights/insights/_history_bar.html.erb
92
+ - app/views/pg_insights/insights/_perf_view.html.erb
93
+ - app/views/pg_insights/insights/_plan_nodes.html.erb
94
+ - app/views/pg_insights/insights/_plan_tree.html.erb
95
+ - app/views/pg_insights/insights/_plan_tree_modern.html.erb
96
+ - app/views/pg_insights/insights/_plan_view.html.erb
82
97
  - app/views/pg_insights/insights/_query_examples.html.erb
83
98
  - app/views/pg_insights/insights/_query_panel.html.erb
84
99
  - app/views/pg_insights/insights/_result.html.erb
85
100
  - app/views/pg_insights/insights/_results_info.html.erb
101
+ - app/views/pg_insights/insights/_results_info_empty.html.erb
86
102
  - app/views/pg_insights/insights/_results_panel.html.erb
87
103
  - app/views/pg_insights/insights/_results_table.html.erb
88
104
  - app/views/pg_insights/insights/_stats_view.html.erb
89
105
  - app/views/pg_insights/insights/_table_controls.html.erb
90
106
  - app/views/pg_insights/insights/_table_view.html.erb
107
+ - app/views/pg_insights/insights/_visual_view.html.erb
91
108
  - app/views/pg_insights/insights/index.html.erb
92
109
  - app/views/pg_insights/timeline/compare.html.erb
93
110
  - app/views/pg_insights/timeline/index.html.erb
@@ -98,6 +115,7 @@ files:
98
115
  - lib/generators/pg_insights/install_generator.rb
99
116
  - lib/generators/pg_insights/templates/db/migrate/create_pg_insights_health_check_results.rb
100
117
  - lib/generators/pg_insights/templates/db/migrate/create_pg_insights_queries.rb
118
+ - lib/generators/pg_insights/templates/db/migrate/create_pg_insights_query_executions.rb
101
119
  - lib/pg_insights.rb
102
120
  - lib/pg_insights/engine.rb
103
121
  - lib/pg_insights/version.rb