ruby-pg-extras 5.6.15 → 5.6.16
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.
- checksums.yaml +4 -4
- data/README.md +23 -3
- data/docker-compose.yml.sample +10 -1
- data/lib/ruby-pg-extras.rb +1 -1
- data/lib/ruby_pg_extras/missing_fk_indexes.rb +13 -3
- data/lib/ruby_pg_extras/version.rb +1 -1
- data/spec/missing_fk_indexes_spec.rb +22 -0
- data/spec/spec_helper.rb +2 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 789f323a6bba1cdf366a6eb53b5102a4a0f3d43ebafb1ea2f3151451bb28bffa
|
|
4
|
+
data.tar.gz: 4faaa79f35aa2c32c1b7c9d7def43b9319d43bb67a3933458bec3badceb672b6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8fe626803b4d7eb880f45571998dac5fd95d0430967c8f111d56ca72891732bc957db2276579bab6063087a8241c13ac2daa28e4059bcb4ac1c6688e6e5af478
|
|
7
|
+
data.tar.gz: b849cd97547e4b394dc4fb6a6e0af538e8dc8c51d85653af165b944c341d0e9cf98ecb0df7607a807145a5befb67cf097f7275dde9de9303d694cb28e6e59b99
|
data/README.md
CHANGED
|
@@ -118,7 +118,7 @@ Keep reading to learn about methods that `diagnose` uses under the hood.
|
|
|
118
118
|
|
|
119
119
|
### `missing_fk_indexes`
|
|
120
120
|
|
|
121
|
-
This method lists
|
|
121
|
+
This method lists **actual foreign key columns** (based on existing foreign key constraints) which don't have a supporting index. It's recommended to always index foreign key columns because they are commonly used for lookups and join conditions.
|
|
122
122
|
|
|
123
123
|
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.
|
|
124
124
|
|
|
@@ -136,14 +136,34 @@ RubyPgExtras.missing_fk_indexes(args: { table_name: "users" })
|
|
|
136
136
|
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
+
You can also exclude known/intentional cases using `ignore_list` (array or comma-separated string), with entries like:
|
|
140
|
+
- `"posts.topic_id"` (ignore a specific table+column)
|
|
141
|
+
- `"topic_id"` (ignore this column name for all tables)
|
|
142
|
+
- `"posts.*"` (ignore all columns on a table)
|
|
143
|
+
- `"*"` (ignore everything)
|
|
144
|
+
|
|
145
|
+
```ruby
|
|
146
|
+
RubyPgExtras.missing_fk_indexes(args: { ignore_list: ["users.company_id", "posts.*"] })
|
|
147
|
+
```
|
|
148
|
+
|
|
139
149
|
`table_name` argument is optional, if omitted, the method will display missing fk indexes for all the tables.
|
|
140
150
|
|
|
141
151
|
## `missing_fk_constraints`
|
|
142
152
|
|
|
143
|
-
|
|
153
|
+
This method shows **columns that look like foreign keys** but don't have a corresponding foreign key constraint yet. 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).
|
|
154
|
+
|
|
155
|
+
Heuristic notes:
|
|
156
|
+
- A column is considered a candidate if it matches `<table_singular>_id` and the related table exists (underscored prefixes like `account_user_id` are supported).
|
|
157
|
+
- Rails polymorphic associations (`<name>_id` + `<name>_type`) are ignored since they cannot be expressed as real FK constraints.
|
|
158
|
+
|
|
159
|
+
You can also exclude known/intentional cases using `ignore_list` (array or comma-separated string), with entries like:
|
|
160
|
+
- `"posts.category_id"` (ignore a specific table+column)
|
|
161
|
+
- `"category_id"` (ignore this column name for all tables)
|
|
162
|
+
- `"posts.*"` (ignore all columns on a table)
|
|
163
|
+
- `"*"` (ignore everything)
|
|
144
164
|
|
|
145
165
|
```ruby
|
|
146
|
-
RubyPgExtras.missing_fk_constraints(args: { table_name: "users" })
|
|
166
|
+
RubyPgExtras.missing_fk_constraints(args: { table_name: "users", ignore_list: ["users.customer_id", "posts.*"] })
|
|
147
167
|
|
|
148
168
|
+---------------------------------+
|
|
149
169
|
| Missing foreign key constraints |
|
data/docker-compose.yml.sample
CHANGED
|
@@ -36,7 +36,7 @@ services:
|
|
|
36
36
|
ports:
|
|
37
37
|
- '5436:5432'
|
|
38
38
|
postgres17:
|
|
39
|
-
image: postgres:17.
|
|
39
|
+
image: postgres:17.7-alpine
|
|
40
40
|
command: postgres -c shared_preload_libraries=pg_stat_statements
|
|
41
41
|
environment:
|
|
42
42
|
POSTGRES_USER: postgres
|
|
@@ -44,4 +44,13 @@ services:
|
|
|
44
44
|
POSTGRES_PASSWORD: secret
|
|
45
45
|
ports:
|
|
46
46
|
- '5437:5432'
|
|
47
|
+
postgres18:
|
|
48
|
+
image: postgres:18.1-alpine
|
|
49
|
+
command: postgres -c shared_preload_libraries=pg_stat_statements
|
|
50
|
+
environment:
|
|
51
|
+
POSTGRES_USER: postgres
|
|
52
|
+
POSTGRES_DB: ruby-pg-extras-test
|
|
53
|
+
POSTGRES_PASSWORD: secret
|
|
54
|
+
ports:
|
|
55
|
+
- '5438:5432'
|
|
47
56
|
|
data/lib/ruby-pg-extras.rb
CHANGED
|
@@ -192,7 +192,7 @@ module RubyPgExtras
|
|
|
192
192
|
end
|
|
193
193
|
|
|
194
194
|
def self.missing_fk_indexes(args: {}, in_format: :display_table)
|
|
195
|
-
RubyPgExtras::MissingFkIndexes.call(args[:table_name])
|
|
195
|
+
RubyPgExtras::MissingFkIndexes.call(args[:table_name], ignore_list: args[:ignore_list])
|
|
196
196
|
end
|
|
197
197
|
|
|
198
198
|
def self.missing_fk_constraints(args: {}, in_format: :display_table)
|
|
@@ -2,11 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
module RubyPgExtras
|
|
4
4
|
class MissingFkIndexes
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
# ignore_list: array (or comma-separated string) of entries like:
|
|
6
|
+
# - "posts.topic_id" (ignore a specific table+column)
|
|
7
|
+
# - "topic_id" (ignore this column name for all tables)
|
|
8
|
+
# - "posts.*" (ignore all columns on a table)
|
|
9
|
+
# - "*" (ignore everything)
|
|
10
|
+
def self.call(table_name, ignore_list: nil)
|
|
11
|
+
new.call(table_name, ignore_list: ignore_list)
|
|
7
12
|
end
|
|
8
13
|
|
|
9
|
-
def call(table_name)
|
|
14
|
+
def call(table_name, ignore_list: nil)
|
|
15
|
+
ignore_list_matcher = IgnoreList.new(ignore_list)
|
|
16
|
+
|
|
10
17
|
indexes_info = query_module.indexes(in_format: :hash)
|
|
11
18
|
foreign_keys = query_module.foreign_keys(in_format: :hash)
|
|
12
19
|
|
|
@@ -23,6 +30,9 @@ module RubyPgExtras
|
|
|
23
30
|
table_fks.each do |fk|
|
|
24
31
|
column_name = fk.fetch("column_name")
|
|
25
32
|
|
|
33
|
+
# Skip columns explicitly excluded via ignore list.
|
|
34
|
+
next if ignore_list_matcher.ignored?(table: table, column_name: column_name)
|
|
35
|
+
|
|
26
36
|
if index_info.none? { |row| row.fetch("columns").split(",").first == column_name }
|
|
27
37
|
agg.push(
|
|
28
38
|
{
|
|
@@ -18,4 +18,26 @@ describe "missing_fk_indexes" do
|
|
|
18
18
|
{ table: "posts", column_name: "topic_id" },
|
|
19
19
|
])
|
|
20
20
|
end
|
|
21
|
+
|
|
22
|
+
it "supports ignoring a specific table+column via args" do
|
|
23
|
+
result = RubyPgExtras.missing_fk_indexes(
|
|
24
|
+
args: { ignore_list: ["posts.topic_id"] },
|
|
25
|
+
in_format: :hash
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
expect(result).to eq([
|
|
29
|
+
{ table: "users", column_name: "company_id" },
|
|
30
|
+
])
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "supports ignoring a column name globally via args" do
|
|
34
|
+
result = RubyPgExtras.missing_fk_indexes(
|
|
35
|
+
args: { ignore_list: ["company_id"] },
|
|
36
|
+
in_format: :hash
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
expect(result).to eq([
|
|
40
|
+
{ table: "posts", column_name: "topic_id" },
|
|
41
|
+
])
|
|
42
|
+
end
|
|
21
43
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -12,9 +12,10 @@ PG_PORTS = {
|
|
|
12
12
|
"15" => "5435",
|
|
13
13
|
"16" => "5436",
|
|
14
14
|
"17" => "5437",
|
|
15
|
+
"18" => "5438",
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
port = PG_PORTS.fetch(pg_version, "
|
|
18
|
+
port = PG_PORTS.fetch(pg_version, "5438")
|
|
18
19
|
|
|
19
20
|
ENV["DATABASE_URL"] ||= "postgresql://postgres:secret@localhost:#{port}/ruby-pg-extras-test"
|
|
20
21
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby-pg-extras
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.6.
|
|
4
|
+
version: 5.6.16
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- pawurb
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-01-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: pg
|