activerecord-pg-extensions 0.2.0 → 0.3.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/CHANGELOG.md +13 -0
- data/lib/active_record/pg_extensions/errors.rb +5 -0
- data/lib/active_record/pg_extensions/pessimistic_migrations.rb +25 -9
- data/lib/active_record/pg_extensions/postgresql_adapter.rb +73 -1
- data/lib/active_record/pg_extensions/railtie.rb +2 -1
- data/lib/active_record/pg_extensions/version.rb +1 -1
- data/spec/pessimistic_migrations_spec.rb +49 -20
- data/spec/postgresql_adapter_spec.rb +123 -0
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b240f7e9306ba57d7f52add8cef37ebe735e2f3d900d328d7cfb2e22fe1fcc6
|
4
|
+
data.tar.gz: 04b62ecf9b4c250e2f664f1a0be0c71baac1b6f5d117dc8d45f08bb7b7100459
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c5a1ae9925eb093ea81424574d409186c85ef2474b1cc2a38f388757ff4e94a8b3893ca7e582e5010e8dbe8915a2e499d1600103c12936169d0447703b5c8d68
|
7
|
+
data.tar.gz: 256b8740a417e1bcc84a7edd23663da83543aa412a7221ae2a818721dd04a16b7ccf3f06915cb625d50f95ecb55ccd0719e1d8204441294dd9860ba25cb54b6a
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.2.3] - 2021-06-23
|
4
|
+
|
5
|
+
- Fix extension_available?
|
6
|
+
|
7
|
+
## [0.2.2] - 2021-06-22
|
8
|
+
|
9
|
+
- Fix bug in Ruby 2.6 calling format wrong.
|
10
|
+
|
11
|
+
## [0.2.1] - 2021-06-22
|
12
|
+
|
13
|
+
- Ensure numeric is in the PG type map for Rails 6.0. So that lsn_diff will
|
14
|
+
return a numeric, instead of a string.
|
15
|
+
|
3
16
|
## [0.2.0] - 2021-06-07
|
4
17
|
|
5
18
|
- Add PostgreSQLAdapter#set_replica_identity
|
@@ -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
|
-
#
|
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
|
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
|
-
|
16
|
-
|
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 ? "
|
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,8 +236,77 @@ module ActiveRecord
|
|
233
236
|
select_value("SELECT pg_is_in_recovery()")
|
234
237
|
end
|
235
238
|
|
239
|
+
def with_statement_timeout(timeout = nil)
|
240
|
+
timeout = 30 if timeout.nil? || timeout == true
|
241
|
+
transaction do
|
242
|
+
execute("SET LOCAL statement_timeout=#{(timeout * 1000).to_i}")
|
243
|
+
yield
|
244
|
+
rescue ActiveRecord::StatementInvalid => e
|
245
|
+
raise ActiveRecord::QueryTimeout.new(sql: e.sql, binds: e.binds) if e.cause.is_a?(PG::QueryCanceled)
|
246
|
+
|
247
|
+
raise
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
unless ::Rails.version >= "6.1"
|
252
|
+
def add_check_constraint(table_name, expression, name:, validate: true)
|
253
|
+
sql = +"ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{quote_column_name(name)} CHECK (#{expression})" # rubocop:disable Layout/LineLength
|
254
|
+
sql << " NOT VALID" unless validate
|
255
|
+
execute(sql)
|
256
|
+
end
|
257
|
+
|
258
|
+
def remove_check_constraint(table_name, name:)
|
259
|
+
execute("ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(name)}")
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
236
263
|
private
|
237
264
|
|
265
|
+
if ::Rails.version < "6.1"
|
266
|
+
# significant change: add PG::TextDecoder::Numeric
|
267
|
+
def add_pg_decoders
|
268
|
+
@default_timezone = nil
|
269
|
+
@timestamp_decoder = nil
|
270
|
+
|
271
|
+
coders_by_name = {
|
272
|
+
"int2" => PG::TextDecoder::Integer,
|
273
|
+
"int4" => PG::TextDecoder::Integer,
|
274
|
+
"int8" => PG::TextDecoder::Integer,
|
275
|
+
"oid" => PG::TextDecoder::Integer,
|
276
|
+
"float4" => PG::TextDecoder::Float,
|
277
|
+
"float8" => PG::TextDecoder::Float,
|
278
|
+
"bool" => PG::TextDecoder::Boolean,
|
279
|
+
"numeric" => PG::TextDecoder::Numeric
|
280
|
+
}
|
281
|
+
|
282
|
+
if defined?(PG::TextDecoder::TimestampUtc)
|
283
|
+
# Use native PG encoders available since pg-1.1
|
284
|
+
coders_by_name["timestamp"] = PG::TextDecoder::TimestampUtc
|
285
|
+
coders_by_name["timestamptz"] = PG::TextDecoder::TimestampWithTimeZone
|
286
|
+
end
|
287
|
+
|
288
|
+
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
|
289
|
+
query = format(<<~SQL, *known_coder_types.join(", "))
|
290
|
+
SELECT t.oid, t.typname
|
291
|
+
FROM pg_type as t
|
292
|
+
WHERE t.typname IN (%s)
|
293
|
+
SQL
|
294
|
+
coders = execute_and_clear(query, "SCHEMA", []) do |result|
|
295
|
+
result
|
296
|
+
.map { |row| construct_coder(row, coders_by_name[row["typname"]]) }
|
297
|
+
.compact
|
298
|
+
end
|
299
|
+
|
300
|
+
map = PG::TypeMapByOid.new
|
301
|
+
coders.each { |coder| map.add_coder(coder) }
|
302
|
+
@connection.type_map_for_results = map
|
303
|
+
|
304
|
+
# extract timestamp decoder for use in update_typemap_for_default_timezone
|
305
|
+
@timestamp_decoder = coders.find { |coder| coder.name == "timestamp" }
|
306
|
+
update_typemap_for_default_timezone
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
238
310
|
def initialize_type_map(map = type_map)
|
239
311
|
map.register_type "pg_lsn", ActiveRecord::ConnectionAdapters::PostgreSQL::OID::SpecializedString.new(:pg_lsn)
|
240
312
|
|
@@ -8,9 +8,10 @@ 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"
|
12
13
|
|
13
|
-
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.
|
14
|
+
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(PostgreSQLAdapter)
|
14
15
|
# if they've already require 'all', then inject now
|
15
16
|
defined?(All) && All.inject
|
16
17
|
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 "
|
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 "
|
27
|
-
connection.
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
|
@@ -92,8 +121,8 @@ describe ActiveRecord::PGExtensions::PessimisticMigrations do
|
|
92
121
|
expect(connection).to receive(:remove_index).with(:users, name: "index_users_on_name", algorithm: :concurrently)
|
93
122
|
|
94
123
|
connection.add_index :users, :name, algorithm: :concurrently
|
95
|
-
expect(connection.executed_statements).to
|
96
|
-
[
|
124
|
+
expect(connection.executed_statements).to match(
|
125
|
+
[match(/\ACREATE +INDEX CONCURRENTLY "index_users_on_name" ON "users" +\("name"\)\z/)]
|
97
126
|
)
|
98
127
|
end
|
99
128
|
|
@@ -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
|
|
@@ -243,5 +261,110 @@ describe ActiveRecord::ConnectionAdapters::PostgreSQLAdapter do
|
|
243
261
|
expect(connection.in_recovery?).to eq false
|
244
262
|
end
|
245
263
|
end
|
264
|
+
|
265
|
+
describe "#select_value" do
|
266
|
+
it "casts numeric types" do
|
267
|
+
expect(connection.select_value("SELECT factorial(2)")).to eq 2
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
describe "#with_statement_timeout" do
|
273
|
+
it "stops long-running queries" do
|
274
|
+
expect do
|
275
|
+
connection.with_statement_timeout(0.01) do
|
276
|
+
connection.execute("SELECT pg_sleep(3)")
|
277
|
+
end
|
278
|
+
end.to raise_error(ActiveRecord::QueryTimeout)
|
279
|
+
end
|
280
|
+
|
281
|
+
it "re-raises other errors" do
|
282
|
+
expect do
|
283
|
+
connection.with_statement_timeout(1) do
|
284
|
+
connection.execute("bad sql")
|
285
|
+
end
|
286
|
+
end.to raise_error(ActiveRecord::StatementInvalid)
|
287
|
+
end
|
288
|
+
|
289
|
+
context "without executing" do
|
290
|
+
it "converts integer to ms" do
|
291
|
+
connection.with_statement_timeout(30) { nil }
|
292
|
+
expect(connection.executed_statements).to eq(
|
293
|
+
[
|
294
|
+
"BEGIN",
|
295
|
+
"SET LOCAL statement_timeout=30000",
|
296
|
+
"COMMIT"
|
297
|
+
]
|
298
|
+
)
|
299
|
+
end
|
300
|
+
|
301
|
+
it "converts float to ms" do
|
302
|
+
connection.with_statement_timeout(5.5) { nil }
|
303
|
+
expect(connection.executed_statements).to eq(
|
304
|
+
[
|
305
|
+
"BEGIN",
|
306
|
+
"SET LOCAL statement_timeout=5500",
|
307
|
+
"COMMIT"
|
308
|
+
]
|
309
|
+
)
|
310
|
+
end
|
311
|
+
|
312
|
+
it "converts ActiveSupport::Duration to ms" do
|
313
|
+
connection.with_statement_timeout(5.seconds) { nil }
|
314
|
+
expect(connection.executed_statements).to eq(
|
315
|
+
[
|
316
|
+
"BEGIN",
|
317
|
+
"SET LOCAL statement_timeout=5000",
|
318
|
+
"COMMIT"
|
319
|
+
]
|
320
|
+
)
|
321
|
+
end
|
322
|
+
|
323
|
+
it "allows true" do
|
324
|
+
connection.with_statement_timeout(true) { nil }
|
325
|
+
expect(connection.executed_statements).to eq(
|
326
|
+
[
|
327
|
+
"BEGIN",
|
328
|
+
"SET LOCAL statement_timeout=30000",
|
329
|
+
"COMMIT"
|
330
|
+
]
|
331
|
+
)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
unless Rails.version >= "6.1"
|
337
|
+
describe "#add_check_constraint" do
|
338
|
+
around do |example|
|
339
|
+
connection.dont_execute(&example)
|
340
|
+
end
|
341
|
+
|
342
|
+
it "works" do
|
343
|
+
connection.add_check_constraint(:table, "column IS NOT NULL", name: :my_constraint)
|
344
|
+
expect(connection.executed_statements).to eq(
|
345
|
+
['ALTER TABLE "table" ADD CONSTRAINT "my_constraint" CHECK (column IS NOT NULL)']
|
346
|
+
)
|
347
|
+
end
|
348
|
+
|
349
|
+
it "defers validation" do
|
350
|
+
connection.add_check_constraint(:table, "column IS NOT NULL", name: :my_constraint, validate: false)
|
351
|
+
expect(connection.executed_statements).to eq(
|
352
|
+
['ALTER TABLE "table" ADD CONSTRAINT "my_constraint" CHECK (column IS NOT NULL) NOT VALID']
|
353
|
+
)
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
describe "#remove_check_constraint" do
|
358
|
+
around do |example|
|
359
|
+
connection.dont_execute(&example)
|
360
|
+
end
|
361
|
+
|
362
|
+
it "works" do
|
363
|
+
connection.remove_check_constraint(:table, name: :my_constraint)
|
364
|
+
expect(connection.executed_statements).to eq(
|
365
|
+
['ALTER TABLE "table" DROP CONSTRAINT "my_constraint"']
|
366
|
+
)
|
367
|
+
end
|
368
|
+
end
|
246
369
|
end
|
247
370
|
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.
|
4
|
+
version: 0.3.0
|
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-
|
11
|
+
date: 2021-09-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -50,6 +50,20 @@ dependencies:
|
|
50
50
|
- - "<"
|
51
51
|
- !ruby/object:Gem::Version
|
52
52
|
version: '6.2'
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: appraisal
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '2.4'
|
60
|
+
type: :development
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '2.4'
|
53
67
|
- !ruby/object:Gem::Dependency
|
54
68
|
name: byebug
|
55
69
|
requirement: !ruby/object:Gem::Requirement
|
@@ -161,6 +175,7 @@ files:
|
|
161
175
|
- config/database.yml
|
162
176
|
- lib/active_record/pg_extensions.rb
|
163
177
|
- lib/active_record/pg_extensions/all.rb
|
178
|
+
- lib/active_record/pg_extensions/errors.rb
|
164
179
|
- lib/active_record/pg_extensions/extension.rb
|
165
180
|
- lib/active_record/pg_extensions/pessimistic_migrations.rb
|
166
181
|
- lib/active_record/pg_extensions/postgresql_adapter.rb
|
@@ -190,7 +205,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
190
205
|
- !ruby/object:Gem::Version
|
191
206
|
version: '0'
|
192
207
|
requirements: []
|
193
|
-
rubygems_version: 3.2.
|
208
|
+
rubygems_version: 3.2.24
|
194
209
|
signing_key:
|
195
210
|
specification_version: 4
|
196
211
|
summary: Several extensions to ActiveRecord's PostgreSQLAdapter.
|