activerecord-pg-extensions 0.2.2 → 0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39407cedf031029bddd4c9cae80f64da4b635388610a5ed8437cfd7bd1248abd
4
- data.tar.gz: 52f6fe2e76431bb4ae3420256ea2a168123641df2c4a851e61e147196d271be1
3
+ metadata.gz: ca67149b2f8917743b8258c14b7d2e393673093d02956a192ce40ed7857efa89
4
+ data.tar.gz: df37221b1ba08633bcb1d059ae296c4f83ec2025e6ad35eb87aaf50c7fdbaf39
5
5
  SHA512:
6
- metadata.gz: b67e8b140d12e4cfec7746f764daa05a613aa71bcb378b7f87a19c96ca12c7715e36ec2706e238d511bcc7377fedd4348e4657f11f1c2af47c61e17688c62ea9
7
- data.tar.gz: 248bacb94d750ac4def26b48fb2e6c86637bd874195904153cc346b224e2b919cc3f6577a9b77637ffa788e4caa2a83244760264c27463886f159e64a71e1103
6
+ metadata.gz: 60739ca5ec1d417e709792231bc06b65af4f6d2e6cac2a883a725bc5acd553d901a2d7c2d9b7da2e1a592f2f66635e740d668070a05551ffcfbefff3b4102dba
7
+ data.tar.gz: 6e34ef248fb441a9dcbdd60e4a2566e9010b01900b7802c33653e77744c9d7c9d33a65f78649118beb20bdc1fc283775232a7b834d4d514a3c8ea797d7698ee4
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.4.0] - 2021-09-29
4
+
5
+ - Deprecate with_statement_timeout
6
+ - Add statement_timeout, lock_timeout, and idle_in_transaction_session_timeout
7
+ ## [0.2.3] - 2021-06-23
8
+
9
+ - Fix extension_available?
10
+
3
11
  ## [0.2.2] - 2021-06-22
4
12
 
5
13
  - Fix bug in Ruby 2.6 calling format wrong.
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ # @deprecated just use QueryCanceled
5
+ QueryTimeout = QueryCanceled
6
+ end
@@ -6,20 +6,36 @@ module ActiveRecord
6
6
  # to executing, in order to reduce the amount of time the actual DDL takes to
7
7
  # execute (and thus how long it needs the lock)
8
8
  module PessimisticMigrations
9
- # does a query first to warm the db cache, to make the actual constraint adding fast
9
+ # adds a temporary check constraint to reduce locking when changing to NOT NULL, and we're not in a transaction
10
10
  def change_column_null(table, column, nullness, default = nil)
11
- # no point in pre-warming the cache to avoid locking if we're already in a transaction
11
+ # no point in doing extra work to avoid locking if we're already in a transaction
12
12
  return super if nullness != false || open_transactions.positive?
13
+ return if columns(table).find { |c| c.name == column.to_s }&.null == false
14
+
15
+ temp_constraint_name = "chk_rails_#{table}_#{column}_not_null"
16
+ scope = quoted_scope(temp_constraint_name)
17
+ # check for temp constraint
18
+ valid = select_value(<<~SQL, "SCHEMA")
19
+ SELECT convalidated FROM pg_constraint INNER JOIN pg_namespace ON pg_namespace.oid=connamespace WHERE conname=#{scope[:name]} AND nspname=#{scope[:schema]}
20
+ SQL
21
+ if valid.nil?
22
+ add_check_constraint(table,
23
+ "#{quote_column_name(column)} IS NOT NULL",
24
+ name: temp_constraint_name,
25
+ validate: false)
26
+ end
27
+ begin
28
+ validate_constraint(table, temp_constraint_name)
29
+ rescue ActiveRecord::StatementInvalid => e
30
+ raise ActiveRecord::NotNullViolation.new(sql: e.sql, binds: e.binds) if e.cause.is_a?(PG::CheckViolation)
31
+
32
+ raise
33
+ end
13
34
 
14
35
  transaction do
15
- # make sure the query ignores indexes, because the actual ALTER TABLE will also ignore
16
- # indexes
17
- execute("SET LOCAL enable_indexscan=off")
18
- execute("SET LOCAL enable_bitmapscan=off")
19
- execute("SELECT COUNT(*) FROM #{quote_table_name(table)} WHERE #{quote_column_name(column)} IS NULL")
20
- raise ActiveRecord::Rollback
36
+ super
37
+ remove_check_constraint(table, name: temp_constraint_name)
21
38
  end
22
- super
23
39
  end
24
40
 
25
41
  # several improvements:
@@ -47,6 +47,7 @@ module ActiveRecord
47
47
  sql << " VERSION #{quote(version)}" if version
48
48
  sql << " CASCADE" if cascade
49
49
  execute(sql)
50
+ reload_type_map
50
51
  @extensions&.delete(extension.to_s)
51
52
  end
52
53
 
@@ -61,6 +62,7 @@ module ActiveRecord
61
62
  sql << " TO #{quote(version)}" if version && version != true
62
63
  sql << " SET SCHEMA #{schema}" if schema
63
64
  execute(sql)
65
+ reload_type_map
64
66
  @extensions&.delete(extension.to_s)
65
67
  end
66
68
 
@@ -73,13 +75,14 @@ module ActiveRecord
73
75
  sql << extensions.join(", ")
74
76
  sql << " CASCADE" if cascade
75
77
  execute(sql)
78
+ reload_type_map
76
79
  @extensions&.except!(*extensions.map(&:to_s))
77
80
  end
78
81
 
79
82
  # check if a particular extension can be installed
80
83
  def extension_available?(extension, version = nil)
81
84
  sql = +"SELECT 1 FROM "
82
- sql << version ? "pg_available_extensions" : "pg_available_extension_versions"
85
+ sql << (version ? "pg_available_extension_versions" : "pg_available_extensions")
83
86
  sql << " WHERE name=#{quote(extension)}"
84
87
  sql << " AND version=#{quote(version)}" if version
85
88
  select_value(sql).to_i == 1
@@ -233,6 +236,56 @@ module ActiveRecord
233
236
  select_value("SELECT pg_is_in_recovery()")
234
237
  end
235
238
 
239
+ def set(configuration_parameter, value, local: false)
240
+ value = value.nil? ? "DEFAULT" : quote(value)
241
+ execute("SET#{' LOCAL' if local} #{configuration_parameter} TO #{value}")
242
+ end
243
+
244
+ def reset(configuration_parameter)
245
+ execute("RESET #{configuration_parameter}")
246
+ end
247
+
248
+ TIMEOUTS = %i[lock_timeout statement_timeout idle_in_transaction_session_timeout].freeze
249
+
250
+ TIMEOUTS.each do |kind|
251
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
252
+ def #{kind}
253
+ current_transaction.#{kind}
254
+ end
255
+
256
+ def #{kind}=(timeout)
257
+ raise ArgumentError, "Timeouts can only be set inside of a transaction" unless current_transaction.open?
258
+
259
+ current_transaction.send(:#{kind}=, timeout)
260
+ end
261
+ RUBY
262
+ end
263
+
264
+ # @deprecated: manage the transaction yourself and set statement_timeout directly
265
+ #
266
+ # otherwise, if you're already in a transaction, or you nest with_statement_timeout,
267
+ # the value will unexpectedly "stick" even after the block returns
268
+ def with_statement_timeout(timeout)
269
+ timeout = 30 if timeout.nil? || timeout == true
270
+
271
+ transaction do
272
+ self.statement_timeout = timeout
273
+ yield
274
+ end
275
+ end
276
+
277
+ unless ::Rails.version >= "6.1"
278
+ def add_check_constraint(table_name, expression, name:, validate: true)
279
+ sql = +"ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{quote_column_name(name)} CHECK (#{expression})" # rubocop:disable Layout/LineLength
280
+ sql << " NOT VALID" unless validate
281
+ execute(sql)
282
+ end
283
+
284
+ def remove_check_constraint(table_name, name:)
285
+ execute("ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(name)}")
286
+ end
287
+ end
288
+
236
289
  private
237
290
 
238
291
  if ::Rails.version < "6.1"
@@ -8,9 +8,13 @@ module ActiveRecord
8
8
  class Railtie < Rails::Railtie
9
9
  initializer "pg_extensions.extend_ar", after: "active_record.initialize_database" do
10
10
  ActiveSupport.on_load(:active_record) do
11
+ require "active_record/pg_extensions/errors"
11
12
  require "active_record/pg_extensions/postgresql_adapter"
13
+ require "active_record/pg_extensions/transaction"
12
14
 
13
- ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(PostgreSQLAdapter)
15
+ ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(PostgreSQLAdapter)
16
+ ::ActiveRecord::ConnectionAdapters::NullTransaction.prepend(NullTransaction)
17
+ ::ActiveRecord::ConnectionAdapters::Transaction.prepend(Transaction)
14
18
  # if they've already require 'all', then inject now
15
19
  defined?(All) && All.inject
16
20
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module PGExtensions
5
+ # Contains general additions to Transaction
6
+ module Transaction
7
+ PostgreSQLAdapter::TIMEOUTS.each do |kind|
8
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
9
+ def #{kind}(local: false)
10
+ return @#{kind} if local
11
+ @#{kind} || parent_transaction.#{kind}
12
+ end
13
+
14
+ private def #{kind}=(timeout)
15
+ return if @#{kind} == timeout
16
+
17
+ @#{kind} = timeout
18
+ return unless materialized?
19
+ connection.set(#{kind.inspect}, "\#{(timeout * 1000).to_i}ms", local: true)
20
+ end
21
+ RUBY
22
+ end
23
+
24
+ def materialize!
25
+ PostgreSQLAdapter::TIMEOUTS.each do |kind|
26
+ next if (timeout = send(kind, local: true)).nil?
27
+
28
+ connection.set(kind, "#{(timeout * 1000).to_i}ms", local: true)
29
+ end
30
+ super
31
+ end
32
+ end
33
+
34
+ # Contains general additions to NullTransaction
35
+ module NullTransaction
36
+ PostgreSQLAdapter::TIMEOUTS.each do |kind|
37
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
38
+ def #{kind}
39
+ nil
40
+ end
41
+ RUBY
42
+ end
43
+ end
44
+ end
45
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module PGExtensions
5
- VERSION = "0.2.2"
5
+ VERSION = "0.4.1"
6
6
  end
7
7
  end
@@ -6,32 +6,61 @@ describe ActiveRecord::PGExtensions::PessimisticMigrations do
6
6
  end
7
7
 
8
8
  describe "#change_column_null" do
9
+ # Rails 6.1 doesn't quote the constraint name when adding a check constraint??
10
+ def quote_constraint_name(name)
11
+ Rails.version >= "6.1" ? name : connection.quote_column_name(name)
12
+ end
13
+
9
14
  it "does nothing extra when changing a column to nullable" do
10
15
  connection.change_column_null(:table, :column, true)
11
16
  expect(connection.executed_statements).to eq ['ALTER TABLE "table" ALTER COLUMN "column" DROP NOT NULL']
12
17
  end
13
18
 
14
- it "pre-warms the cache" do
19
+ it "does nothing if we're in a transaction" do
20
+ connection.transaction do
21
+ connection.change_column_null(:table, :column, true)
22
+ end
23
+ expect(connection.executed_statements).to eq ["BEGIN",
24
+ 'ALTER TABLE "table" ALTER COLUMN "column" DROP NOT NULL',
25
+ "COMMIT"]
26
+ end
27
+
28
+ it "skips entirely if the column is already NOT NULL" do
29
+ expect(connection).to receive(:columns).with(:table).and_return([double(name: "column", null: false)])
15
30
  connection.change_column_null(:table, :column, false)
16
- expect(connection.executed_statements).to eq(
17
- ["BEGIN",
18
- "SET LOCAL enable_indexscan=off",
19
- "SET LOCAL enable_bitmapscan=off",
20
- 'SELECT COUNT(*) FROM "table" WHERE "column" IS NULL',
21
- "ROLLBACK",
22
- 'ALTER TABLE "table" ALTER COLUMN "column" SET NOT NULL']
23
- )
31
+ expect(connection.executed_statements).to eq([])
24
32
  end
25
33
 
26
- it "does nothing extra if a transaction is already active" do
27
- connection.transaction do
28
- connection.change_column_null(:table, :column, false)
29
- end
30
- expect(connection.executed_statements).to eq(
31
- ["BEGIN",
32
- 'ALTER TABLE "table" ALTER COLUMN "column" SET NOT NULL',
33
- "COMMIT"]
34
- )
34
+ it "adds and removes a check constraint" do
35
+ expect(connection).to receive(:columns).and_return([])
36
+ allow(connection).to receive(:check_constraint_for!).and_return(double(name: "chk_rails_table_column_not_null"))
37
+ connection.change_column_null(:table, :column, false)
38
+
39
+ expect(connection.executed_statements).to eq [
40
+ "SELECT convalidated FROM pg_constraint INNER JOIN pg_namespace ON pg_namespace.oid=connamespace WHERE conname='chk_rails_table_column_not_null' AND nspname=ANY (current_schemas(false))\n", # rubocop:disable Layout/LineLength
41
+ %{ALTER TABLE "table" ADD CONSTRAINT #{quote_constraint_name('chk_rails_table_column_not_null')} CHECK ("column" IS NOT NULL) NOT VALID}, # rubocop:disable Layout/LineLength
42
+ 'ALTER TABLE "table" VALIDATE CONSTRAINT "chk_rails_table_column_not_null"',
43
+ "BEGIN",
44
+ 'ALTER TABLE "table" ALTER COLUMN "column" SET NOT NULL',
45
+ 'ALTER TABLE "table" DROP CONSTRAINT "chk_rails_table_column_not_null"',
46
+ "COMMIT"
47
+ ]
48
+ end
49
+
50
+ it "verifies an existing check constraint" do
51
+ expect(connection).to receive(:columns).and_return([])
52
+ allow(connection).to receive(:check_constraint_for!).and_return(double(name: "chk_rails_table_column_not_null"))
53
+ expect(connection).to receive(:select_value).and_return(false)
54
+ connection.change_column_null(:table, :column, false)
55
+
56
+ expect(connection.executed_statements).to eq [
57
+ # stubbed out <check constraint valid>
58
+ 'ALTER TABLE "table" VALIDATE CONSTRAINT "chk_rails_table_column_not_null"',
59
+ "BEGIN",
60
+ 'ALTER TABLE "table" ALTER COLUMN "column" SET NOT NULL',
61
+ 'ALTER TABLE "table" DROP CONSTRAINT "chk_rails_table_column_not_null"',
62
+ "COMMIT"
63
+ ]
35
64
  end
36
65
  end
37
66
 
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  describe ActiveRecord::ConnectionAdapters::PostgreSQLAdapter do
4
+ before do
5
+ allow(connection).to receive(:reload_type_map)
6
+ end
7
+
4
8
  describe "#set_constraints" do
5
9
  around do |example|
6
10
  connection.dont_execute(&example)
@@ -131,6 +135,20 @@ describe ActiveRecord::ConnectionAdapters::PostgreSQLAdapter do
131
135
  it "does not allow dropping no extensions" do
132
136
  expect { connection.drop_extension }.to raise_error(ArgumentError)
133
137
  end
138
+
139
+ describe "#extension_available?" do
140
+ it "works with no version constraint" do
141
+ connection.extension_available?(:postgis)
142
+ expect(connection.executed_statements).to eq ["SELECT 1 FROM pg_available_extensions WHERE name='postgis'"]
143
+ end
144
+
145
+ it "works with a version constraint" do
146
+ connection.extension_available?(:postgis, "2.0")
147
+ expect(connection.executed_statements).to eq(
148
+ ["SELECT 1 FROM pg_available_extension_versions WHERE name='postgis' AND version='2.0'"]
149
+ )
150
+ end
151
+ end
134
152
  end
135
153
  end
136
154
 
@@ -250,4 +268,190 @@ describe ActiveRecord::ConnectionAdapters::PostgreSQLAdapter do
250
268
  end
251
269
  end
252
270
  end
271
+
272
+ describe "#with_statement_timeout" do
273
+ around do |example|
274
+ # these specs were written before we supported deferring setting timeouts
275
+ # until the transaction materializes
276
+ connection.disable_lazy_transactions!
277
+ example.call
278
+ connection.enable_lazy_transactions!
279
+ end
280
+
281
+ it "stops long-running queries" do
282
+ expect do
283
+ connection.with_statement_timeout(0.01) do
284
+ connection.execute("SELECT pg_sleep(3)")
285
+ end
286
+ end.to raise_error(ActiveRecord::QueryCanceled)
287
+ end
288
+
289
+ it "re-raises other errors" do
290
+ expect do
291
+ connection.with_statement_timeout(1) do
292
+ connection.execute("bad sql")
293
+ end
294
+ end.to(raise_error { |e| expect(e.cause).to be_a(PG::SyntaxError) })
295
+ end
296
+
297
+ context "without executing" do
298
+ around do |example|
299
+ connection.dont_execute(&example)
300
+ end
301
+
302
+ it "converts integer to ms" do
303
+ connection.with_statement_timeout(30) { nil }
304
+ expect(connection.executed_statements).to eq(
305
+ [
306
+ "BEGIN",
307
+ "SET LOCAL statement_timeout TO '30000ms'",
308
+ "COMMIT"
309
+ ]
310
+ )
311
+ end
312
+
313
+ it "converts float to ms" do
314
+ connection.with_statement_timeout(5.5) { nil }
315
+ expect(connection.executed_statements).to eq(
316
+ [
317
+ "BEGIN",
318
+ "SET LOCAL statement_timeout TO '5500ms'",
319
+ "COMMIT"
320
+ ]
321
+ )
322
+ end
323
+
324
+ it "converts ActiveSupport::Duration to ms" do
325
+ connection.with_statement_timeout(5.seconds) { nil }
326
+ expect(connection.executed_statements).to eq(
327
+ [
328
+ "BEGIN",
329
+ "SET LOCAL statement_timeout TO '5000ms'",
330
+ "COMMIT"
331
+ ]
332
+ )
333
+ end
334
+
335
+ it "allows true" do
336
+ connection.with_statement_timeout(true) { nil }
337
+ expect(connection.executed_statements).to eq(
338
+ [
339
+ "BEGIN",
340
+ "SET LOCAL statement_timeout TO '30000ms'",
341
+ "COMMIT"
342
+ ]
343
+ )
344
+ end
345
+ end
346
+ end
347
+
348
+ describe "#statement_timeout=" do
349
+ around do |example|
350
+ connection.dont_execute(&example)
351
+ end
352
+
353
+ it "raises if a transaction isn't active" do
354
+ expect { connection.statement_timeout = 30 }.to raise_error(ArgumentError)
355
+ end
356
+
357
+ it "does nothing if the transaction never materializes" do
358
+ connection.transaction do
359
+ connection.statement_timeout = 30
360
+ expect(connection.statement_timeout).to eq 30
361
+ end
362
+ expect(connection.statement_timeout).to be_nil
363
+
364
+ expect(connection.executed_statements).to be_empty
365
+ end
366
+
367
+ it "sets the timeout if the transaction is materialized" do
368
+ connection.transaction do
369
+ connection.select_value("SELECT 1")
370
+ connection.statement_timeout = 30
371
+ expect(connection.statement_timeout).to eq 30
372
+ end
373
+ expect(connection.statement_timeout).to be_nil
374
+
375
+ expect(connection.executed_statements).to eq(
376
+ ["BEGIN",
377
+ "SELECT 1",
378
+ "SET LOCAL statement_timeout TO '30000ms'",
379
+ "COMMIT"]
380
+ )
381
+ end
382
+
383
+ it "sets the timeout if the transaction materializes" do
384
+ connection.transaction do
385
+ connection.statement_timeout = 30
386
+ connection.select_value("SELECT 1")
387
+ expect(connection.statement_timeout).to eq 30
388
+ end
389
+ expect(connection.statement_timeout).to be_nil
390
+
391
+ expect(connection.executed_statements).to eq(
392
+ ["BEGIN",
393
+ "SET LOCAL statement_timeout TO '30000ms'",
394
+ "SELECT 1",
395
+ "COMMIT"]
396
+ )
397
+ end
398
+
399
+ it "works with nested transactions" do
400
+ connection.transaction do
401
+ connection.statement_timeout = 30
402
+ connection.transaction(requires_new: true) do
403
+ connection.statement_timeout = 15
404
+ connection.select_value("SELECT 1")
405
+ expect(connection.statement_timeout).to eq 15
406
+ end
407
+ expect(connection.statement_timeout).to eq 30
408
+ end
409
+ expect(connection.statement_timeout).to be_nil
410
+
411
+ expect(connection.executed_statements).to eq(
412
+ ["BEGIN",
413
+ "SET LOCAL statement_timeout TO '30000ms'",
414
+ "SAVEPOINT active_record_1",
415
+ "SET LOCAL statement_timeout TO '15000ms'",
416
+ "SELECT 1",
417
+ "RELEASE SAVEPOINT active_record_1",
418
+ "COMMIT"]
419
+ )
420
+ end
421
+ end
422
+
423
+ unless Rails.version >= "6.1"
424
+ describe "#add_check_constraint" do
425
+ around do |example|
426
+ connection.dont_execute(&example)
427
+ end
428
+
429
+ it "works" do
430
+ connection.add_check_constraint(:table, "column IS NOT NULL", name: :my_constraint)
431
+ expect(connection.executed_statements).to eq(
432
+ ['ALTER TABLE "table" ADD CONSTRAINT "my_constraint" CHECK (column IS NOT NULL)']
433
+ )
434
+ end
435
+
436
+ it "defers validation" do
437
+ connection.add_check_constraint(:table, "column IS NOT NULL", name: :my_constraint, validate: false)
438
+ expect(connection.executed_statements).to eq(
439
+ ['ALTER TABLE "table" ADD CONSTRAINT "my_constraint" CHECK (column IS NOT NULL) NOT VALID']
440
+ )
441
+ end
442
+ end
443
+
444
+ describe "#remove_check_constraint" do
445
+ around do |example|
446
+ connection.dont_execute(&example)
447
+ end
448
+
449
+ it "works" do
450
+ connection.remove_check_constraint(:table, name: :my_constraint)
451
+ expect(connection.executed_statements).to eq(
452
+ ['ALTER TABLE "table" DROP CONSTRAINT "my_constraint"']
453
+ )
454
+ end
455
+ end
456
+ end
253
457
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-pg-extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Cutrer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-22 00:00:00.000000000 Z
11
+ date: 2021-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -175,10 +175,12 @@ files:
175
175
  - config/database.yml
176
176
  - lib/active_record/pg_extensions.rb
177
177
  - lib/active_record/pg_extensions/all.rb
178
+ - lib/active_record/pg_extensions/errors.rb
178
179
  - lib/active_record/pg_extensions/extension.rb
179
180
  - lib/active_record/pg_extensions/pessimistic_migrations.rb
180
181
  - lib/active_record/pg_extensions/postgresql_adapter.rb
181
182
  - lib/active_record/pg_extensions/railtie.rb
183
+ - lib/active_record/pg_extensions/transaction.rb
182
184
  - lib/active_record/pg_extensions/version.rb
183
185
  - lib/activerecord-pg-extensions.rb
184
186
  - spec/pessimistic_migrations_spec.rb
@@ -204,7 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
204
206
  - !ruby/object:Gem::Version
205
207
  version: '0'
206
208
  requirements: []
207
- rubygems_version: 3.0.3
209
+ rubygems_version: 3.2.24
208
210
  signing_key:
209
211
  specification_version: 4
210
212
  summary: Several extensions to ActiveRecord's PostgreSQLAdapter.