ruby-pg-extras 4.5.1 → 4.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d029c96b61595f277b52f37a747a644943f7569394a9d7bf3e84758397e40174
4
- data.tar.gz: 0f5abfe2d07b9030d0eb768d6e3712d139eecafa9c12d77c4ac51f802bc9f007
3
+ metadata.gz: 250bb1e08a0937724fc2cf90c16d26670218a1c23884fd69f33f7379bb550a20
4
+ data.tar.gz: 12e69c803e3bd48287445bd46451255b3a0074fb3c1d4a0d373bb2d64a98e900
5
5
  SHA512:
6
- metadata.gz: '083ed61d5ab3804b90416da21b11e4463efda2e2e81dbd457b60bbb31bbb165ef2e097d1eb65114437a87e54c6aa434e214630c3652f47871a3ac40b3bb4eb88'
7
- data.tar.gz: 8451042b71129d99672ad90d6906c31bee8181ba4e0acc12af68b85ab14a9f5eac19e2ecea7dd485fc7b7738b02f2d8df3c8d74b26e976f087cd906ac1b9ac2d
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: circleci/ruby:2.6.5
5
+ - image: cimg/ruby:2.6
6
6
  environment:
7
7
  DATABASE_URL: postgresql://postgres:secret@localhost:5432/ruby-pg-extras-test
8
- - image: circleci/postgres:11.5
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: circleci/postgres:12.7
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: circleci/postgres:13.3
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
@@ -2,7 +2,7 @@ version: '3'
2
2
 
3
3
  services:
4
4
  postgres11:
5
- image: postgres:11.5-alpine
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.7-alpine
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.3-alpine
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'
@@ -3,6 +3,7 @@
3
3
  require 'terminal-table'
4
4
  require 'uri'
5
5
  require 'pg'
6
+ require 'ruby_pg_extras/size_parser'
6
7
  require 'ruby_pg_extras/diagnose_data'
7
8
  require 'ruby_pg_extras/diagnose_print'
8
9
  require 'ruby_pg_extras/index_info'
@@ -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 = Filesize.from("1 MB").to_i # 1000000 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
- Filesize.from(i.fetch("index_size").sub("bytes", "").strip).to_i >= PG_EXTRAS_UNUSED_INDEXES_MIN_SIZE_BYTES
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyPgExtras
4
- VERSION = "4.5.1"
4
+ VERSION = "4.6.0"
5
5
  end
@@ -16,7 +16,6 @@ Gem::Specification.new do |s|
16
16
  s.require_paths = ["lib"]
17
17
  s.license = "MIT"
18
18
  s.add_dependency "pg"
19
- s.add_dependency "filesize"
20
19
  s.add_dependency "terminal-table"
21
20
  s.add_development_dependency "rake"
22
21
  s.add_development_dependency "rspec"
@@ -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
@@ -12,6 +12,8 @@ elsif pg_version == "12"
12
12
  "5433"
13
13
  elsif pg_version == "13"
14
14
  "5434"
15
+ elsif pg_version == "14"
16
+ "5435"
15
17
  else
16
18
  "5432"
17
19
  end
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.5.1
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-05-13 00:00:00.000000000 Z
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