ruby-pg-extras 5.3.1 → 5.4.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +1 -2
- data/Gemfile +1 -1
- data/README.md +5 -1
- data/Rakefile +2 -2
- data/lib/ruby-pg-extras.rb +23 -23
- data/lib/ruby_pg_extras/diagnose_data.rb +24 -24
- data/lib/ruby_pg_extras/diagnose_print.rb +3 -3
- data/lib/ruby_pg_extras/index_info.rb +4 -4
- data/lib/ruby_pg_extras/index_info_print.rb +5 -5
- data/lib/ruby_pg_extras/queries/all_locks.sql +2 -0
- data/lib/ruby_pg_extras/queries/locks.sql +2 -0
- data/lib/ruby_pg_extras/size_parser.rb +2 -2
- data/lib/ruby_pg_extras/table_info.rb +1 -1
- data/lib/ruby_pg_extras/table_info_print.rb +4 -4
- data/lib/ruby_pg_extras/version.rb +1 -1
- data/ruby-pg-extras.gemspec +13 -12
- data/spec/diagnose_data_spec.rb +6 -6
- data/spec/diagnose_print_spec.rb +5 -5
- data/spec/index_info_spec.rb +6 -6
- data/spec/size_parser_spec.rb +12 -12
- data/spec/smoke_spec.rb +3 -3
- data/spec/spec_helper.rb +13 -13
- data/spec/table_info_spec.rb +3 -3
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ddb04fe6f72f45595c16a533c58ef34fc59dc551ab78e131f0cec1ca4a56d3b
|
4
|
+
data.tar.gz: d8763349854102e5bfd2174461f7d3c43de7c74526dba14d1982c68705f59055
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b33851aaed74e98903aee07d92bf4a048300f7e99bec1e7cb541c14a7669cbdf2bd8c5d784d922f276c3c287d6cf7bb65df16a7788e2b58fdcd20ca1c3a4ec4
|
7
|
+
data.tar.gz: '085b52d651b6dbf60a5a44129416fccc8801e7be6c321fb0ac9083667902bdd7025a52a2e7dc20e6756f3062492820342f1aabbcf1bfe8be9b5c43bf0362d6a2'
|
data/.github/workflows/ci.yml
CHANGED
@@ -57,8 +57,7 @@ jobs:
|
|
57
57
|
ruby-version: ${{ matrix.ruby-version }}
|
58
58
|
- name: Setup dependencies
|
59
59
|
run: |
|
60
|
-
gem
|
61
|
-
gem install bundler
|
60
|
+
gem install bundler -v 2.4.22
|
62
61
|
sudo apt-get update --allow-releaseinfo-change
|
63
62
|
sudo apt install postgresql-client
|
64
63
|
sudo apt install libpq-dev
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -10,6 +10,8 @@ Alternative versions:
|
|
10
10
|
|
11
11
|
- [Ruby on Rails](https://github.com/pawurb/rails-pg-extras)
|
12
12
|
|
13
|
+
- [Rust](https://github.com/pawurb/rust-pg-extras)
|
14
|
+
|
13
15
|
- [NodeJS](https://github.com/pawurb/node-postgres-extras)
|
14
16
|
|
15
17
|
- [Elixir](https://github.com/pawurb/ecto_psql_extras)
|
@@ -98,6 +100,8 @@ RubyPgExtras.long_running_queries(args: { threshold: "200 milliseconds" })
|
|
98
100
|
|
99
101
|
```
|
100
102
|
|
103
|
+
You can customize the default `public` schema by setting `ENV['PG_EXTRAS_SCHEMA']` value.
|
104
|
+
|
101
105
|
## Diagnose report
|
102
106
|
|
103
107
|
The simplest way to start using pg-extras is to execute a `diagnose` method. It runs a set of checks and prints out a report highlighting areas that may require additional investigation:
|
@@ -437,7 +441,7 @@ This command displays the total size of each table and materialized view in the
|
|
437
441
|
|
438
442
|
```ruby
|
439
443
|
|
440
|
-
RubyPgExtras.unused_indexes(args: { max_scans:
|
444
|
+
RubyPgExtras.unused_indexes(args: { max_scans: 50 })
|
441
445
|
|
442
446
|
table | index | index_size | index_scans
|
443
447
|
---------------------+--------------------------------------------+------------+-------------
|
data/Rakefile
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
-
require
|
2
|
+
require "rspec/core/rake_task"
|
3
3
|
|
4
4
|
RSpec::Core::RakeTask.new(:spec)
|
5
5
|
|
6
|
-
desc
|
6
|
+
desc "Test all PG versions"
|
7
7
|
task :test_all do
|
8
8
|
system("PG_VERSION=11 bundle exec rspec spec/ && PG_VERSION=12 bundle exec rspec spec/ && PG_VERSION=13 bundle exec rspec spec/ && PG_VERSION=14 bundle exec rspec spec/")
|
9
9
|
end
|
data/lib/ruby-pg-extras.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
3
|
+
require "terminal-table"
|
4
|
+
require "uri"
|
5
|
+
require "pg"
|
6
|
+
require "ruby_pg_extras/size_parser"
|
7
|
+
require "ruby_pg_extras/diagnose_data"
|
8
|
+
require "ruby_pg_extras/diagnose_print"
|
9
|
+
require "ruby_pg_extras/index_info"
|
10
|
+
require "ruby_pg_extras/index_info_print"
|
11
|
+
require "ruby_pg_extras/table_info"
|
12
|
+
require "ruby_pg_extras/table_info_print"
|
13
13
|
|
14
14
|
module RubyPgExtras
|
15
15
|
@@database_url = nil
|
@@ -27,7 +27,7 @@ module RubyPgExtras
|
|
27
27
|
buffercache_usage ssl_used connections
|
28
28
|
)
|
29
29
|
|
30
|
-
DEFAULT_SCHEMA = ENV["PG_EXTRAS_SCHEMA"] ||
|
30
|
+
DEFAULT_SCHEMA = ENV["PG_EXTRAS_SCHEMA"] || "public"
|
31
31
|
|
32
32
|
DEFAULT_ARGS = Hash.new({}).merge({
|
33
33
|
calls: { limit: 10 },
|
@@ -50,7 +50,7 @@ module RubyPgExtras
|
|
50
50
|
table_index_scans: { schema: DEFAULT_SCHEMA },
|
51
51
|
records_rank: { schema: DEFAULT_SCHEMA },
|
52
52
|
tables: { schema: DEFAULT_SCHEMA },
|
53
|
-
kill_pid: { pid: 0 }
|
53
|
+
kill_pid: { pid: 0 },
|
54
54
|
})
|
55
55
|
|
56
56
|
QUERIES.each do |query_name|
|
@@ -58,7 +58,7 @@ module RubyPgExtras
|
|
58
58
|
run_query(
|
59
59
|
query_name: query_name,
|
60
60
|
in_format: options.fetch(:in_format, :display_table),
|
61
|
-
args: options.fetch(:args, {})
|
61
|
+
args: options.fetch(:args, {}),
|
62
62
|
)
|
63
63
|
end
|
64
64
|
end
|
@@ -75,16 +75,16 @@ module RubyPgExtras
|
|
75
75
|
end
|
76
76
|
|
77
77
|
sql = if (custom_args = DEFAULT_ARGS[query_name].merge(args)) != {}
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
78
|
+
sql_for(query_name: query_name) % custom_args
|
79
|
+
else
|
80
|
+
sql_for(query_name: query_name)
|
81
|
+
end
|
82
82
|
result = connection.exec(sql)
|
83
83
|
|
84
84
|
display_result(
|
85
85
|
result,
|
86
86
|
title: description_for(query_name: query_name),
|
87
|
-
in_format: in_format
|
87
|
+
in_format: in_format,
|
88
88
|
)
|
89
89
|
end
|
90
90
|
|
@@ -140,15 +140,15 @@ module RubyPgExtras
|
|
140
140
|
result
|
141
141
|
when :display_table
|
142
142
|
headings = if result.count > 0
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
143
|
+
result[0].keys
|
144
|
+
else
|
145
|
+
["No results"]
|
146
|
+
end
|
147
147
|
|
148
148
|
puts Terminal::Table.new(
|
149
149
|
title: title,
|
150
150
|
headings: headings,
|
151
|
-
rows: result.values
|
151
|
+
rows: result.values,
|
152
152
|
)
|
153
153
|
else
|
154
154
|
raise "Invalid in_format option"
|
@@ -22,7 +22,7 @@ module RubyPgExtras
|
|
22
22
|
:unused_indexes,
|
23
23
|
:null_indexes,
|
24
24
|
:bloat,
|
25
|
-
:duplicate_indexes
|
25
|
+
:duplicate_indexes,
|
26
26
|
].yield_self do |checks|
|
27
27
|
extensions_data = query_module.extensions(in_format: :hash)
|
28
28
|
|
@@ -66,12 +66,12 @@ module RubyPgExtras
|
|
66
66
|
if table_cache_hit_ratio > min_expected
|
67
67
|
{
|
68
68
|
ok: true,
|
69
|
-
message: "Table cache hit ratio is correct: #{table_cache_hit_ratio}."
|
69
|
+
message: "Table cache hit ratio is correct: #{table_cache_hit_ratio}.",
|
70
70
|
}
|
71
71
|
else
|
72
72
|
{
|
73
73
|
ok: false,
|
74
|
-
message: "Table hit ratio is too low: #{table_cache_hit_ratio}."
|
74
|
+
message: "Table hit ratio is too low: #{table_cache_hit_ratio}.",
|
75
75
|
}
|
76
76
|
end
|
77
77
|
end
|
@@ -87,12 +87,12 @@ module RubyPgExtras
|
|
87
87
|
if index_cache_hit_ratio > min_expected
|
88
88
|
{
|
89
89
|
ok: true,
|
90
|
-
message: "Index hit ratio is correct: #{index_cache_hit_ratio}."
|
90
|
+
message: "Index hit ratio is correct: #{index_cache_hit_ratio}.",
|
91
91
|
}
|
92
92
|
else
|
93
93
|
{
|
94
94
|
ok: false,
|
95
|
-
message: "Index hit ratio is too low: #{index_cache_hit_ratio}."
|
95
|
+
message: "Index hit ratio is too low: #{index_cache_hit_ratio}.",
|
96
96
|
}
|
97
97
|
end
|
98
98
|
end
|
@@ -103,12 +103,12 @@ module RubyPgExtras
|
|
103
103
|
if ssl_connection
|
104
104
|
{
|
105
105
|
ok: true,
|
106
|
-
message: "Database client is using a secure SSL connection."
|
106
|
+
message: "Database client is using a secure SSL connection.",
|
107
107
|
}
|
108
108
|
else
|
109
109
|
{
|
110
110
|
ok: false,
|
111
|
-
message: "Database client is using an unencrypted connection."
|
111
|
+
message: "Database client is using an unencrypted connection.",
|
112
112
|
}
|
113
113
|
end
|
114
114
|
end
|
@@ -116,7 +116,7 @@ module RubyPgExtras
|
|
116
116
|
def unused_indexes
|
117
117
|
indexes = query_module.unused_indexes(
|
118
118
|
in_format: :hash,
|
119
|
-
args: { min_scans: PG_EXTRAS_UNUSED_INDEXES_MAX_SCANS }
|
119
|
+
args: { min_scans: PG_EXTRAS_UNUSED_INDEXES_MAX_SCANS },
|
120
120
|
).select do |i|
|
121
121
|
SizeParser.to_i(i.fetch("index_size").strip) >= PG_EXTRAS_UNUSED_INDEXES_MIN_SIZE_BYTES
|
122
122
|
end
|
@@ -124,15 +124,15 @@ module RubyPgExtras
|
|
124
124
|
if indexes.count == 0
|
125
125
|
{
|
126
126
|
ok: true,
|
127
|
-
message: "No unused indexes detected."
|
127
|
+
message: "No unused indexes detected.",
|
128
128
|
}
|
129
129
|
else
|
130
130
|
print_indexes = indexes.map do |i|
|
131
|
-
"'#{i.fetch(
|
131
|
+
"'#{i.fetch("index")}' on '#{i.fetch("table")}' size #{i.fetch("index_size")}"
|
132
132
|
end.join(",\n")
|
133
133
|
{
|
134
134
|
ok: false,
|
135
|
-
message: "Unused indexes detected:\n#{print_indexes}"
|
135
|
+
message: "Unused indexes detected:\n#{print_indexes}",
|
136
136
|
}
|
137
137
|
end
|
138
138
|
end
|
@@ -140,7 +140,7 @@ module RubyPgExtras
|
|
140
140
|
def null_indexes
|
141
141
|
indexes = query_module.null_indexes(
|
142
142
|
in_format: :hash,
|
143
|
-
args: { min_relation_size_mb: PG_EXTRAS_NULL_INDEXES_MIN_SIZE_MB }
|
143
|
+
args: { min_relation_size_mb: PG_EXTRAS_NULL_INDEXES_MIN_SIZE_MB },
|
144
144
|
).select do |i|
|
145
145
|
i.fetch("null_frac").gsub("%", "").to_f >= PG_EXTRAS_NULL_MIN_NULL_FRAC_PERCENT
|
146
146
|
end
|
@@ -148,15 +148,15 @@ module RubyPgExtras
|
|
148
148
|
if indexes.count == 0
|
149
149
|
{
|
150
150
|
ok: true,
|
151
|
-
message: "No null indexes detected."
|
151
|
+
message: "No null indexes detected.",
|
152
152
|
}
|
153
153
|
else
|
154
154
|
print_indexes = indexes.map do |i|
|
155
|
-
"'#{i.fetch(
|
155
|
+
"'#{i.fetch("index")}' size #{i.fetch("index_size")} null values fraction #{i.fetch("null_frac")}"
|
156
156
|
end.join(",\n")
|
157
157
|
{
|
158
158
|
ok: false,
|
159
|
-
message: "Null indexes detected:\n#{print_indexes}"
|
159
|
+
message: "Null indexes detected:\n#{print_indexes}",
|
160
160
|
}
|
161
161
|
end
|
162
162
|
end
|
@@ -169,16 +169,16 @@ module RubyPgExtras
|
|
169
169
|
if bloat_data.count == 0
|
170
170
|
{
|
171
171
|
ok: true,
|
172
|
-
message: "No bloat detected."
|
172
|
+
message: "No bloat detected.",
|
173
173
|
}
|
174
174
|
else
|
175
175
|
print_bloat = bloat_data.map do |b|
|
176
|
-
"'#{b.fetch(
|
176
|
+
"'#{b.fetch("object_name")}' bloat #{b.fetch("bloat")} waste #{b.fetch("waste")}"
|
177
177
|
end.join(",\n")
|
178
178
|
|
179
179
|
{
|
180
180
|
ok: false,
|
181
|
-
message: "Bloat detected:\n#{print_bloat}"
|
181
|
+
message: "Bloat detected:\n#{print_bloat}",
|
182
182
|
}
|
183
183
|
end
|
184
184
|
end
|
@@ -189,16 +189,16 @@ module RubyPgExtras
|
|
189
189
|
if indexes.count == 0
|
190
190
|
{
|
191
191
|
ok: true,
|
192
|
-
message: "No duplicate indexes detected."
|
192
|
+
message: "No duplicate indexes detected.",
|
193
193
|
}
|
194
194
|
else
|
195
195
|
print_indexes = indexes.map do |i|
|
196
|
-
"'#{i.fetch(
|
196
|
+
"'#{i.fetch("idx1")}' of size #{i.fetch("size")} is identical to '#{i.fetch("idx2")}'"
|
197
197
|
end.join(",\n")
|
198
198
|
|
199
199
|
{
|
200
200
|
ok: false,
|
201
|
-
message: "Duplicate indexes detected:\n#{print_indexes}"
|
201
|
+
message: "Duplicate indexes detected:\n#{print_indexes}",
|
202
202
|
}
|
203
203
|
end
|
204
204
|
end
|
@@ -211,16 +211,16 @@ module RubyPgExtras
|
|
211
211
|
if queries.count == 0
|
212
212
|
{
|
213
213
|
ok: true,
|
214
|
-
message: "No queries using significant execution ratio detected."
|
214
|
+
message: "No queries using significant execution ratio detected.",
|
215
215
|
}
|
216
216
|
else
|
217
217
|
print_queries = queries.map do |q|
|
218
|
-
"'#{q.fetch(
|
218
|
+
"'#{q.fetch("query").slice(0, 30)}...' called #{q.fetch("ncalls")} times, using #{q.fetch("prop_exec_time")} of total exec time."
|
219
219
|
end.join(",\n")
|
220
220
|
|
221
221
|
{
|
222
222
|
ok: false,
|
223
|
-
message: "Queries using significant execution ratio detected:\n#{print_queries}"
|
223
|
+
message: "Queries using significant execution ratio detected:\n#{print_queries}",
|
224
224
|
}
|
225
225
|
end
|
226
226
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "terminal-table"
|
4
4
|
|
5
5
|
module RubyPgExtras
|
6
6
|
class DiagnosePrint
|
@@ -17,13 +17,13 @@ module RubyPgExtras
|
|
17
17
|
|
18
18
|
[
|
19
19
|
colorize("[#{symbol}] - #{el.fetch(:check_name)}", color),
|
20
|
-
colorize(el.fetch(:message), color)
|
20
|
+
colorize(el.fetch(:message), color),
|
21
21
|
]
|
22
22
|
end
|
23
23
|
|
24
24
|
puts Terminal::Table.new(
|
25
25
|
title: title,
|
26
|
-
rows: rows
|
26
|
+
rows: rows,
|
27
27
|
)
|
28
28
|
end
|
29
29
|
|
@@ -19,16 +19,16 @@ module RubyPgExtras
|
|
19
19
|
{
|
20
20
|
index_name: index_name,
|
21
21
|
table_name: index_data.fetch("tablename"),
|
22
|
-
columns: index_data.fetch("columns").split(
|
22
|
+
columns: index_data.fetch("columns").split(",").map(&:strip),
|
23
23
|
index_size: index_size_data.find do |el|
|
24
24
|
el.fetch("name") == index_name
|
25
25
|
end.fetch("size", "N/A"),
|
26
|
-
index_scans:
|
26
|
+
index_scans: index_scans_data.find do |el|
|
27
27
|
el.fetch("index") == index_name
|
28
28
|
end.fetch("index_scans", "N/A"),
|
29
29
|
null_frac: null_indexes_data.find do |el|
|
30
30
|
el.fetch("index") == index_name
|
31
|
-
end&.fetch("null_frac", "N/A")&.strip || "0.00%"
|
31
|
+
end&.fetch("null_frac", "N/A")&.strip || "0.00%",
|
32
32
|
}
|
33
33
|
end
|
34
34
|
end
|
@@ -40,7 +40,7 @@ module RubyPgExtras
|
|
40
40
|
def null_indexes_data
|
41
41
|
@_null_indexes_data ||= query_module.null_indexes(
|
42
42
|
in_format: :hash,
|
43
|
-
args: { min_relation_size_mb: 0 }
|
43
|
+
args: { min_relation_size_mb: 0 },
|
44
44
|
)
|
45
45
|
end
|
46
46
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "terminal-table"
|
4
4
|
|
5
5
|
module RubyPgExtras
|
6
6
|
class IndexInfoPrint
|
@@ -13,10 +13,10 @@ module RubyPgExtras
|
|
13
13
|
[
|
14
14
|
el.fetch(:index_name),
|
15
15
|
el.fetch(:table_name),
|
16
|
-
el.fetch(:columns).join(
|
16
|
+
el.fetch(:columns).join(", "),
|
17
17
|
el.fetch(:index_size),
|
18
18
|
el.fetch(:index_scans),
|
19
|
-
el.fetch(:null_frac)
|
19
|
+
el.fetch(:null_frac),
|
20
20
|
]
|
21
21
|
end
|
22
22
|
|
@@ -27,10 +27,10 @@ module RubyPgExtras
|
|
27
27
|
"Columns",
|
28
28
|
"Index size",
|
29
29
|
"Index scans",
|
30
|
-
"Null frac"
|
30
|
+
"Null frac",
|
31
31
|
],
|
32
32
|
title: title,
|
33
|
-
rows: rows
|
33
|
+
rows: rows,
|
34
34
|
)
|
35
35
|
end
|
36
36
|
|
@@ -10,7 +10,7 @@ module RubyPgExtras
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.regexp_for_units(units)
|
13
|
-
/\A(-?\d+)\s?(#{units.join(
|
13
|
+
/\A(-?\d+)\s?(#{units.join("|")})\z/i
|
14
14
|
end
|
15
15
|
|
16
16
|
SI_UNITS = %w[bytes kB MB GB TB PB EB ZB YB].map(&:downcase).freeze
|
@@ -32,7 +32,7 @@ module RubyPgExtras
|
|
32
32
|
return nil unless match_data
|
33
33
|
|
34
34
|
exponent = units.index(match_data[2].downcase).to_i
|
35
|
-
match_data[1].to_i * multiplier**exponent
|
35
|
+
match_data[1].to_i * multiplier ** exponent
|
36
36
|
end
|
37
37
|
|
38
38
|
DIGITS_ONLY_REGEXP = /\A(-?\d+)\z/.freeze
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "terminal-table"
|
4
4
|
|
5
5
|
module RubyPgExtras
|
6
6
|
class TableInfoPrint
|
@@ -17,7 +17,7 @@ module RubyPgExtras
|
|
17
17
|
el.fetch(:indexes_cache_hit),
|
18
18
|
el.fetch(:estimated_rows),
|
19
19
|
el.fetch(:sequential_scans),
|
20
|
-
el.fetch(:indexes_scans)
|
20
|
+
el.fetch(:indexes_scans),
|
21
21
|
]
|
22
22
|
end
|
23
23
|
|
@@ -29,10 +29,10 @@ module RubyPgExtras
|
|
29
29
|
"Indexes cache hit",
|
30
30
|
"Estimated rows",
|
31
31
|
"Sequential scans",
|
32
|
-
"Indexes scans"
|
32
|
+
"Indexes scans",
|
33
33
|
],
|
34
34
|
title: title,
|
35
|
-
rows: rows
|
35
|
+
rows: rows,
|
36
36
|
)
|
37
37
|
end
|
38
38
|
|
data/ruby-pg-extras.gemspec
CHANGED
@@ -1,24 +1,25 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require "ruby_pg_extras/version"
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
|
-
s.name
|
8
|
-
s.version
|
9
|
-
s.authors
|
10
|
-
s.email
|
11
|
-
s.summary
|
12
|
-
s.description
|
13
|
-
s.homepage
|
14
|
-
s.files
|
15
|
-
s.test_files
|
7
|
+
s.name = "ruby-pg-extras"
|
8
|
+
s.version = RubyPgExtras::VERSION
|
9
|
+
s.authors = ["pawurb"]
|
10
|
+
s.email = ["contact@pawelurbanek.com"]
|
11
|
+
s.summary = %q{ Ruby PostgreSQL performance database insights }
|
12
|
+
s.description = %q{ Ruby port of Heroku PG Extras. The goal of this project is to provide a powerful insights into PostgreSQL database for Ruby on Rails apps that are not using the default Heroku PostgreSQL plugin. }
|
13
|
+
s.homepage = "http://github.com/pawurb/ruby-pg-extras"
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = s.files.grep(%r{^(spec)/})
|
16
16
|
s.require_paths = ["lib"]
|
17
|
-
s.license
|
17
|
+
s.license = "MIT"
|
18
18
|
s.add_dependency "pg"
|
19
19
|
s.add_dependency "terminal-table"
|
20
20
|
s.add_development_dependency "rake"
|
21
21
|
s.add_development_dependency "rspec"
|
22
|
+
s.add_development_dependency "rufo"
|
22
23
|
|
23
24
|
if s.respond_to?(:metadata=)
|
24
25
|
s.metadata = { "rubygems_mfa_required" => "true" }
|
data/spec/diagnose_data_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spec_helper"
|
4
4
|
|
5
5
|
describe RubyPgExtras::DiagnoseData do
|
6
6
|
subject(:result) do
|
@@ -14,7 +14,7 @@ describe RubyPgExtras::DiagnoseData do
|
|
14
14
|
[
|
15
15
|
{ "table" => "public.plans", "index" => "index_plans_on_payer_id", "index_size" => "16 MB", "index_scans" => 0 },
|
16
16
|
{ "table" => "public.feedbacks", "index" => "index_feedbacks_on_target_id", "index_size" => "111180 bytes", "index_scans" => 1 },
|
17
|
-
{ "table" => "public.channels", "index" => "index_channels_on_slack_id", "index_size" => "56 MB", "index_scans" => 7}
|
17
|
+
{ "table" => "public.channels", "index" => "index_channels_on_slack_id", "index_size" => "56 MB", "index_scans" => 7 },
|
18
18
|
]
|
19
19
|
}
|
20
20
|
|
@@ -22,7 +22,7 @@ describe RubyPgExtras::DiagnoseData do
|
|
22
22
|
[
|
23
23
|
{ "oid" => 123, "index" => "index_plans_on_payer_id", "index_size" => "16 MB", "unique" => true, "null_frac" => "00.00%", "expected_saving" => "0 kb" },
|
24
24
|
{ "oid" => 321, "index" => "index_feedbacks_on_target_id", "index_size" => "80 kB", "unique" => true, "null_frac" => "97.00%", "expected_saving" => "77 kb" },
|
25
|
-
{ "oid" => 231, "index" => "index_channels_on_slack_id", "index_size" => "56 MB", "unique" => true, "null_frac" => "49.99%", "expected_saving" => "28 MB" }
|
25
|
+
{ "oid" => 231, "index" => "index_channels_on_slack_id", "index_size" => "56 MB", "unique" => true, "null_frac" => "49.99%", "expected_saving" => "28 MB" },
|
26
26
|
]
|
27
27
|
}
|
28
28
|
|
@@ -30,19 +30,19 @@ describe RubyPgExtras::DiagnoseData do
|
|
30
30
|
[
|
31
31
|
{ "type" => "table", "schemaname" => "public", "object_name" => "bloated_table_1", "bloat" => 8, "waste" => "0 kb" },
|
32
32
|
{ "type" => "table", "schemaname" => "public", "object_name" => "bloated_table_2", "bloat" => 8, "waste" => "77 kb" },
|
33
|
-
{ "type" => "schemaname", "public" => "index_channels_on_slack_id", "object_name" => "bloated_index", "bloat" => 11, "waste" => "28 MB" }
|
33
|
+
{ "type" => "schemaname", "public" => "index_channels_on_slack_id", "object_name" => "bloated_index", "bloat" => 11, "waste" => "28 MB" },
|
34
34
|
]
|
35
35
|
}
|
36
36
|
|
37
37
|
expect(RubyPgExtras).to receive(:duplicate_indexes) {
|
38
38
|
[
|
39
|
-
{ "size" => "128 kb", "idx1" => "users_pkey", "idx2" => "index_users_id" }
|
39
|
+
{ "size" => "128 kb", "idx1" => "users_pkey", "idx2" => "index_users_id" },
|
40
40
|
]
|
41
41
|
}
|
42
42
|
|
43
43
|
expect(RubyPgExtras).to receive(:outliers) {
|
44
44
|
[
|
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" }
|
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
48
|
end
|
data/spec/diagnose_print_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spec_helper"
|
4
4
|
|
5
5
|
describe RubyPgExtras::DiagnosePrint do
|
6
6
|
subject(:print_result) do
|
@@ -12,18 +12,18 @@ describe RubyPgExtras::DiagnosePrint do
|
|
12
12
|
{
|
13
13
|
:check_name => :table_cache_hit,
|
14
14
|
:ok => false,
|
15
|
-
:message => "Table hit ratio too low: 0.906977."
|
15
|
+
:message => "Table hit ratio too low: 0.906977.",
|
16
16
|
},
|
17
17
|
{
|
18
18
|
:check_name => :index_cache_hit,
|
19
19
|
:ok => false,
|
20
|
-
:message => "Index hit ratio is too low: 0.818182."
|
20
|
+
:message => "Index hit ratio is too low: 0.818182.",
|
21
21
|
},
|
22
22
|
{
|
23
23
|
:check_name => :ssl_used,
|
24
24
|
:ok => true,
|
25
|
-
:message => "Database client is using a secure SSL connection."
|
26
|
-
}
|
25
|
+
:message => "Database client is using a secure SSL connection.",
|
26
|
+
},
|
27
27
|
]
|
28
28
|
end
|
29
29
|
|
data/spec/index_info_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spec_helper"
|
4
4
|
|
5
5
|
describe RubyPgExtras::IndexInfo do
|
6
6
|
subject(:result) do
|
@@ -13,27 +13,27 @@ describe RubyPgExtras::IndexInfo do
|
|
13
13
|
expect(RubyPgExtras).to receive(:indexes) {
|
14
14
|
[
|
15
15
|
{ "schemaname" => "public", "indexname" => "index_users_on_api_auth_token", "tablename" => "users", "columns" => "api_auth_token, column2" },
|
16
|
-
{"schemaname" => "public", "indexname" => "index_teams_on_slack_id", "tablename" => "teams", "columns" => "slack_id" },
|
16
|
+
{ "schemaname" => "public", "indexname" => "index_teams_on_slack_id", "tablename" => "teams", "columns" => "slack_id" },
|
17
17
|
]
|
18
18
|
}
|
19
19
|
|
20
20
|
expect(RubyPgExtras).to receive(:index_size) {
|
21
21
|
[
|
22
22
|
{ "name" => "index_users_on_api_auth_token", "size" => "1744 kB" },
|
23
|
-
{"name" => "index_teams_on_slack_id", "size" => "500 kB"},
|
23
|
+
{ "name" => "index_teams_on_slack_id", "size" => "500 kB" },
|
24
24
|
]
|
25
25
|
}
|
26
26
|
|
27
27
|
expect(RubyPgExtras).to receive(:null_indexes) {
|
28
28
|
[
|
29
|
-
{ "oid" => 16803, "index" => "index_users_on_api_auth_token", "index_size" => "1744 kB", "unique"=>true, "indexed_column" => "api_auth_token", "null_frac" => "25.00%", "expected_saving" => "300 kB" }
|
29
|
+
{ "oid" => 16803, "index" => "index_users_on_api_auth_token", "index_size" => "1744 kB", "unique" => true, "indexed_column" => "api_auth_token", "null_frac" => "25.00%", "expected_saving" => "300 kB" },
|
30
30
|
]
|
31
31
|
}
|
32
32
|
|
33
33
|
expect(RubyPgExtras).to receive(:index_scans) {
|
34
34
|
[
|
35
|
-
{ "schemaname" => "public", "table" => "users", "index" => "index_users_on_api_auth_token", "index_size" => "1744 kB", "index_scans"=> 0 },
|
36
|
-
{ "schemaname" => "public", "table" => "teams", "index" => "index_teams_on_slack_id", "index_size" => "500 kB", "index_scans"=> 0 }
|
35
|
+
{ "schemaname" => "public", "table" => "users", "index" => "index_users_on_api_auth_token", "index_size" => "1744 kB", "index_scans" => 0 },
|
36
|
+
{ "schemaname" => "public", "table" => "teams", "index" => "index_teams_on_slack_id", "index_size" => "500 kB", "index_scans" => 0 },
|
37
37
|
]
|
38
38
|
}
|
39
39
|
end
|
data/spec/size_parser_spec.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spec_helper"
|
4
4
|
|
5
5
|
describe RubyPgExtras::SizeParser do
|
6
6
|
subject(:result) { described_class.to_i(arg) }
|
7
7
|
|
8
|
-
describe
|
8
|
+
describe "SI Units" do
|
9
9
|
let(:arg) { "#{num_units} #{unit}" }
|
10
10
|
|
11
11
|
context "when the argument is a number followed by 'bytes', with possible case variations" do
|
@@ -72,7 +72,7 @@ describe RubyPgExtras::SizeParser do
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
-
describe
|
75
|
+
describe "Binary Units" do
|
76
76
|
let(:arg) { "#{num_units} #{unit}" }
|
77
77
|
|
78
78
|
context "when the argument is a number followed by 'bytes', with possible case variations" do
|
@@ -139,28 +139,28 @@ describe RubyPgExtras::SizeParser do
|
|
139
139
|
end
|
140
140
|
end
|
141
141
|
|
142
|
-
context
|
143
|
-
let(:arg) {
|
142
|
+
context "when the argument has only digits" do
|
143
|
+
let(:arg) { "654245" }
|
144
144
|
|
145
145
|
it { is_expected.to eq(arg.to_i) }
|
146
146
|
end
|
147
147
|
|
148
|
-
describe
|
149
|
-
it
|
148
|
+
describe "errors" do
|
149
|
+
it "raises an error when the argument has an invalid prefix" do
|
150
150
|
expect do
|
151
|
-
described_class.to_i(
|
151
|
+
described_class.to_i("123 qb")
|
152
152
|
end.to raise_error ArgumentError
|
153
153
|
end
|
154
154
|
|
155
|
-
it
|
155
|
+
it "raises an error when the argument does not have a unit in bytes" do
|
156
156
|
expect do
|
157
|
-
described_class.to_i(
|
157
|
+
described_class.to_i("123 mL")
|
158
158
|
end.to raise_error ArgumentError
|
159
159
|
end
|
160
160
|
|
161
|
-
it
|
161
|
+
it "when the argument cannot be parsed an number of units" do
|
162
162
|
expect do
|
163
|
-
described_class.to_i(
|
163
|
+
described_class.to_i("1c3 MB")
|
164
164
|
end.to raise_error ArgumentError
|
165
165
|
end
|
166
166
|
end
|
data/spec/smoke_spec.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spec_helper"
|
4
4
|
|
5
5
|
describe RubyPgExtras do
|
6
6
|
RubyPgExtras::QUERIES.each do |query_name|
|
7
7
|
it "#{query_name} description can be read" do
|
8
8
|
expect do
|
9
9
|
RubyPgExtras.description_for(
|
10
|
-
query_name: query_name
|
10
|
+
query_name: query_name,
|
11
11
|
)
|
12
12
|
end.not_to raise_error
|
13
13
|
end
|
@@ -18,7 +18,7 @@ describe RubyPgExtras do
|
|
18
18
|
expect do
|
19
19
|
RubyPgExtras.run_query(
|
20
20
|
query_name: query_name,
|
21
|
-
in_format: :hash
|
21
|
+
in_format: :hash,
|
22
22
|
)
|
23
23
|
end.not_to raise_error
|
24
24
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require_relative
|
3
|
+
require "rubygems"
|
4
|
+
require "bundler/setup"
|
5
|
+
require_relative "../lib/ruby-pg-extras"
|
6
6
|
|
7
7
|
pg_version = ENV["PG_VERSION"]
|
8
8
|
|
9
9
|
port = if pg_version == "11"
|
10
|
-
|
11
|
-
elsif pg_version == "12"
|
12
|
-
|
13
|
-
elsif pg_version == "13"
|
14
|
-
|
15
|
-
elsif pg_version == "14"
|
16
|
-
|
17
|
-
else
|
18
|
-
|
19
|
-
end
|
10
|
+
"5432"
|
11
|
+
elsif pg_version == "12"
|
12
|
+
"5433"
|
13
|
+
elsif pg_version == "13"
|
14
|
+
"5434"
|
15
|
+
elsif pg_version == "14"
|
16
|
+
"5435"
|
17
|
+
else
|
18
|
+
"5432"
|
19
|
+
end
|
20
20
|
|
21
21
|
ENV["DATABASE_URL"] ||= "postgresql://postgres:secret@localhost:#{port}/ruby-pg-extras-test"
|
22
22
|
|
data/spec/table_info_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spec_helper"
|
4
4
|
|
5
5
|
describe RubyPgExtras::TableInfo do
|
6
6
|
subject(:result) do
|
@@ -13,14 +13,14 @@ describe RubyPgExtras::TableInfo do
|
|
13
13
|
expect(RubyPgExtras).to receive(:tables) {
|
14
14
|
[
|
15
15
|
{ "schemaname" => "public", "tablename" => "users" },
|
16
|
-
{ "schemaname" => "public", "tablename" => "teams" }
|
16
|
+
{ "schemaname" => "public", "tablename" => "teams" },
|
17
17
|
]
|
18
18
|
}
|
19
19
|
|
20
20
|
expect(RubyPgExtras).to receive(:table_size) {
|
21
21
|
[
|
22
22
|
{ "name" => "teams", "size" => "25 MB" },
|
23
|
-
{"name" => "users", "size" => "250 MB"},
|
23
|
+
{ "name" => "users", "size" => "250 MB" },
|
24
24
|
]
|
25
25
|
}
|
26
26
|
|
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.
|
4
|
+
version: 5.4.0
|
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: 2024-09-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rufo
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
description: " Ruby port of Heroku PG Extras. The goal of this project is to provide
|
70
84
|
a powerful insights into PostgreSQL database for Ruby on Rails apps that are not
|
71
85
|
using the default Heroku PostgreSQL plugin. "
|
@@ -159,7 +173,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
159
173
|
- !ruby/object:Gem::Version
|
160
174
|
version: '0'
|
161
175
|
requirements: []
|
162
|
-
rubygems_version: 3.
|
176
|
+
rubygems_version: 3.5.4
|
163
177
|
signing_key:
|
164
178
|
specification_version: 4
|
165
179
|
summary: Ruby PostgreSQL performance database insights
|