ruby-pg-extras 5.3.1 → 5.4.1
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 +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
|