ruby-pg-extras 4.5.1 → 4.7.1

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: 3a9ada0be2b417c1579a57fa5470a153036beb6e1381c633ba39a0d0004ef55b
4
+ data.tar.gz: 7cf0925b3506be4de603fb6b8d4c7891e56e56acfc838b0bc8916a65d42a6a5e
5
5
  SHA512:
6
- metadata.gz: '083ed61d5ab3804b90416da21b11e4463efda2e2e81dbd457b60bbb31bbb165ef2e097d1eb65114437a87e54c6aa434e214630c3652f47871a3ac40b3bb4eb88'
7
- data.tar.gz: 8451042b71129d99672ad90d6906c31bee8181ba4e0acc12af68b85ab14a9f5eac19e2ecea7dd485fc7b7738b02f2d8df3c8d74b26e976f087cd906ac1b9ac2d
6
+ metadata.gz: a4b6e4fe8da7a37fa23b9e4a58689f85708ce80fb057d1dce7c3f8846a5882feee68122632542dc1581b2bcab6784dcbe44742c1f8426b75bb79bd3b1e156a3d
7
+ data.tar.gz: b18bc1dbf06d7f7d10e57cc6d6c84cab8cba3d75d993d725b030c435c2f4c8dfc17087d2bd5d5a6e86787592531cf4dda575f5c70f237511d4cbd48c58426dd4
data/.circleci/config.yml CHANGED
@@ -2,39 +2,47 @@ version: 2
2
2
  jobs:
3
3
  test:
4
4
  docker:
5
- - image: circleci/ruby:2.6.5
5
+ - image: cimg/ruby:2.7.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
32
39
  - run: gem update --system
33
40
  - run: gem install bundler
34
- - run: bundle config set --local path 'vendor/bundle'
35
- - run: bundle install
36
41
  - run: sudo apt-get update --allow-releaseinfo-change
37
42
  - run: sudo apt install postgresql-client
43
+ - run: sudo apt install libpq-dev
44
+ - run: bundle config set --local path 'vendor/bundle'
45
+ - run: bundle install
38
46
  - run: dockerize -wait tcp://postgres11:5432 -timeout 1m
39
47
  - run:
40
48
  name: Run specs for PG 11
@@ -51,6 +59,11 @@ jobs:
51
59
  environment:
52
60
  DATABASE_URL: postgresql://postgres:secret@postgres13:5432/ruby-pg-extras-test
53
61
  command: bundle exec rspec spec/
62
+ - run:
63
+ name: Run specs for PG 14
64
+ environment:
65
+ DATABASE_URL: postgresql://postgres:secret@postgres14:5432/ruby-pg-extras-test
66
+ command: bundle exec rspec spec/
54
67
  workflows:
55
68
  version: 2
56
69
  test:
data/README.md CHANGED
@@ -255,14 +255,14 @@ This command provides information on the efficiency of indexes, represented as w
255
255
 
256
256
  RubyPgExtras.locks
257
257
 
258
- procpid | relname | transactionid | granted | query_snippet | mode | age
259
- ---------+---------+---------------+---------+-----------------------+-------------------------------------
260
- 31776 | | | t | <IDLE> in transaction | ExclusiveLock | 00:19:29.837898
261
- 31776 | | 1294 | t | <IDLE> in transaction | RowExclusiveLock | 00:19:29.837898
262
- 31912 | | | t | select * from hello; | ExclusiveLock | 00:19:17.94259
263
- 3443 | | | t | +| ExclusiveLock | 00:00:00
264
- | | | | select +| |
265
- | | | | pg_stat_activi | |
258
+ procpid | relname | transactionid | granted | query_snippet | mode | age | application |
259
+ ---------+---------+---------------+---------+-----------------------+------------------------------------------------------
260
+ 31776 | | | t | <IDLE> in transaction | ExclusiveLock | 00:19:29.837898 | bin/rails
261
+ 31776 | | 1294 | t | <IDLE> in transaction | RowExclusiveLock | 00:19:29.837898 | bin/rails
262
+ 31912 | | | t | select * from hello; | ExclusiveLock | 00:19:17.94259 | bin/rails
263
+ 3443 | | | t | +| ExclusiveLock | 00:00:00 | bin/sidekiq
264
+ | | | | select +| | |
265
+ | | | | pg_stat_activi | | |
266
266
  (4 rows)
267
267
  ```
268
268
 
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
@@ -7,7 +7,8 @@ SELECT
7
7
  pg_locks.granted,
8
8
  pg_locks.mode,
9
9
  pg_stat_activity.query AS query_snippet,
10
- age(now(),pg_stat_activity.query_start) AS "age"
10
+ age(now(),pg_stat_activity.query_start) AS "age",
11
+ pg_stat_activity.application_name AS application
11
12
  FROM pg_stat_activity,pg_locks left
12
13
  OUTER JOIN pg_class
13
14
  ON (pg_locks.relation = pg_class.oid)
@@ -7,7 +7,8 @@ SELECT
7
7
  pg_locks.granted,
8
8
  pg_locks.mode,
9
9
  pg_stat_activity.query AS query_snippet,
10
- age(now(),pg_stat_activity.query_start) AS "age"
10
+ age(now(),pg_stat_activity.query_start) AS "age",
11
+ pg_stat_activity.application_name AS application
11
12
  FROM pg_stat_activity,pg_locks left
12
13
  OUTER JOIN pg_class
13
14
  ON (pg_locks.relation = pg_class.oid)
@@ -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.7.1"
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.7.1
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-07-08 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