ruby-pg-extras 4.5.1 → 4.6.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/.circleci/config.yml +16 -4
- data/Rakefile +1 -1
- data/docker-compose.yml.sample +12 -3
- data/lib/ruby-pg-extras.rb +1 -0
- data/lib/ruby_pg_extras/diagnose_data.rb +2 -4
- data/lib/ruby_pg_extras/size_parser.rb +43 -0
- data/lib/ruby_pg_extras/version.rb +1 -1
- data/ruby-pg-extras.gemspec +0 -1
- data/spec/size_parser_spec.rb +167 -0
- data/spec/spec_helper.rb +2 -0
- metadata +5 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 250bb1e08a0937724fc2cf90c16d26670218a1c23884fd69f33f7379bb550a20
|
4
|
+
data.tar.gz: 12e69c803e3bd48287445bd46451255b3a0074fb3c1d4a0d373bb2d64a98e900
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b68d9e6c988df34cb7e3236ce4c12a7dbfdef23139dbc61cfe6364e21f95b55f0ca11c6f2657e1d350cf16fbb641a72f91228a12569b785061ee4e0d65737e45
|
7
|
+
data.tar.gz: d31f3679f3ffd66bc9a39e9868985a260807a32af5335e722ccba5f5df515c80d451b957544fcaa7e016e2bbbebe09992cd89a7046cb033639a48eb95bb43fbe
|
data/.circleci/config.yml
CHANGED
@@ -2,30 +2,37 @@ version: 2
|
|
2
2
|
jobs:
|
3
3
|
test:
|
4
4
|
docker:
|
5
|
-
- image:
|
5
|
+
- image: cimg/ruby:2.6
|
6
6
|
environment:
|
7
7
|
DATABASE_URL: postgresql://postgres:secret@localhost:5432/ruby-pg-extras-test
|
8
|
-
- image:
|
8
|
+
- image: cimg/postgres:11.15
|
9
9
|
command: postgres -c shared_preload_libraries=pg_stat_statements
|
10
10
|
name: postgres11
|
11
11
|
environment:
|
12
12
|
POSTGRES_USER: postgres
|
13
13
|
POSTGRES_DB: ruby-pg-extras-test
|
14
14
|
POSTGRES_PASSWORD: secret
|
15
|
-
- image:
|
15
|
+
- image: cimg/postgres:12.10
|
16
16
|
command: postgres -c shared_preload_libraries=pg_stat_statements
|
17
17
|
name: postgres12
|
18
18
|
environment:
|
19
19
|
POSTGRES_USER: postgres
|
20
20
|
POSTGRES_DB: ruby-pg-extras-test
|
21
21
|
POSTGRES_PASSWORD: secret
|
22
|
-
- image:
|
22
|
+
- image: cimg/postgres:13.6
|
23
23
|
command: postgres -c shared_preload_libraries=pg_stat_statements
|
24
24
|
name: postgres13
|
25
25
|
environment:
|
26
26
|
POSTGRES_USER: postgres
|
27
27
|
POSTGRES_DB: ruby-pg-extras-test
|
28
28
|
POSTGRES_PASSWORD: secret
|
29
|
+
- image: cimg/postgres:14.2
|
30
|
+
command: postgres -c shared_preload_libraries=pg_stat_statements
|
31
|
+
name: postgres14
|
32
|
+
environment:
|
33
|
+
POSTGRES_USER: postgres
|
34
|
+
POSTGRES_DB: ruby-pg-extras-test
|
35
|
+
POSTGRES_PASSWORD: secret
|
29
36
|
parallelism: 1
|
30
37
|
steps:
|
31
38
|
- checkout
|
@@ -51,6 +58,11 @@ jobs:
|
|
51
58
|
environment:
|
52
59
|
DATABASE_URL: postgresql://postgres:secret@postgres13:5432/ruby-pg-extras-test
|
53
60
|
command: bundle exec rspec spec/
|
61
|
+
- run:
|
62
|
+
name: Run specs for PG 14
|
63
|
+
environment:
|
64
|
+
DATABASE_URL: postgresql://postgres:secret@postgres14:5432/ruby-pg-extras-test
|
65
|
+
command: bundle exec rspec spec/
|
54
66
|
workflows:
|
55
67
|
version: 2
|
56
68
|
test:
|
data/Rakefile
CHANGED
@@ -5,5 +5,5 @@ RSpec::Core::RakeTask.new(:spec)
|
|
5
5
|
|
6
6
|
desc 'Test all PG versions'
|
7
7
|
task :test_all do
|
8
|
-
system("PG_VERSION=11 bundle exec rspec spec/ && PG_VERSION=12 bundle exec rspec spec/ && PG_VERSION=13 bundle exec rspec spec/")
|
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/docker-compose.yml.sample
CHANGED
@@ -2,7 +2,7 @@ version: '3'
|
|
2
2
|
|
3
3
|
services:
|
4
4
|
postgres11:
|
5
|
-
image: postgres:11.
|
5
|
+
image: postgres:11.16-alpine
|
6
6
|
command: postgres -c shared_preload_libraries=pg_stat_statements
|
7
7
|
environment:
|
8
8
|
POSTGRES_USER: postgres
|
@@ -11,7 +11,7 @@ services:
|
|
11
11
|
ports:
|
12
12
|
- '5432:5432'
|
13
13
|
postgres12:
|
14
|
-
image: postgres:12.
|
14
|
+
image: postgres:12.11-alpine
|
15
15
|
command: postgres -c shared_preload_libraries=pg_stat_statements
|
16
16
|
environment:
|
17
17
|
POSTGRES_USER: postgres
|
@@ -20,7 +20,7 @@ services:
|
|
20
20
|
ports:
|
21
21
|
- '5433:5432'
|
22
22
|
postgres13:
|
23
|
-
image: postgres:13.
|
23
|
+
image: postgres:13.7-alpine
|
24
24
|
command: postgres -c shared_preload_libraries=pg_stat_statements
|
25
25
|
environment:
|
26
26
|
POSTGRES_USER: postgres
|
@@ -28,3 +28,12 @@ services:
|
|
28
28
|
POSTGRES_PASSWORD: secret
|
29
29
|
ports:
|
30
30
|
- '5434:5432'
|
31
|
+
postgres14:
|
32
|
+
image: postgres:14.3-alpine
|
33
|
+
command: postgres -c shared_preload_libraries=pg_stat_statements
|
34
|
+
environment:
|
35
|
+
POSTGRES_USER: postgres
|
36
|
+
POSTGRES_DB: ruby-pg-extras-test
|
37
|
+
POSTGRES_PASSWORD: secret
|
38
|
+
ports:
|
39
|
+
- '5435:5432'
|
data/lib/ruby-pg-extras.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'filesize'
|
4
|
-
|
5
3
|
module RubyPgExtras
|
6
4
|
class DiagnoseData
|
7
5
|
PG_EXTRAS_TABLE_CACHE_HIT_MIN_EXPECTED = "0.985"
|
8
6
|
PG_EXTRAS_INDEX_CACHE_HIT_MIN_EXPECTED = "0.985"
|
9
7
|
PG_EXTRAS_UNUSED_INDEXES_MAX_SCANS = 20
|
10
|
-
PG_EXTRAS_UNUSED_INDEXES_MIN_SIZE_BYTES =
|
8
|
+
PG_EXTRAS_UNUSED_INDEXES_MIN_SIZE_BYTES = SizeParser.to_i("1 MB") # 1000000 bytes
|
11
9
|
PG_EXTRAS_NULL_INDEXES_MIN_SIZE_MB = 1 # 1 MB
|
12
10
|
PG_EXTRAS_NULL_MIN_NULL_FRAC_PERCENT = 50 # 50%
|
13
11
|
PG_EXTRAS_BLOAT_MIN_VALUE = 10
|
@@ -118,7 +116,7 @@ module RubyPgExtras
|
|
118
116
|
in_format: :hash,
|
119
117
|
args: { min_scans: PG_EXTRAS_UNUSED_INDEXES_MAX_SCANS }
|
120
118
|
).select do |i|
|
121
|
-
|
119
|
+
SizeParser.to_i(i.fetch("index_size").strip) >= PG_EXTRAS_UNUSED_INDEXES_MIN_SIZE_BYTES
|
122
120
|
end
|
123
121
|
|
124
122
|
if indexes.count == 0
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyPgExtras
|
4
|
+
class SizeParser
|
5
|
+
def self.to_i(arg)
|
6
|
+
value = to_i_si(arg) || to_i_binary(arg) || to_i_digits(arg)
|
7
|
+
raise ArgumentError, "Unparseable size: #{arg}" if value.nil?
|
8
|
+
|
9
|
+
value
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.regexp_for_units(units)
|
13
|
+
/\A(-?\d+)\s?(#{units.join('|')})\z/i
|
14
|
+
end
|
15
|
+
|
16
|
+
SI_UNITS = %w[bytes kB MB GB TB PB EB ZB YB].map(&:downcase).freeze
|
17
|
+
SI_REGEXP = regexp_for_units(SI_UNITS)
|
18
|
+
|
19
|
+
def self.to_i_si(arg)
|
20
|
+
to_i_for_units(arg, SI_REGEXP, SI_UNITS, 1000)
|
21
|
+
end
|
22
|
+
|
23
|
+
BINARY_UNITS = %w[bytes KiB MiB GiB TiB PiB EiB ZiB YiB].map(&:downcase).freeze
|
24
|
+
BINARY_REGEXP = regexp_for_units(BINARY_UNITS)
|
25
|
+
|
26
|
+
def self.to_i_binary(arg)
|
27
|
+
to_i_for_units(arg, BINARY_REGEXP, BINARY_UNITS, 1024)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.to_i_for_units(arg, regexp, units, multiplier)
|
31
|
+
match_data = regexp.match(arg)
|
32
|
+
return nil unless match_data
|
33
|
+
|
34
|
+
exponent = units.index(match_data[2].downcase).to_i
|
35
|
+
match_data[1].to_i * multiplier**exponent
|
36
|
+
end
|
37
|
+
|
38
|
+
DIGITS_ONLY_REGEXP = /\A(-?\d+)\z/.freeze
|
39
|
+
def self.to_i_digits(arg)
|
40
|
+
DIGITS_ONLY_REGEXP.match?(arg) ? arg.to_i : nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/ruby-pg-extras.gemspec
CHANGED
@@ -0,0 +1,167 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe RubyPgExtras::SizeParser do
|
6
|
+
subject(:result) { described_class.to_i(arg) }
|
7
|
+
|
8
|
+
describe 'SI Units' do
|
9
|
+
let(:arg) { "#{num_units} #{unit}" }
|
10
|
+
|
11
|
+
context "when the argument is a number followed by 'bytes', with possible case variations" do
|
12
|
+
let(:num_units) { rand(1000) }
|
13
|
+
let(:unit) { %w[bytes BYTES Bytes].sample }
|
14
|
+
|
15
|
+
it { is_expected.to eq(num_units) }
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when the argument is a number followed by 'kB', with possible case variations" do
|
19
|
+
let(:num_units) { rand(1000) }
|
20
|
+
let(:unit) { %w[kB kb KB].sample }
|
21
|
+
|
22
|
+
it { is_expected.to eq(num_units * 1000) }
|
23
|
+
end
|
24
|
+
|
25
|
+
context "when the argument is a number followed by 'MB', with possible case variations" do
|
26
|
+
let(:num_units) { rand(1000) }
|
27
|
+
let(:unit) { %w[MB Mb mb].sample }
|
28
|
+
|
29
|
+
it { is_expected.to eq(num_units * 1000 * 1000) }
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when the argument is a number followed by 'GB', with possible case variations" do
|
33
|
+
let(:num_units) { rand(1000) }
|
34
|
+
let(:unit) { %w[GB Gb gb].sample }
|
35
|
+
|
36
|
+
it { is_expected.to eq(num_units * 1000 * 1000 * 1000) }
|
37
|
+
end
|
38
|
+
|
39
|
+
context "when the argument is a number followed by 'TB', with possible case variations" do
|
40
|
+
let(:num_units) { rand(1000) }
|
41
|
+
let(:unit) { %w[TB Tb tb].sample }
|
42
|
+
|
43
|
+
it { is_expected.to eq(num_units * 1000 * 1000 * 1000 * 1000) }
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when the argument is a number followed by 'PB', with possible case variations" do
|
47
|
+
let(:num_units) { rand(1000) }
|
48
|
+
let(:unit) { %w[PB Pb pb].sample }
|
49
|
+
|
50
|
+
it { is_expected.to eq(num_units * 1000 * 1000 * 1000 * 1000 * 1000) }
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when the argument is a number followed by 'EB', with possible case variations" do
|
54
|
+
let(:num_units) { rand(1000) }
|
55
|
+
let(:unit) { %w[EB Eb eb].sample }
|
56
|
+
|
57
|
+
it { is_expected.to eq(num_units * 1000 * 1000 * 1000 * 1000 * 1000 * 1000) }
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when the argument is a number followed by 'ZB', with possible case variations" do
|
61
|
+
let(:num_units) { 912 }
|
62
|
+
let(:unit) { %w[ZB Zb zb].sample }
|
63
|
+
|
64
|
+
it { is_expected.to eq(num_units * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000) }
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when the argument is a number followed by 'YB', with possible case variations" do
|
68
|
+
let(:num_units) { 912 }
|
69
|
+
let(:unit) { %w[YB Yb yb].sample }
|
70
|
+
|
71
|
+
it { is_expected.to eq(num_units * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000) }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'Binary Units' do
|
76
|
+
let(:arg) { "#{num_units} #{unit}" }
|
77
|
+
|
78
|
+
context "when the argument is a number followed by 'bytes', with possible case variations" do
|
79
|
+
let(:num_units) { rand(1000) }
|
80
|
+
let(:unit) { %w[bytes BYTES Bytes].sample }
|
81
|
+
|
82
|
+
it { is_expected.to eq(num_units) }
|
83
|
+
end
|
84
|
+
|
85
|
+
context "when the argument is a number followed by 'kiB', with possible case variations" do
|
86
|
+
let(:num_units) { rand(1000) }
|
87
|
+
let(:unit) { %w[kiB kib KiB].sample }
|
88
|
+
|
89
|
+
it { is_expected.to eq(num_units * 1024) }
|
90
|
+
end
|
91
|
+
|
92
|
+
context "when the argument is a number followed by 'MiB', with possible case variations" do
|
93
|
+
let(:num_units) { rand(1000) }
|
94
|
+
let(:unit) { %w[MiB Mib mib].sample }
|
95
|
+
|
96
|
+
it { is_expected.to eq(num_units * 1024 * 1024) }
|
97
|
+
end
|
98
|
+
|
99
|
+
context "when the argument is a number followed by 'GiB', with possible case variations" do
|
100
|
+
let(:num_units) { rand(1000) }
|
101
|
+
let(:unit) { %w[GiB Gib gib].sample }
|
102
|
+
|
103
|
+
it { is_expected.to eq(num_units * 1024 * 1024 * 1024) }
|
104
|
+
end
|
105
|
+
|
106
|
+
context "when the argument is a number followed by 'TiB', with possible case variations" do
|
107
|
+
let(:num_units) { rand(1000) }
|
108
|
+
let(:unit) { %w[TiB Tib tib].sample }
|
109
|
+
|
110
|
+
it { is_expected.to eq(num_units * 1024 * 1024 * 1024 * 1024) }
|
111
|
+
end
|
112
|
+
|
113
|
+
context "when the argument is a number followed by 'PiB', with possible case variations" do
|
114
|
+
let(:num_units) { rand(1000) }
|
115
|
+
let(:unit) { %w[PiB Pib pib].sample }
|
116
|
+
|
117
|
+
it { is_expected.to eq(num_units * 1024 * 1024 * 1024 * 1024 * 1024) }
|
118
|
+
end
|
119
|
+
|
120
|
+
context "when the argument is a number followed by 'EiB', with possible case variations" do
|
121
|
+
let(:num_units) { rand(1000) }
|
122
|
+
let(:unit) { %w[EiB Eib eib].sample }
|
123
|
+
|
124
|
+
it { is_expected.to eq(num_units * 1024 * 1024 * 1024 * 1024 * 1024 * 1024) }
|
125
|
+
end
|
126
|
+
|
127
|
+
context "when the argument is a number followed by 'ZB', with possible case variations" do
|
128
|
+
let(:num_units) { 912 }
|
129
|
+
let(:unit) { %w[ZiB Zib zib].sample }
|
130
|
+
|
131
|
+
it { is_expected.to eq(num_units * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024) }
|
132
|
+
end
|
133
|
+
|
134
|
+
context "when the argument is a number followed by 'YB', with possible case variations" do
|
135
|
+
let(:num_units) { 912 }
|
136
|
+
let(:unit) { %w[YiB Yib yib].sample }
|
137
|
+
|
138
|
+
it { is_expected.to eq(num_units * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024) }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'when the argument has only digits' do
|
143
|
+
let(:arg) { '654245' }
|
144
|
+
|
145
|
+
it { is_expected.to eq(arg.to_i) }
|
146
|
+
end
|
147
|
+
|
148
|
+
describe 'errors' do
|
149
|
+
it 'raises an error when the argument has an invalid prefix' do
|
150
|
+
expect do
|
151
|
+
described_class.to_i('123 qb')
|
152
|
+
end.to raise_error ArgumentError
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'raises an error when the argument does not have a unit in bytes' do
|
156
|
+
expect do
|
157
|
+
described_class.to_i('123 mL')
|
158
|
+
end.to raise_error ArgumentError
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'when the argument cannot be parsed an number of units' do
|
162
|
+
expect do
|
163
|
+
described_class.to_i('1c3 MB')
|
164
|
+
end.to raise_error ArgumentError
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
data/spec/spec_helper.rb
CHANGED
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: 4.
|
4
|
+
version: 4.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- pawurb
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-06-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: filesize
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: terminal-table
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -138,6 +124,7 @@ files:
|
|
138
124
|
- lib/ruby_pg_extras/queries/total_table_size.sql
|
139
125
|
- lib/ruby_pg_extras/queries/unused_indexes.sql
|
140
126
|
- lib/ruby_pg_extras/queries/vacuum_stats.sql
|
127
|
+
- lib/ruby_pg_extras/size_parser.rb
|
141
128
|
- lib/ruby_pg_extras/table_info.rb
|
142
129
|
- lib/ruby_pg_extras/table_info_print.rb
|
143
130
|
- lib/ruby_pg_extras/version.rb
|
@@ -146,6 +133,7 @@ files:
|
|
146
133
|
- spec/diagnose_data_spec.rb
|
147
134
|
- spec/diagnose_print_spec.rb
|
148
135
|
- spec/index_info_spec.rb
|
136
|
+
- spec/size_parser_spec.rb
|
149
137
|
- spec/smoke_spec.rb
|
150
138
|
- spec/spec_helper.rb
|
151
139
|
- spec/table_info_spec.rb
|
@@ -177,6 +165,7 @@ test_files:
|
|
177
165
|
- spec/diagnose_data_spec.rb
|
178
166
|
- spec/diagnose_print_spec.rb
|
179
167
|
- spec/index_info_spec.rb
|
168
|
+
- spec/size_parser_spec.rb
|
180
169
|
- spec/smoke_spec.rb
|
181
170
|
- spec/spec_helper.rb
|
182
171
|
- spec/table_info_spec.rb
|