ruby-pg-extras 5.6.0 → 5.6.2
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 +36 -4
- data/lib/ruby-pg-extras.rb +16 -5
- data/lib/ruby_pg_extras/detect_fk_column.rb +54 -0
- data/lib/ruby_pg_extras/diagnose_data.rb +42 -0
- data/lib/ruby_pg_extras/missing_fk_constraints.rb +17 -5
- data/lib/ruby_pg_extras/missing_fk_indexes.rb +19 -5
- data/lib/ruby_pg_extras/version.rb +1 -1
- data/spec/detect_fk_column_spec.rb +38 -0
- data/spec/diagnose_data_spec.rb +14 -0
- data/spec/spec_helper.rb +14 -1
- metadata +7 -4
- /data/spec/{missing_fk_constraints.rb → missing_fk_constraints_spec.rb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 57c2a84fde86ad8d8f2edba0c3bb0036b525df7471013341338291b1e8c1f8e9
|
|
4
|
+
data.tar.gz: bc5624774204781bd1e970f118957aea5107e555c6f5698f3d32f7dfe5f3dc8e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bbe16634243b05f414ca9eee58b30b939a3a7bed2bbadead9782aa39951bb2b4dc13e71cd5b3e38a0698b03fb330b43427a807f1b221e4beb62128e3dc2e6a62
|
|
7
|
+
data.tar.gz: 6ea5ef05e992a7f8f9dcb986b3ff983a888584bea0468711ce7e40a4c43c4485d205fbd1bb71dd50591f37e5036406829f7ae24f3ec5b5390da2e75bca7eccb7
|
data/README.md
CHANGED
|
@@ -118,27 +118,45 @@ 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 columns likely to be foreign keys (i.e. name ending in `_id`)
|
|
121
|
+
This method lists columns likely to be foreign keys (i.e. column name ending in `_id` and related table exists) which don't have an index. It's recommended to always index foreign key columns because they are used for searching relation objects.
|
|
122
122
|
|
|
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
|
|
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
|
|
|
125
125
|
```ruby
|
|
126
126
|
RubyPgExtras.missing_fk_indexes(args: { table_name: "users" })
|
|
127
127
|
|
|
128
|
+
+---------------------------------+
|
|
129
|
+
| Missing foreign key indexes |
|
|
130
|
+
+-------------------+-------------+
|
|
131
|
+
| table | column_name |
|
|
132
|
+
+-------------------+-------------+
|
|
133
|
+
| feedbacks | team_id |
|
|
134
|
+
| votes | user_id |
|
|
135
|
+
+-------------------+-------------+
|
|
136
|
+
|
|
128
137
|
```
|
|
129
138
|
|
|
130
139
|
`table_name` argument is optional, if omitted, the method will display missing fk indexes for all the tables.
|
|
131
140
|
|
|
132
141
|
## `missing_fk_constraints`
|
|
133
142
|
|
|
134
|
-
Similarly to the previous method, this one shows columns likely to be foreign keys
|
|
143
|
+
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).
|
|
135
144
|
|
|
136
145
|
```ruby
|
|
137
146
|
RubyPgExtras.missing_fk_constraints(args: { table_name: "users" })
|
|
138
147
|
|
|
148
|
+
+---------------------------------+
|
|
149
|
+
| Missing foreign key constraints |
|
|
150
|
+
+-------------------+-------------+
|
|
151
|
+
| table | column_name |
|
|
152
|
+
+-------------------+-------------+
|
|
153
|
+
| feedbacks | team_id |
|
|
154
|
+
| votes | user_id |
|
|
155
|
+
+-------------------+-------------+
|
|
156
|
+
|
|
139
157
|
```
|
|
140
158
|
|
|
141
|
-
`table_name` argument is optional, if omitted, method will display missing
|
|
159
|
+
`table_name` argument is optional, if omitted, method will display missing fk constraints for all the tables.
|
|
142
160
|
|
|
143
161
|
### `table_info`
|
|
144
162
|
|
|
@@ -160,6 +178,14 @@ This method displays structure of a selected table, listing its column names, to
|
|
|
160
178
|
```ruby
|
|
161
179
|
RubyPgExtras.table_schema(args: { table_name: "users" })
|
|
162
180
|
|
|
181
|
+
+-----------------------------+-----------------------------+-------------+-----------------------------------+
|
|
182
|
+
| column_name | data_type | is_nullable | column_default |
|
|
183
|
+
+-----------------------------+-----------------------------+-------------+-----------------------------------+
|
|
184
|
+
| id | bigint | NO | nextval('users_id_seq'::regclass) |
|
|
185
|
+
| team_id | integer | NO | |
|
|
186
|
+
| slack_id | character varying | NO | |
|
|
187
|
+
| pseudonym | character varying | YES | |
|
|
188
|
+
|
|
163
189
|
```
|
|
164
190
|
|
|
165
191
|
### `table_foreign_keys`
|
|
@@ -169,6 +195,12 @@ This method displays foreign key constraints for a selected table. It lists fore
|
|
|
169
195
|
```ruby
|
|
170
196
|
RubyPgExtras.table_foreign_keys(args: { table_name: "users" })
|
|
171
197
|
|
|
198
|
+
+------------+---------------------+-------------+--------------------+---------------------+
|
|
199
|
+
| table_name | constraint_name | column_name | foreign_table_name | foreign_column_name |
|
|
200
|
+
+------------+---------------------+-------------+--------------------+---------------------+
|
|
201
|
+
| users | fk_rails_b2bbf87303 | team_id | teams | id |
|
|
202
|
+
+------------+---------------------+-------------+--------------------+---------------------+
|
|
203
|
+
|
|
172
204
|
```
|
|
173
205
|
|
|
174
206
|
### `index_info`
|
data/lib/ruby-pg-extras.rb
CHANGED
|
@@ -6,6 +6,7 @@ require "pg"
|
|
|
6
6
|
require "ruby_pg_extras/size_parser"
|
|
7
7
|
require "ruby_pg_extras/diagnose_data"
|
|
8
8
|
require "ruby_pg_extras/diagnose_print"
|
|
9
|
+
require "ruby_pg_extras/detect_fk_column"
|
|
9
10
|
require "ruby_pg_extras/missing_fk_indexes"
|
|
10
11
|
require "ruby_pg_extras/missing_fk_constraints"
|
|
11
12
|
require "ruby_pg_extras/index_info"
|
|
@@ -74,9 +75,9 @@ module RubyPgExtras
|
|
|
74
75
|
end
|
|
75
76
|
end
|
|
76
77
|
|
|
77
|
-
def self.
|
|
78
|
+
def self.run_query_base(query_name:, conn:, exec_method:, in_format:, args: {})
|
|
78
79
|
if %i(calls outliers).include?(query_name)
|
|
79
|
-
pg_stat_statements_ver =
|
|
80
|
+
pg_stat_statements_ver = conn.send(exec_method, "select installed_version from pg_available_extensions where name='pg_stat_statements'")
|
|
80
81
|
.to_a[0].fetch("installed_version", nil)
|
|
81
82
|
if pg_stat_statements_ver != nil
|
|
82
83
|
if Gem::Version.new(pg_stat_statements_ver) < Gem::Version.new(NEW_PG_STAT_STATEMENTS)
|
|
@@ -98,7 +99,7 @@ module RubyPgExtras
|
|
|
98
99
|
else
|
|
99
100
|
sql_for(query_name: query_name)
|
|
100
101
|
end
|
|
101
|
-
result =
|
|
102
|
+
result = conn.send(exec_method, sql)
|
|
102
103
|
|
|
103
104
|
display_result(
|
|
104
105
|
result,
|
|
@@ -107,6 +108,16 @@ module RubyPgExtras
|
|
|
107
108
|
)
|
|
108
109
|
end
|
|
109
110
|
|
|
111
|
+
def self.run_query(query_name:, in_format:, args: {})
|
|
112
|
+
run_query_base(
|
|
113
|
+
query_name: query_name,
|
|
114
|
+
conn: connection,
|
|
115
|
+
exec_method: :exec,
|
|
116
|
+
in_format: in_format,
|
|
117
|
+
args: args,
|
|
118
|
+
)
|
|
119
|
+
end
|
|
120
|
+
|
|
110
121
|
def self.diagnose(in_format: :display_table)
|
|
111
122
|
data = RubyPgExtras::DiagnoseData.call
|
|
112
123
|
|
|
@@ -154,7 +165,7 @@ module RubyPgExtras
|
|
|
154
165
|
end
|
|
155
166
|
|
|
156
167
|
def self.missing_fk_constraints(args: {}, in_format: :display_table)
|
|
157
|
-
RubyPgExtras::
|
|
168
|
+
RubyPgExtras::MissingFkConstraints.call(args[:table_name])
|
|
158
169
|
end
|
|
159
170
|
|
|
160
171
|
def self.display_result(result, title:, in_format:)
|
|
@@ -175,7 +186,7 @@ module RubyPgExtras
|
|
|
175
186
|
puts Terminal::Table.new(
|
|
176
187
|
title: title,
|
|
177
188
|
headings: headings,
|
|
178
|
-
rows: result.values,
|
|
189
|
+
rows: (result.try(:values) || result.map(&:values)),
|
|
179
190
|
)
|
|
180
191
|
else
|
|
181
192
|
raise "Invalid in_format option"
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyPgExtras
|
|
4
|
+
class DetectFkColumn
|
|
5
|
+
PLURAL_RULES = [
|
|
6
|
+
[/s$/i, "s"],
|
|
7
|
+
[/^(ax|test)is$/i, '\1es'],
|
|
8
|
+
[/(octop|vir)us$/i, '\1i'],
|
|
9
|
+
[/(alias|status)$/i, '\1es'],
|
|
10
|
+
[/(bu)s$/i, '\1ses'],
|
|
11
|
+
[/(buffal|tomat)o$/i, '\1oes'],
|
|
12
|
+
[/([ti])um$/i, '\1a'],
|
|
13
|
+
[/sis$/i, "ses"],
|
|
14
|
+
[/(?:([^f])fe|([lr])f)$/i, '\1\2ves'],
|
|
15
|
+
[/([^aeiouy]|qu)y$/i, '\1ies'],
|
|
16
|
+
[/(x|ch|ss|sh)$/i, '\1es'],
|
|
17
|
+
[/(matr|vert|ind)(?:ix|ex)$/i, '\1ices'],
|
|
18
|
+
[/^(m|l)ouse$/i, '\1ice'],
|
|
19
|
+
[/^(ox)$/i, '\1en'],
|
|
20
|
+
[/(quiz)$/i, '\1zes'],
|
|
21
|
+
]
|
|
22
|
+
IRREGULAR = {
|
|
23
|
+
"person" => "people",
|
|
24
|
+
"man" => "men",
|
|
25
|
+
"child" => "children",
|
|
26
|
+
"sex" => "sexes",
|
|
27
|
+
"move" => "moves",
|
|
28
|
+
"zombie" => "zombies",
|
|
29
|
+
}
|
|
30
|
+
UNCOUNTABLE = %w(equipment information rice money species series fish sheep jeans police)
|
|
31
|
+
|
|
32
|
+
def self.call(column_name, tables)
|
|
33
|
+
new.call(column_name, tables)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def call(column_name, tables)
|
|
37
|
+
return false unless column_name =~ /_id$/
|
|
38
|
+
table_name = column_name.split("_").first
|
|
39
|
+
table_name = pluralize(table_name)
|
|
40
|
+
tables.include?(table_name)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def pluralize(word)
|
|
44
|
+
return word if UNCOUNTABLE.include?(word.downcase)
|
|
45
|
+
return IRREGULAR[word] if IRREGULAR.key?(word)
|
|
46
|
+
return IRREGULAR.invert[word] if IRREGULAR.value?(word)
|
|
47
|
+
|
|
48
|
+
PLURAL_RULES.reverse.each do |(rule, replacement)|
|
|
49
|
+
return word.gsub(rule, replacement) if word.match?(rule)
|
|
50
|
+
end
|
|
51
|
+
word + "s"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -23,6 +23,8 @@ module RubyPgExtras
|
|
|
23
23
|
:null_indexes,
|
|
24
24
|
:bloat,
|
|
25
25
|
:duplicate_indexes,
|
|
26
|
+
:missing_fk_indexes,
|
|
27
|
+
:missing_fk_constraints,
|
|
26
28
|
].yield_self do |checks|
|
|
27
29
|
extensions_data = query_module.extensions(in_format: :hash)
|
|
28
30
|
|
|
@@ -55,6 +57,46 @@ module RubyPgExtras
|
|
|
55
57
|
RubyPgExtras
|
|
56
58
|
end
|
|
57
59
|
|
|
60
|
+
def missing_fk_indexes
|
|
61
|
+
missing = query_module.missing_fk_indexes(in_format: :hash)
|
|
62
|
+
|
|
63
|
+
if missing.count == 0
|
|
64
|
+
return {
|
|
65
|
+
ok: true,
|
|
66
|
+
message: "No missing foreign key indexes detected.",
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
missing_text = missing.map do |el|
|
|
71
|
+
"#{el.fetch(:table)}.#{el.fetch(:column_name)}"
|
|
72
|
+
end.join(",\n")
|
|
73
|
+
|
|
74
|
+
{
|
|
75
|
+
ok: false,
|
|
76
|
+
message: "Missing foreign key indexes detected: #{missing_text}.",
|
|
77
|
+
}
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def missing_fk_constraints
|
|
81
|
+
missing = query_module.missing_fk_constraints(in_format: :hash)
|
|
82
|
+
|
|
83
|
+
if missing.count == 0
|
|
84
|
+
return {
|
|
85
|
+
ok: true,
|
|
86
|
+
message: "No missing foreign key constraints detected.",
|
|
87
|
+
}
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
missing_text = missing.map do |el|
|
|
91
|
+
"#{el.fetch(:table)}.#{el.fetch(:column_name)}"
|
|
92
|
+
end.join(",\n")
|
|
93
|
+
|
|
94
|
+
{
|
|
95
|
+
ok: false,
|
|
96
|
+
message: "Missing foreign key constraints detected: #{missing_text}.",
|
|
97
|
+
}
|
|
98
|
+
end
|
|
99
|
+
|
|
58
100
|
def table_cache_hit
|
|
59
101
|
min_expected = ENV.fetch(
|
|
60
102
|
"PG_EXTRAS_TABLE_CACHE_HIT_MIN_EXPECTED",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module RubyPgExtras
|
|
4
|
-
class
|
|
4
|
+
class MissingFkConstraints
|
|
5
5
|
def self.call(table_name)
|
|
6
6
|
new.call(table_name)
|
|
7
7
|
end
|
|
@@ -10,15 +10,17 @@ module RubyPgExtras
|
|
|
10
10
|
tables = if table_name
|
|
11
11
|
[table_name]
|
|
12
12
|
else
|
|
13
|
-
|
|
13
|
+
all_tables
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
tables.reduce([]) do |agg, table|
|
|
17
|
-
foreign_keys_info =
|
|
18
|
-
schema =
|
|
17
|
+
foreign_keys_info = query_module.table_foreign_keys(args: { table_name: table }, in_format: :hash)
|
|
18
|
+
schema = query_module.table_schema(args: { table_name: table }, in_format: :hash)
|
|
19
19
|
|
|
20
20
|
fk_columns = schema.filter_map do |row|
|
|
21
|
-
|
|
21
|
+
if DetectFkColumn.call(row.fetch("column_name"), all_tables)
|
|
22
|
+
row.fetch("column_name")
|
|
23
|
+
end
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
fk_columns.each do |column_name|
|
|
@@ -35,5 +37,15 @@ module RubyPgExtras
|
|
|
35
37
|
agg
|
|
36
38
|
end
|
|
37
39
|
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def all_tables
|
|
44
|
+
@_all_tables ||= query_module.table_size(in_format: :hash).map { |row| row.fetch("name") }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def query_module
|
|
48
|
+
RubyPgExtras
|
|
49
|
+
end
|
|
38
50
|
end
|
|
39
51
|
end
|
|
@@ -10,19 +10,23 @@ module RubyPgExtras
|
|
|
10
10
|
tables = if table_name
|
|
11
11
|
[table_name]
|
|
12
12
|
else
|
|
13
|
-
|
|
13
|
+
all_tables
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
indexes_info = query_module.indexes(in_format: :hash)
|
|
17
|
+
|
|
16
18
|
tables.reduce([]) do |agg, table|
|
|
17
|
-
index_info =
|
|
18
|
-
schema =
|
|
19
|
+
index_info = indexes_info.select { |row| row.fetch("tablename") == table }
|
|
20
|
+
schema = query_module.table_schema(args: { table_name: table }, in_format: :hash)
|
|
19
21
|
|
|
20
22
|
fk_columns = schema.filter_map do |row|
|
|
21
|
-
|
|
23
|
+
if DetectFkColumn.call(row.fetch("column_name"), all_tables)
|
|
24
|
+
row.fetch("column_name")
|
|
25
|
+
end
|
|
22
26
|
end
|
|
23
27
|
|
|
24
28
|
fk_columns.each do |column_name|
|
|
25
|
-
if index_info.none? { |row| row.fetch(
|
|
29
|
+
if index_info.none? { |row| row.fetch("columns").split(",").first == column_name }
|
|
26
30
|
agg.push(
|
|
27
31
|
{
|
|
28
32
|
table: table,
|
|
@@ -35,5 +39,15 @@ module RubyPgExtras
|
|
|
35
39
|
agg
|
|
36
40
|
end
|
|
37
41
|
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def all_tables
|
|
46
|
+
@_all_tables ||= query_module.table_size(in_format: :hash).map { |row| row.fetch("name") }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def query_module
|
|
50
|
+
RubyPgExtras
|
|
51
|
+
end
|
|
38
52
|
end
|
|
39
53
|
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
describe RubyPgExtras::DetectFkColumn do
|
|
6
|
+
subject(:result) do
|
|
7
|
+
RubyPgExtras::DetectFkColumn.call(column_name, tables)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe "call" do
|
|
11
|
+
context "no matching table" do
|
|
12
|
+
let(:column_name) { "company_id" }
|
|
13
|
+
let(:tables) { ["users", "posts"] }
|
|
14
|
+
|
|
15
|
+
it "returns false" do
|
|
16
|
+
expect(result).to eq(false)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context "matching table" do
|
|
21
|
+
let(:column_name) { "user_id" }
|
|
22
|
+
let(:tables) { ["users", "posts"] }
|
|
23
|
+
|
|
24
|
+
it "returns true" do
|
|
25
|
+
expect(result).to eq(true)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context "matching table" do
|
|
30
|
+
let(:column_name) { "octopus_id" }
|
|
31
|
+
let(:tables) { ["users", "octopi"] }
|
|
32
|
+
|
|
33
|
+
it "returns true" do
|
|
34
|
+
expect(result).to eq(true)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/spec/diagnose_data_spec.rb
CHANGED
|
@@ -45,6 +45,20 @@ describe RubyPgExtras::DiagnoseData do
|
|
|
45
45
|
{ "query" => "SELECT * FROM users WHERE users.age > 20 AND users.height > 160", "exec_time" => "154:39:26.431466", "prop_exec_time" => "72.2%", "ncalls" => "34,211,877", "sync_io_time" => "00:34:19.784318" },
|
|
46
46
|
]
|
|
47
47
|
}
|
|
48
|
+
|
|
49
|
+
expect(RubyPgExtras).to receive(:missing_fk_constraints) {
|
|
50
|
+
[
|
|
51
|
+
{ table: "users", column_name: "company_id" },
|
|
52
|
+
{ table: "posts", column_name: "topic_id" },
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
expect(RubyPgExtras).to receive(:missing_fk_indexes) {
|
|
57
|
+
[
|
|
58
|
+
{ table: "users", column_name: "company_id" },
|
|
59
|
+
{ table: "posts", column_name: "topic_id" },
|
|
60
|
+
]
|
|
61
|
+
}
|
|
48
62
|
end
|
|
49
63
|
|
|
50
64
|
it "works" do
|
data/spec/spec_helper.rb
CHANGED
|
@@ -24,6 +24,8 @@ RSpec.configure do |config|
|
|
|
24
24
|
DB_SCHEMA = <<-SQL
|
|
25
25
|
DROP TABLE IF EXISTS posts;
|
|
26
26
|
DROP TABLE IF EXISTS users;
|
|
27
|
+
DROP TABLE IF EXISTS topics;
|
|
28
|
+
DROP TABLE IF EXISTS companies;
|
|
27
29
|
|
|
28
30
|
CREATE TABLE users (
|
|
29
31
|
id SERIAL PRIMARY KEY,
|
|
@@ -35,11 +37,22 @@ CREATE TABLE posts (
|
|
|
35
37
|
id SERIAL PRIMARY KEY,
|
|
36
38
|
user_id INTEGER NOT NULL,
|
|
37
39
|
topic_id INTEGER,
|
|
40
|
+
external_id INTEGER,
|
|
38
41
|
title VARCHAR(255),
|
|
39
42
|
CONSTRAINT fk_posts_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
40
43
|
);
|
|
41
44
|
|
|
42
|
-
CREATE
|
|
45
|
+
CREATE TABLE topics (
|
|
46
|
+
id SERIAL PRIMARY KEY,
|
|
47
|
+
title VARCHAR(255)
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
CREATE TABLE companies (
|
|
51
|
+
id SERIAL PRIMARY KEY,
|
|
52
|
+
name VARCHAR(255)
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
CREATE INDEX index_posts_on_user_id ON posts(user_id, topic_id);
|
|
43
56
|
SQL
|
|
44
57
|
|
|
45
58
|
RubyPgExtras.connection.exec(DB_SCHEMA)
|
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.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- pawurb
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-02-
|
|
11
|
+
date: 2025-02-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: pg
|
|
@@ -111,6 +111,7 @@ files:
|
|
|
111
111
|
- Rakefile
|
|
112
112
|
- docker-compose.yml.sample
|
|
113
113
|
- lib/ruby-pg-extras.rb
|
|
114
|
+
- lib/ruby_pg_extras/detect_fk_column.rb
|
|
114
115
|
- lib/ruby_pg_extras/diagnose_data.rb
|
|
115
116
|
- lib/ruby_pg_extras/diagnose_print.rb
|
|
116
117
|
- lib/ruby_pg_extras/index_info.rb
|
|
@@ -166,10 +167,11 @@ files:
|
|
|
166
167
|
- lib/ruby_pg_extras/version.rb
|
|
167
168
|
- ruby-pg-extras-diagnose.png
|
|
168
169
|
- ruby-pg-extras.gemspec
|
|
170
|
+
- spec/detect_fk_column_spec.rb
|
|
169
171
|
- spec/diagnose_data_spec.rb
|
|
170
172
|
- spec/diagnose_print_spec.rb
|
|
171
173
|
- spec/index_info_spec.rb
|
|
172
|
-
- spec/
|
|
174
|
+
- spec/missing_fk_constraints_spec.rb
|
|
173
175
|
- spec/missing_fk_indexes_spec.rb
|
|
174
176
|
- spec/size_parser_spec.rb
|
|
175
177
|
- spec/smoke_spec.rb
|
|
@@ -200,10 +202,11 @@ signing_key:
|
|
|
200
202
|
specification_version: 4
|
|
201
203
|
summary: Ruby PostgreSQL performance database insights
|
|
202
204
|
test_files:
|
|
205
|
+
- spec/detect_fk_column_spec.rb
|
|
203
206
|
- spec/diagnose_data_spec.rb
|
|
204
207
|
- spec/diagnose_print_spec.rb
|
|
205
208
|
- spec/index_info_spec.rb
|
|
206
|
-
- spec/
|
|
209
|
+
- spec/missing_fk_constraints_spec.rb
|
|
207
210
|
- spec/missing_fk_indexes_spec.rb
|
|
208
211
|
- spec/size_parser_spec.rb
|
|
209
212
|
- spec/smoke_spec.rb
|
|
File without changes
|