ruby-pg-extras 5.3.1 → 5.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +34 -32
- data/Gemfile +1 -1
- data/README.md +5 -1
- data/Rakefile +3 -3
- data/docker-compose.yml.sample +27 -10
- data/lib/ruby-pg-extras.rb +28 -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/calls_17.sql +9 -0
- data/lib/ruby_pg_extras/queries/locks.sql +2 -0
- data/lib/ruby_pg_extras/queries/outliers_17.sql +10 -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 +18 -14
- data/spec/table_info_spec.rb +3 -3
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 809377163a6ca42ea4b8b0087e1d4ede8cfe326d0ee10a85a32df4d6f0e447f5
|
4
|
+
data.tar.gz: 295812fd83c470552c330bcf520749ebfcd6574270c7f2ee7d58d74c0877b968
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf48947fd5d74c8e7052cfcf9383521366887e22b7206cc4f830c91cbc17fa75db07279240d6a611febc0b7af6a9f03b9db7431b4a3b21cb80c416becaa13e2f
|
7
|
+
data.tar.gz: 1aa0b28a52a83e76f31a5101af38fa006f07ab2180980d3d149206925eba96ca76a7589cf194e534f621e32513fe7c313d45137933824a6600b86bb42295849d
|
data/.github/workflows/ci.yml
CHANGED
@@ -12,43 +12,52 @@ jobs:
|
|
12
12
|
strategy:
|
13
13
|
fail-fast: false
|
14
14
|
matrix:
|
15
|
-
ruby-version: ['3.2', '3.1', '3.0', '2.7', '2.6']
|
15
|
+
ruby-version: ['3.3', '3.2', '3.1', '3.0', '2.7', '2.6']
|
16
16
|
steps:
|
17
|
-
- uses: actions/checkout@
|
18
|
-
- name: Run PostgreSQL
|
17
|
+
- uses: actions/checkout@v4
|
18
|
+
- name: Run PostgreSQL 12
|
19
19
|
run: |
|
20
20
|
docker run --env POSTGRES_USER=postgres \
|
21
21
|
--env POSTGRES_DB=ruby-pg-extras-test \
|
22
22
|
--env POSTGRES_PASSWORD=secret \
|
23
|
-
-d -p 5432:5432 postgres:
|
23
|
+
-d -p 5432:5432 postgres:12.20-alpine \
|
24
24
|
postgres -c shared_preload_libraries=pg_stat_statements
|
25
|
-
- name: Run PostgreSQL
|
25
|
+
- name: Run PostgreSQL 13
|
26
26
|
run: |
|
27
27
|
docker run --env POSTGRES_USER=postgres \
|
28
28
|
--env POSTGRES_DB=ruby-pg-extras-test \
|
29
29
|
--env POSTGRES_PASSWORD=secret \
|
30
|
-
-d -p 5433:5432 postgres:
|
30
|
+
-d -p 5433:5432 postgres:13.16-alpine \
|
31
31
|
postgres -c shared_preload_libraries=pg_stat_statements
|
32
|
-
- name: Run PostgreSQL
|
32
|
+
- name: Run PostgreSQL 14
|
33
33
|
run: |
|
34
34
|
docker run --env POSTGRES_USER=postgres \
|
35
35
|
--env POSTGRES_DB=ruby-pg-extras-test \
|
36
36
|
--env POSTGRES_PASSWORD=secret \
|
37
|
-
-d -p 5434:5432 postgres:13
|
37
|
+
-d -p 5434:5432 postgres:14.13-alpine \
|
38
38
|
postgres -c shared_preload_libraries=pg_stat_statements
|
39
|
-
- name: Run PostgreSQL
|
39
|
+
- name: Run PostgreSQL 15
|
40
40
|
run: |
|
41
41
|
docker run --env POSTGRES_USER=postgres \
|
42
42
|
--env POSTGRES_DB=ruby-pg-extras-test \
|
43
43
|
--env POSTGRES_PASSWORD=secret \
|
44
|
-
-d -p 5435:5432 postgres:
|
44
|
+
-d -p 5435:5432 postgres:15.8-alpine \
|
45
45
|
postgres -c shared_preload_libraries=pg_stat_statements
|
46
|
-
|
46
|
+
sleep 15
|
47
|
+
- name: Run PostgreSQL 16
|
48
|
+
run: |
|
49
|
+
docker run --env POSTGRES_USER=postgres \
|
50
|
+
--env POSTGRES_DB=ruby-pg-extras-test \
|
51
|
+
--env POSTGRES_PASSWORD=secret \
|
52
|
+
-d -p 5436:5432 postgres:16.4-alpine \
|
53
|
+
postgres -c shared_preload_libraries=pg_stat_statements
|
54
|
+
sleep 15
|
55
|
+
- name: Run PostgreSQL 17
|
47
56
|
run: |
|
48
57
|
docker run --env POSTGRES_USER=postgres \
|
49
58
|
--env POSTGRES_DB=ruby-pg-extras-test \
|
50
59
|
--env POSTGRES_PASSWORD=secret \
|
51
|
-
-d -p
|
60
|
+
-d -p 5437:5432 postgres:17.0-alpine \
|
52
61
|
postgres -c shared_preload_libraries=pg_stat_statements
|
53
62
|
sleep 15
|
54
63
|
- name: Set up Ruby ${{ matrix.ruby-version }}
|
@@ -57,72 +66,65 @@ jobs:
|
|
57
66
|
ruby-version: ${{ matrix.ruby-version }}
|
58
67
|
- name: Setup dependencies
|
59
68
|
run: |
|
60
|
-
gem
|
61
|
-
gem install bundler
|
69
|
+
gem install bundler -v 2.4.22
|
62
70
|
sudo apt-get update --allow-releaseinfo-change
|
63
71
|
sudo apt install postgresql-client
|
64
72
|
sudo apt install libpq-dev
|
65
73
|
bundle config set --local path 'vendor/bundle'
|
66
74
|
bundle install
|
67
75
|
sleep 10
|
68
|
-
- name: Run tests for PG
|
76
|
+
- name: Run tests for PG 12
|
69
77
|
env:
|
70
|
-
PG_VERSION:
|
78
|
+
PG_VERSION: 12
|
71
79
|
POSTGRES_HOST: localhost
|
72
80
|
POSTGRES_USER: postgres
|
73
81
|
POSTGRES_DB: ruby-pg-extras-test
|
74
82
|
POSTGRES_PASSWORD: secret
|
75
|
-
DATABASE_URL: postgresql://postgres:secret@localhost:5432/ruby-pg-extras-test
|
76
83
|
run: |
|
77
84
|
bundle exec rspec spec/
|
78
|
-
- name: Run tests for PG
|
85
|
+
- name: Run tests for PG 13
|
79
86
|
env:
|
80
|
-
PG_VERSION:
|
87
|
+
PG_VERSION: 13
|
81
88
|
POSTGRES_HOST: localhost
|
82
89
|
POSTGRES_USER: postgres
|
83
90
|
POSTGRES_DB: ruby-pg-extras-test
|
84
91
|
POSTGRES_PASSWORD: secret
|
85
|
-
DATABASE_URL: postgresql://postgres:secret@localhost:5432/ruby-pg-extras-test
|
86
92
|
run: |
|
87
93
|
bundle exec rspec spec/
|
88
|
-
- name: Run tests for PG
|
94
|
+
- name: Run tests for PG 14
|
89
95
|
env:
|
90
|
-
PG_VERSION:
|
96
|
+
PG_VERSION: 14
|
91
97
|
POSTGRES_HOST: localhost
|
92
98
|
POSTGRES_USER: postgres
|
93
99
|
POSTGRES_DB: ruby-pg-extras-test
|
94
100
|
POSTGRES_PASSWORD: secret
|
95
|
-
DATABASE_URL: postgresql://postgres:secret@localhost:5433/ruby-pg-extras-test
|
96
101
|
run: |
|
97
102
|
bundle exec rspec spec/
|
98
|
-
- name: Run tests for PG
|
103
|
+
- name: Run tests for PG 15
|
99
104
|
env:
|
100
|
-
PG_VERSION:
|
105
|
+
PG_VERSION: 15
|
101
106
|
POSTGRES_HOST: localhost
|
102
107
|
POSTGRES_USER: postgres
|
103
108
|
POSTGRES_DB: ruby-pg-extras-test
|
104
109
|
POSTGRES_PASSWORD: secret
|
105
|
-
DATABASE_URL: postgresql://postgres:secret@localhost:5434/ruby-pg-extras-test
|
106
110
|
run: |
|
107
111
|
bundle exec rspec spec/
|
108
|
-
- name: Run tests for PG
|
112
|
+
- name: Run tests for PG 16
|
109
113
|
env:
|
110
|
-
PG_VERSION:
|
114
|
+
PG_VERSION: 16
|
111
115
|
POSTGRES_HOST: localhost
|
112
116
|
POSTGRES_USER: postgres
|
113
117
|
POSTGRES_DB: ruby-pg-extras-test
|
114
118
|
POSTGRES_PASSWORD: secret
|
115
|
-
DATABASE_URL: postgresql://postgres:secret@localhost:5435/ruby-pg-extras-test
|
116
119
|
run: |
|
117
120
|
bundle exec rspec spec/
|
118
|
-
- name: Run tests for PG
|
121
|
+
- name: Run tests for PG 17
|
119
122
|
env:
|
120
|
-
PG_VERSION:
|
123
|
+
PG_VERSION: 17
|
121
124
|
POSTGRES_HOST: localhost
|
122
125
|
POSTGRES_USER: postgres
|
123
126
|
POSTGRES_DB: ruby-pg-extras-test
|
124
127
|
POSTGRES_PASSWORD: secret
|
125
|
-
DATABASE_URL: postgresql://postgres:secret@localhost:5436/ruby-pg-extras-test
|
126
128
|
run: |
|
127
129
|
bundle exec rspec spec/
|
128
130
|
|
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
|
-
system("PG_VERSION=
|
8
|
+
system("PG_VERSION=12 bundle exec rspec spec/ && PG_VERSION=13 bundle exec rspec spec/ && PG_VERSION=14 bundle exec rspec spec/ && PG_VERSION=15 bundle exec rspec spec/ && PG_VERSION=16 bundle exec rspec spec/ && PG_VERSION=17 bundle exec rspec spec/")
|
9
9
|
end
|
data/docker-compose.yml.sample
CHANGED
@@ -1,8 +1,6 @@
|
|
1
|
-
version: '3'
|
2
|
-
|
3
1
|
services:
|
4
|
-
|
5
|
-
image: postgres:
|
2
|
+
postgres12:
|
3
|
+
image: postgres:12.20-alpine
|
6
4
|
command: postgres -c shared_preload_libraries=pg_stat_statements
|
7
5
|
environment:
|
8
6
|
POSTGRES_USER: postgres
|
@@ -10,8 +8,8 @@ services:
|
|
10
8
|
POSTGRES_PASSWORD: secret
|
11
9
|
ports:
|
12
10
|
- '5432:5432'
|
13
|
-
|
14
|
-
image: postgres:
|
11
|
+
postgres13:
|
12
|
+
image: postgres:13.16-alpine
|
15
13
|
command: postgres -c shared_preload_libraries=pg_stat_statements
|
16
14
|
environment:
|
17
15
|
POSTGRES_USER: postgres
|
@@ -19,8 +17,8 @@ services:
|
|
19
17
|
POSTGRES_PASSWORD: secret
|
20
18
|
ports:
|
21
19
|
- '5433:5432'
|
22
|
-
|
23
|
-
image: postgres:13
|
20
|
+
postgres14:
|
21
|
+
image: postgres:14.13-alpine
|
24
22
|
command: postgres -c shared_preload_libraries=pg_stat_statements
|
25
23
|
environment:
|
26
24
|
POSTGRES_USER: postgres
|
@@ -28,8 +26,8 @@ services:
|
|
28
26
|
POSTGRES_PASSWORD: secret
|
29
27
|
ports:
|
30
28
|
- '5434:5432'
|
31
|
-
|
32
|
-
image: postgres:
|
29
|
+
postgres15:
|
30
|
+
image: postgres:15.8-alpine
|
33
31
|
command: postgres -c shared_preload_libraries=pg_stat_statements
|
34
32
|
environment:
|
35
33
|
POSTGRES_USER: postgres
|
@@ -37,3 +35,22 @@ services:
|
|
37
35
|
POSTGRES_PASSWORD: secret
|
38
36
|
ports:
|
39
37
|
- '5435:5432'
|
38
|
+
postgres16:
|
39
|
+
image: postgres:16.4-alpine
|
40
|
+
command: postgres -c shared_preload_libraries=pg_stat_statements
|
41
|
+
environment:
|
42
|
+
POSTGRES_USER: postgres
|
43
|
+
POSTGRES_DB: ruby-pg-extras-test
|
44
|
+
POSTGRES_PASSWORD: secret
|
45
|
+
ports:
|
46
|
+
- '5436:5432'
|
47
|
+
postgres17:
|
48
|
+
image: postgres:17.0-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
|
+
- '5437:5432'
|
56
|
+
|
data/lib/ruby-pg-extras.rb
CHANGED
@@ -1,19 +1,20 @@
|
|
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
|
16
16
|
NEW_PG_STAT_STATEMENTS = "1.8"
|
17
|
+
PG_STAT_STATEMENTS_17 = "1.11"
|
17
18
|
|
18
19
|
QUERIES = %i(
|
19
20
|
add_extensions bloat blocking cache_hit db_settings
|
@@ -27,16 +28,18 @@ module RubyPgExtras
|
|
27
28
|
buffercache_usage ssl_used connections
|
28
29
|
)
|
29
30
|
|
30
|
-
DEFAULT_SCHEMA = ENV["PG_EXTRAS_SCHEMA"] ||
|
31
|
+
DEFAULT_SCHEMA = ENV["PG_EXTRAS_SCHEMA"] || "public"
|
31
32
|
|
32
33
|
DEFAULT_ARGS = Hash.new({}).merge({
|
33
34
|
calls: { limit: 10 },
|
34
35
|
calls_legacy: { limit: 10 },
|
36
|
+
calls_17: { limit: 10 },
|
35
37
|
long_running_queries: { threshold: "500 milliseconds" },
|
36
38
|
locks: { limit: 20 },
|
37
39
|
blocking: { limit: 20 },
|
38
40
|
outliers: { limit: 10 },
|
39
41
|
outliers_legacy: { limit: 10 },
|
42
|
+
outliers_17: { limit: 10 },
|
40
43
|
buffercache_stats: { limit: 10 },
|
41
44
|
buffercache_usage: { limit: 20 },
|
42
45
|
unused_indexes: { max_scans: 50, schema: DEFAULT_SCHEMA },
|
@@ -50,7 +53,7 @@ module RubyPgExtras
|
|
50
53
|
table_index_scans: { schema: DEFAULT_SCHEMA },
|
51
54
|
records_rank: { schema: DEFAULT_SCHEMA },
|
52
55
|
tables: { schema: DEFAULT_SCHEMA },
|
53
|
-
kill_pid: { pid: 0 }
|
56
|
+
kill_pid: { pid: 0 },
|
54
57
|
})
|
55
58
|
|
56
59
|
QUERIES.each do |query_name|
|
@@ -58,7 +61,7 @@ module RubyPgExtras
|
|
58
61
|
run_query(
|
59
62
|
query_name: query_name,
|
60
63
|
in_format: options.fetch(:in_format, :display_table),
|
61
|
-
args: options.fetch(:args, {})
|
64
|
+
args: options.fetch(:args, {}),
|
62
65
|
)
|
63
66
|
end
|
64
67
|
end
|
@@ -70,21 +73,23 @@ module RubyPgExtras
|
|
70
73
|
if pg_stat_statements_ver != nil
|
71
74
|
if Gem::Version.new(pg_stat_statements_ver) < Gem::Version.new(NEW_PG_STAT_STATEMENTS)
|
72
75
|
query_name = "#{query_name}_legacy".to_sym
|
76
|
+
elsif Gem::Version.new(pg_stat_statements_ver) >= Gem::Version.new(PG_STAT_STATEMENTS_17)
|
77
|
+
query_name = "#{query_name}_17".to_sym
|
73
78
|
end
|
74
79
|
end
|
75
80
|
end
|
76
81
|
|
77
82
|
sql = if (custom_args = DEFAULT_ARGS[query_name].merge(args)) != {}
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
83
|
+
sql_for(query_name: query_name) % custom_args
|
84
|
+
else
|
85
|
+
sql_for(query_name: query_name)
|
86
|
+
end
|
82
87
|
result = connection.exec(sql)
|
83
88
|
|
84
89
|
display_result(
|
85
90
|
result,
|
86
91
|
title: description_for(query_name: query_name),
|
87
|
-
in_format: in_format
|
92
|
+
in_format: in_format,
|
88
93
|
)
|
89
94
|
end
|
90
95
|
|
@@ -140,15 +145,15 @@ module RubyPgExtras
|
|
140
145
|
result
|
141
146
|
when :display_table
|
142
147
|
headings = if result.count > 0
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
148
|
+
result[0].keys
|
149
|
+
else
|
150
|
+
["No results"]
|
151
|
+
end
|
147
152
|
|
148
153
|
puts Terminal::Table.new(
|
149
154
|
title: title,
|
150
155
|
headings: headings,
|
151
|
-
rows: result.values
|
156
|
+
rows: result.values,
|
152
157
|
)
|
153
158
|
else
|
154
159
|
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
|
|
@@ -0,0 +1,9 @@
|
|
1
|
+
/* Queries that have highest frequency of execution */
|
2
|
+
|
3
|
+
SELECT query AS qry,
|
4
|
+
interval '1 millisecond' * total_exec_time AS exec_time,
|
5
|
+
to_char((total_exec_time/sum(total_exec_time) OVER()) * 100, 'FM90D0') || '%%' AS prop_exec_time,
|
6
|
+
to_char(calls, 'FM999G999G990') AS ncalls,
|
7
|
+
interval '1 millisecond' * (shared_blk_read_time + shared_blk_write_time) AS sync_io_time
|
8
|
+
FROM pg_stat_statements WHERE userid = (SELECT usesysid FROM pg_user WHERE usename = current_user LIMIT 1)
|
9
|
+
ORDER BY calls DESC LIMIT %{limit};
|
@@ -0,0 +1,10 @@
|
|
1
|
+
/* Queries that have longest execution time in aggregate */
|
2
|
+
|
3
|
+
SELECT interval '1 millisecond' * total_exec_time AS total_exec_time,
|
4
|
+
to_char((total_exec_time/sum(total_exec_time) OVER()) * 100, 'FM90D0') || '%%' AS prop_exec_time,
|
5
|
+
to_char(calls, 'FM999G999G999G990') AS ncalls,
|
6
|
+
interval '1 millisecond' * (shared_blk_read_time + shared_blk_write_time) AS sync_io_time,
|
7
|
+
query AS query
|
8
|
+
FROM pg_stat_statements WHERE userid = (SELECT usesysid FROM pg_user WHERE usename = current_user LIMIT 1)
|
9
|
+
ORDER BY total_exec_time DESC
|
10
|
+
LIMIT %{limit};
|
@@ -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,26 @@
|
|
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
|
-
port = if pg_version == "
|
10
|
-
|
11
|
-
elsif pg_version == "
|
12
|
-
|
13
|
-
elsif pg_version == "
|
14
|
-
|
15
|
-
elsif pg_version == "
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
9
|
+
port = if pg_version == "12"
|
10
|
+
"5432"
|
11
|
+
elsif pg_version == "13"
|
12
|
+
"5433"
|
13
|
+
elsif pg_version == "14"
|
14
|
+
"5434"
|
15
|
+
elsif pg_version == "15"
|
16
|
+
"5435"
|
17
|
+
elsif pg_version == "16"
|
18
|
+
"5436"
|
19
|
+
elsif pg_version == "17"
|
20
|
+
"5437"
|
21
|
+
else
|
22
|
+
"5432"
|
23
|
+
end
|
20
24
|
|
21
25
|
ENV["DATABASE_URL"] ||= "postgresql://postgres:secret@localhost:#{port}/ruby-pg-extras-test"
|
22
26
|
|
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.1
|
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-10-08 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. "
|
@@ -95,6 +109,7 @@ files:
|
|
95
109
|
- lib/ruby_pg_extras/queries/buffercache_usage.sql
|
96
110
|
- lib/ruby_pg_extras/queries/cache_hit.sql
|
97
111
|
- lib/ruby_pg_extras/queries/calls.sql
|
112
|
+
- lib/ruby_pg_extras/queries/calls_17.sql
|
98
113
|
- lib/ruby_pg_extras/queries/calls_legacy.sql
|
99
114
|
- lib/ruby_pg_extras/queries/connections.sql
|
100
115
|
- lib/ruby_pg_extras/queries/db_settings.sql
|
@@ -112,6 +127,7 @@ files:
|
|
112
127
|
- lib/ruby_pg_extras/queries/mandelbrot.sql
|
113
128
|
- lib/ruby_pg_extras/queries/null_indexes.sql
|
114
129
|
- lib/ruby_pg_extras/queries/outliers.sql
|
130
|
+
- lib/ruby_pg_extras/queries/outliers_17.sql
|
115
131
|
- lib/ruby_pg_extras/queries/outliers_legacy.sql
|
116
132
|
- lib/ruby_pg_extras/queries/pg_stat_statements_reset.sql
|
117
133
|
- lib/ruby_pg_extras/queries/records_rank.sql
|
@@ -159,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
159
175
|
- !ruby/object:Gem::Version
|
160
176
|
version: '0'
|
161
177
|
requirements: []
|
162
|
-
rubygems_version: 3.
|
178
|
+
rubygems_version: 3.5.4
|
163
179
|
signing_key:
|
164
180
|
specification_version: 4
|
165
181
|
summary: Ruby PostgreSQL performance database insights
|