rails-pg-extras 5.5.1 → 5.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8bb397d676884df226763f0b5e11046dae35f31e434e1dc9fbee727d71542b36
4
- data.tar.gz: 533fcb32dbdac4eb85601c0a9e194175370f37ab9245bae20b2a0c6cc18d50ce
3
+ metadata.gz: 12c092356cb3e67c70abd5e49d61227fda3872353846b2fc18f23e83e5b33526
4
+ data.tar.gz: 795c689588341078ed71d1ab6e522ba3b2d26e968d5f1a060983f70c0a163732
5
5
  SHA512:
6
- metadata.gz: 2f1eb7423937f8ffebaac99e65451cb9dbc5ba9f7cf6489ef7a4bd1042b4f5db108de08f4e1d41ec7ccd847a95af4c7d5abbc780a50161b6791c5e20aeade994
7
- data.tar.gz: 9c2e23d4fbe6ea97b4c217648dab172de9f46d67a07587b00c2c0bfd1f9f0cc70336aa26b4ab09e85dd60d1be95d6cd8c611df95904b47a1e90dab6ddc881798
6
+ metadata.gz: 821ad0700c0b8d6fc352e15f7c45591354ac49d061c16d67e55b1778ae1ea4b979bfd62f76dc0b0bebd6cf8716803fb7e799434deba397d28496ac634a4c34af
7
+ data.tar.gz: 5104d36a6a7e7a709f9e8be494178624b2e727d89e6958729dd00497245f11d2f8ae9a329c2ae848a00d41bf85e97b0eadb8cf17597678249e0150aa5837c120
@@ -12,7 +12,7 @@ jobs:
12
12
  strategy:
13
13
  fail-fast: false
14
14
  matrix:
15
- ruby-version: ['3.3', '3.2', '3.1', '3.0', '2.7', '2.6']
15
+ ruby-version: ['3.3', '3.2', '3.1', '3.0', '2.7']
16
16
  steps:
17
17
  - uses: actions/checkout@v4
18
18
  - name: Run PostgreSQL 12
data/README.md CHANGED
@@ -210,6 +210,47 @@ you can add this info to the output:
210
210
 
211
211
  ![Marginalia logs](https://github.com/pawurb/rails-pg-extras/raw/main/marginalia-logs.png)
212
212
 
213
+ ### `missing_fk_indexes`
214
+
215
+ This method lists columns likely to be foreign keys (i.e. column name ending in `_id` and related table exists) but don't have an index. It's recommended to always index foreign key columns because they are used for searching relation objects.
216
+
217
+ You can add indexes on the columns returned by this query and later check if they are receiving scans using the [unused_indexes method](#unused_indexes). Please remember that each index decreases write performance and autovacuuming overhead, so be careful when adding multiple indexes to often updated tables.
218
+
219
+ ```ruby
220
+ RailsPgExtras.missing_fk_indexes(args: { table_name: "users" })
221
+
222
+ +---------------------------------+
223
+ | Missing foreign key indexes |
224
+ +-------------------+-------------+
225
+ | table | column_name |
226
+ +-------------------+-------------+
227
+ | feedbacks | team_id |
228
+ | votes | user_id |
229
+ +-------------------+-------------+
230
+
231
+ ```
232
+
233
+ `table_name` argument is optional, if omitted, the method will display missing fk indexes for all the tables.
234
+
235
+ ## `missing_fk_constraints`
236
+
237
+ Similarly to the previous method, this one shows columns likely to be foreign keys that don't have a corresponding foreign key constraint. Foreign key constraints improve data integrity in the database by preventing relations with nonexisting objects. You can read more about the benefits of using foreign keys [in this blog post](https://pawelurbanek.com/rails-postgresql-data-integrity).
238
+
239
+ ```ruby
240
+ RailsPgExtras.missing_fk_constraints(args: { table_name: "users" })
241
+
242
+ +---------------------------------+
243
+ | Missing foreign key constraints |
244
+ +-------------------+-------------+
245
+ | table | column_name |
246
+ +-------------------+-------------+
247
+ | feedbacks | team_id |
248
+ | votes | user_id |
249
+ +-------------------+-------------+
250
+
251
+ ```
252
+
253
+ `table_name` argument is optional, if omitted, method will display missing fk constraints for all the tables.
213
254
 
214
255
  ### `table_info`
215
256
 
@@ -20,8 +20,10 @@ module RailsPgExtras::Web
20
20
 
21
21
  private
22
22
 
23
+ SKIP_QUERIES = %i[table_schema table_foreign_keys].freeze
24
+
23
25
  def load_queries
24
- @all_queries = (RailsPgExtras::QUERIES - RailsPgExtras::Web::ACTIONS).inject({}) do |memo, query_name|
26
+ @all_queries = (RailsPgExtras::QUERIES - RailsPgExtras::Web::ACTIONS - SKIP_QUERIES).inject({}) do |memo, query_name|
25
27
  unless query_name.in? %i[mandelbrot]
26
28
  memo[query_name] = { disabled: query_disabled?(query_name) }
27
29
  end
@@ -6,6 +6,8 @@ require "rails_pg_extras/diagnose_data"
6
6
  require "rails_pg_extras/diagnose_print"
7
7
  require "rails_pg_extras/index_info"
8
8
  require "rails_pg_extras/index_info_print"
9
+ require "rails_pg_extras/missing_fk_indexes"
10
+ require "rails_pg_extras/missing_fk_constraints"
9
11
  require "rails_pg_extras/table_info"
10
12
  require "rails_pg_extras/table_info_print"
11
13
 
@@ -26,32 +28,12 @@ module RailsPgExtras
26
28
  end
27
29
 
28
30
  def self.run_query(query_name:, in_format:, args: {})
29
- if %i(calls outliers).include?(query_name)
30
- pg_stat_statements_version_sql = "SELECT installed_version
31
- FROM pg_available_extensions
32
- WHERE name = 'pg_stat_statements'"
33
- if (version = RailsPgExtras.connection.execute(pg_stat_statements_version_sql)
34
- .to_a[0].fetch("installed_version", nil))
35
- if Gem::Version.new(version) < Gem::Version.new(NEW_PG_STAT_STATEMENTS)
36
- query_name = "#{query_name}_legacy".to_sym
37
- elsif Gem::Version.new(version) >= Gem::Version.new(PG_STAT_STATEMENTS_17)
38
- query_name = "#{query_name}_17".to_sym
39
- end
40
- end
41
- end
42
-
43
- sql = if (custom_args = DEFAULT_ARGS[query_name].merge(args)) != {}
44
- RubyPgExtras.sql_for(query_name: query_name) % custom_args
45
- else
46
- RubyPgExtras.sql_for(query_name: query_name)
47
- end
48
-
49
- result = connection.execute(sql)
50
-
51
- RubyPgExtras.display_result(
52
- result,
53
- title: RubyPgExtras.description_for(query_name: query_name),
31
+ RubyPgExtras.run_query_base(
32
+ query_name: query_name,
33
+ conn: connection,
34
+ exec_method: :execute,
54
35
  in_format: in_format,
36
+ args: args,
55
37
  )
56
38
  end
57
39
 
@@ -150,6 +132,16 @@ module RailsPgExtras
150
132
  end
151
133
  end
152
134
 
135
+ def self.missing_fk_indexes(args: {}, in_format: :display_table)
136
+ result = RailsPgExtras::MissingFkIndexes.call(args[:table_name])
137
+ RubyPgExtras.display_result(result, title: "Missing foreign key indexes", in_format: in_format)
138
+ end
139
+
140
+ def self.missing_fk_constraints(args: {}, in_format: :display_table)
141
+ result = RailsPgExtras::MissingFkConstraints.call(args[:table_name])
142
+ RubyPgExtras.display_result(result, title: "Missing foreign key constraints", in_format: in_format)
143
+ end
144
+
153
145
  def self.connection
154
146
  if (db_url = ENV["RAILS_PG_EXTRAS_DATABASE_URL"])
155
147
  connector = ActiveRecord::Base.establish_connection(db_url)
@@ -4,7 +4,7 @@ require "rails_pg_extras/web"
4
4
 
5
5
  module RailsPgExtras
6
6
  class Configuration
7
- DEFAULT_CONFIG = { enabled_web_actions: Web::ACTIONS - [:kill_all], public_dashboard: ENV["RAILS_PG_EXTRAS_PUBLIC_DASHBOARD"] == "true" }
7
+ DEFAULT_CONFIG = { enabled_web_actions: Web::ACTIONS - [:kill_all, :kill_pid], public_dashboard: ENV["RAILS_PG_EXTRAS_PUBLIC_DASHBOARD"] == "true" }
8
8
 
9
9
  attr_reader :enabled_web_actions
10
10
  attr_accessor :public_dashboard
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsPgExtras
4
+ class MissingFkConstraints < RubyPgExtras::MissingFkConstraints
5
+ private
6
+
7
+ def query_module
8
+ RailsPgExtras
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsPgExtras
4
+ class MissingFkIndexes < RubyPgExtras::MissingFkIndexes
5
+ private
6
+
7
+ def query_module
8
+ RailsPgExtras
9
+ end
10
+ end
11
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsPgExtras
4
- VERSION = "5.5.1"
4
+ VERSION = "5.6.1"
5
5
  end
@@ -2,7 +2,7 @@ require "rails_pg_extras/web/engine"
2
2
 
3
3
  module RailsPgExtras
4
4
  module Web
5
- ACTIONS = %i[kill_all pg_stat_statements_reset add_extensions].freeze
5
+ ACTIONS = %i[kill_all pg_stat_statements_reset add_extensions kill_pid].freeze
6
6
 
7
7
  def self.action_enabled?(action_name)
8
8
  RailsPgExtras.configuration.enabled_web_actions.include?(action_name.to_sym)
data/spec/smoke_spec.rb CHANGED
@@ -4,7 +4,13 @@ require "spec_helper"
4
4
  require "rails-pg-extras"
5
5
 
6
6
  describe RailsPgExtras do
7
- RailsPgExtras::QUERIES.each do |query_name|
7
+ SKIP_QUERIES = %i[
8
+ kill_all
9
+ table_schema
10
+ table_foreign_keys
11
+ ]
12
+
13
+ RailsPgExtras::QUERIES.reject { |q| SKIP_QUERIES.include?(q) }.each do |query_name|
8
14
  it "#{query_name} query can be executed" do
9
15
  expect do
10
16
  RailsPgExtras.run_query(
@@ -31,7 +37,7 @@ describe RailsPgExtras do
31
37
 
32
38
  it "collecting queries data works" do
33
39
  output = RailsPgExtras.measure_queries { RailsPgExtras.diagnose(in_format: :hash) }
34
- expect(output.fetch(:count)).to eq 10
40
+ expect(output.fetch(:count) > 0).to eq(true)
35
41
  end
36
42
 
37
43
  it "supports custom RAILS_PG_EXTRAS_DATABASE_URL" do
@@ -44,4 +50,20 @@ describe RailsPgExtras do
44
50
 
45
51
  ENV["RAILS_PG_EXTRAS_DATABASE_URL"] = nil
46
52
  end
53
+
54
+ describe "missing_fk_indexes" do
55
+ it "works" do
56
+ expect {
57
+ RailsPgExtras.missing_fk_indexes
58
+ }.not_to raise_error
59
+ end
60
+ end
61
+
62
+ describe "missing_fk_constraints" do
63
+ it "works" do
64
+ expect {
65
+ RailsPgExtras.missing_fk_constraints
66
+ }.not_to raise_error
67
+ end
68
+ end
47
69
  end
data/spec/spec_helper.rb CHANGED
@@ -7,21 +7,16 @@ require_relative "../lib/rails-pg-extras"
7
7
 
8
8
  pg_version = ENV["PG_VERSION"]
9
9
 
10
- port = if pg_version == "12"
11
- "5432"
12
- elsif pg_version == "13"
13
- "5433"
14
- elsif pg_version == "14"
15
- "5434"
16
- elsif pg_version == "15"
17
- "5435"
18
- elsif pg_version == "16"
19
- "5436"
20
- elsif pg_version == "17"
21
- "5437"
22
- else
23
- "5432"
24
- end
10
+ PG_PORTS = {
11
+ "12" => "5432",
12
+ "13" => "5433",
13
+ "14" => "5434",
14
+ "15" => "5435",
15
+ "16" => "5436",
16
+ "17" => "5437",
17
+ }
18
+
19
+ port = PG_PORTS.fetch(pg_version, "5432")
25
20
 
26
21
  ENV["DATABASE_URL"] ||= "postgresql://postgres:secret@localhost:#{port}/rails-pg-extras-test"
27
22
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-pg-extras
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.5.1
4
+ version: 5.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - pawurb
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-01-04 00:00:00.000000000 Z
11
+ date: 2025-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-pg-extras
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 5.5.1
19
+ version: 5.6.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 5.5.1
26
+ version: 5.6.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rails
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -116,6 +116,8 @@ files:
116
116
  - lib/rails_pg_extras/diagnose_print.rb
117
117
  - lib/rails_pg_extras/index_info.rb
118
118
  - lib/rails_pg_extras/index_info_print.rb
119
+ - lib/rails_pg_extras/missing_fk_constraints.rb
120
+ - lib/rails_pg_extras/missing_fk_indexes.rb
119
121
  - lib/rails_pg_extras/railtie.rb
120
122
  - lib/rails_pg_extras/table_info.rb
121
123
  - lib/rails_pg_extras/table_info_print.rb