activerecord6-redshift-adapter 1.1.2 → 1.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/active_record/connection_adapters/redshift/database_statements.rb +8 -2
- data/lib/active_record/connection_adapters/redshift/schema_definitions.rb +2 -2
- data/lib/active_record/connection_adapters/redshift/schema_statements.rb +4 -4
- data/lib/active_record/connection_adapters/redshift_adapter.rb +189 -94
- metadata +9 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: aed3175ea88bb9b6b163ffc7b198768b81c16330dc1d7b480d7d1a17356f6033
|
4
|
+
data.tar.gz: 66de7284e67e34a05bbd376be4cd8c3ee0a0c3b7565db16229a7c1512eb0de41
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c840dd282c228c3aab781e770ac40a8c5a2ee3ddb71c6d380f27cf6a9c411ed3ff5c659cfa6dbaa768da6db58dadbdefec8736309f4cff360a5639fcf2c83c96
|
7
|
+
data.tar.gz: bce5739dd4b207c1c92f726b80ad0a920eeb04b3f5d76800e5ff0121bd3a2c79474a967795c6ca4c7d567b6c8654dd9620188aa8397f0ee0a38886a072eb0439
|
@@ -47,9 +47,12 @@ module ActiveRecord
|
|
47
47
|
def select_value(arel, name = nil, binds = [])
|
48
48
|
# In Rails 5.2, arel_from_relation replaced binds_from_relation,
|
49
49
|
# so we see which method exists to get the variables
|
50
|
+
#
|
51
|
+
# In Rails 6.0 to_sql_and_binds began only returning sql, with
|
52
|
+
# to_sql_and_binds serving as a replacement
|
50
53
|
if respond_to?(:arel_from_relation, true)
|
51
54
|
arel = arel_from_relation(arel)
|
52
|
-
sql, binds =
|
55
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
53
56
|
else
|
54
57
|
arel, binds = binds_from_relation arel, binds
|
55
58
|
sql = to_sql(arel, binds)
|
@@ -62,9 +65,12 @@ module ActiveRecord
|
|
62
65
|
def select_values(arel, name = nil)
|
63
66
|
# In Rails 5.2, arel_from_relation replaced binds_from_relation,
|
64
67
|
# so we see which method exists to get the variables
|
68
|
+
#
|
69
|
+
# In Rails 6.0 to_sql_and_binds began only returning sql, with
|
70
|
+
# to_sql_and_binds serving as a replacement
|
65
71
|
if respond_to?(:arel_from_relation, true)
|
66
72
|
arel = arel_from_relation(arel)
|
67
|
-
sql, binds =
|
73
|
+
sql, binds = to_sql_and_binds(arel, [])
|
68
74
|
else
|
69
75
|
arel, binds = binds_from_relation arel, []
|
70
76
|
sql = to_sql(arel, binds)
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
private
|
6
6
|
|
7
7
|
def visit_ColumnDefinition(o)
|
8
|
-
o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale)
|
8
|
+
o.sql_type = type_to_sql(o.type, limit: o.limit, precision: o.precision, scale: o.scale)
|
9
9
|
super
|
10
10
|
end
|
11
11
|
|
@@ -277,11 +277,11 @@ module ActiveRecord
|
|
277
277
|
def change_column(table_name, column_name, type, options = {})
|
278
278
|
clear_cache!
|
279
279
|
quoted_table_name = quote_table_name(table_name)
|
280
|
-
sql_type = type_to_sql(type, options[:limit], options[:precision], options[:scale])
|
280
|
+
sql_type = type_to_sql(type, limit: options[:limit], precision: options[:precision], scale: options[:scale])
|
281
281
|
sql = "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{sql_type}"
|
282
282
|
sql << " USING #{options[:using]}" if options[:using]
|
283
283
|
if options[:cast_as]
|
284
|
-
sql << " USING CAST(#{quote_column_name(column_name)} AS #{type_to_sql(options[:cast_as], options[:limit], options[:precision], options[:scale])})"
|
284
|
+
sql << " USING CAST(#{quote_column_name(column_name)} AS #{type_to_sql(options[:cast_as], limit: options[:limit], precision: options[:precision], scale: options[:scale])})"
|
285
285
|
end
|
286
286
|
execute sql
|
287
287
|
|
@@ -372,7 +372,7 @@ module ActiveRecord
|
|
372
372
|
end
|
373
373
|
|
374
374
|
# Maps logical Rails types to PostgreSQL-specific data types.
|
375
|
-
def type_to_sql(type, limit
|
375
|
+
def type_to_sql(type, limit: nil, precision: nil, scale: nil, **)
|
376
376
|
case type.to_s
|
377
377
|
when 'integer'
|
378
378
|
return 'integer' unless limit
|
@@ -12,10 +12,14 @@ require 'active_record/connection_adapters/redshift/schema_statements'
|
|
12
12
|
require 'active_record/connection_adapters/redshift/type_metadata'
|
13
13
|
require 'active_record/connection_adapters/redshift/database_statements'
|
14
14
|
|
15
|
+
require 'active_record/tasks/database_tasks'
|
16
|
+
|
15
17
|
require 'pg'
|
16
18
|
|
17
19
|
require 'ipaddr'
|
18
20
|
|
21
|
+
ActiveRecord::Tasks::DatabaseTasks.register_task(/redshift/, "ActiveRecord::Tasks::PostgreSQLDatabaseTasks")
|
22
|
+
|
19
23
|
module ActiveRecord
|
20
24
|
module ConnectionHandling # :nodoc:
|
21
25
|
RS_VALID_CONN_PARAMS = [:host, :hostaddr, :port, :dbname, :user, :password, :connect_timeout,
|
@@ -78,10 +82,10 @@ module ActiveRecord
|
|
78
82
|
string: { name: "varchar" },
|
79
83
|
text: { name: "varchar" },
|
80
84
|
integer: { name: "integer" },
|
81
|
-
float: { name: "
|
85
|
+
float: { name: "decimal" },
|
82
86
|
decimal: { name: "decimal" },
|
83
87
|
datetime: { name: "timestamp" },
|
84
|
-
time: { name: "
|
88
|
+
time: { name: "timestamp" },
|
85
89
|
date: { name: "date" },
|
86
90
|
bigint: { name: "bigint" },
|
87
91
|
boolean: { name: "boolean" },
|
@@ -122,55 +126,29 @@ module ActiveRecord
|
|
122
126
|
{ concurrently: 'CONCURRENTLY' }
|
123
127
|
end
|
124
128
|
|
125
|
-
class StatementPool < ConnectionAdapters::StatementPool
|
129
|
+
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
126
130
|
def initialize(connection, max)
|
127
131
|
super(max)
|
128
132
|
@connection = connection
|
129
133
|
@counter = 0
|
130
|
-
@cache = Hash.new { |h,pid| h[pid] = {} }
|
131
134
|
end
|
132
135
|
|
133
|
-
def each(&block); cache.each(&block); end
|
134
|
-
def key?(key); cache.key?(key); end
|
135
|
-
def [](key); cache[key]; end
|
136
|
-
def length; cache.length; end
|
137
|
-
|
138
136
|
def next_key
|
139
137
|
"a#{@counter + 1}"
|
140
138
|
end
|
141
139
|
|
142
140
|
def []=(sql, key)
|
143
|
-
|
144
|
-
dealloc(cache.shift.last)
|
145
|
-
end
|
146
|
-
@counter += 1
|
147
|
-
cache[sql] = key
|
148
|
-
end
|
149
|
-
|
150
|
-
def clear
|
151
|
-
cache.each_value do |stmt_key|
|
152
|
-
dealloc stmt_key
|
153
|
-
end
|
154
|
-
cache.clear
|
155
|
-
end
|
156
|
-
|
157
|
-
def delete(sql_key)
|
158
|
-
dealloc cache[sql_key]
|
159
|
-
cache.delete sql_key
|
141
|
+
super.tap { @counter += 1 }
|
160
142
|
end
|
161
143
|
|
162
144
|
private
|
163
|
-
|
164
|
-
def cache
|
165
|
-
@cache[Process.pid]
|
166
|
-
end
|
167
|
-
|
168
145
|
def dealloc(key)
|
169
146
|
@connection.query "DEALLOCATE #{key}" if connection_active?
|
147
|
+
rescue PG::Error
|
170
148
|
end
|
171
149
|
|
172
150
|
def connection_active?
|
173
|
-
@connection.status == PG::
|
151
|
+
@connection.status == PG::CONNECTION_OK
|
174
152
|
rescue PG::Error
|
175
153
|
false
|
176
154
|
end
|
@@ -255,14 +233,6 @@ module ActiveRecord
|
|
255
233
|
true
|
256
234
|
end
|
257
235
|
|
258
|
-
# Enable standard-conforming strings if available.
|
259
|
-
def set_standard_conforming_strings
|
260
|
-
old, self.client_min_messages = client_min_messages, 'panic'
|
261
|
-
execute('SET standard_conforming_strings = on', 'SCHEMA') rescue nil
|
262
|
-
ensure
|
263
|
-
self.client_min_messages = old
|
264
|
-
end
|
265
|
-
|
266
236
|
def supports_ddl_transactions?
|
267
237
|
true
|
268
238
|
end
|
@@ -342,7 +312,7 @@ module ActiveRecord
|
|
342
312
|
@connection.server_version
|
343
313
|
end
|
344
314
|
|
345
|
-
def translate_exception(exception, message)
|
315
|
+
def translate_exception(exception, message:, sql:, binds:)
|
346
316
|
return exception unless exception.respond_to?(:result)
|
347
317
|
|
348
318
|
case exception.message
|
@@ -496,39 +466,68 @@ module ActiveRecord
|
|
496
466
|
ret
|
497
467
|
end
|
498
468
|
|
469
|
+
|
499
470
|
def exec_no_cache(sql, name, binds)
|
500
|
-
|
471
|
+
materialize_transactions
|
472
|
+
|
473
|
+
# make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
|
474
|
+
# made since we established the connection
|
475
|
+
update_typemap_for_default_timezone
|
476
|
+
|
477
|
+
type_casted_binds = type_casted_binds(binds)
|
478
|
+
log(sql, name, binds, type_casted_binds) do
|
479
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
480
|
+
@connection.exec_params(sql, type_casted_binds)
|
481
|
+
end
|
482
|
+
end
|
501
483
|
end
|
502
484
|
|
503
485
|
def exec_cache(sql, name, binds)
|
504
|
-
|
505
|
-
|
506
|
-
[col, type_cast(val, col)]
|
507
|
-
}
|
486
|
+
materialize_transactions
|
487
|
+
update_typemap_for_default_timezone
|
508
488
|
|
509
|
-
|
510
|
-
|
489
|
+
stmt_key = prepare_statement(sql, binds)
|
490
|
+
type_casted_binds = type_casted_binds(binds)
|
491
|
+
|
492
|
+
log(sql, name, binds, type_casted_binds, stmt_key) do
|
493
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
494
|
+
@connection.exec_prepared(stmt_key, type_casted_binds)
|
495
|
+
end
|
511
496
|
end
|
512
497
|
rescue ActiveRecord::StatementInvalid => e
|
513
|
-
|
514
|
-
|
515
|
-
#
|
516
|
-
#
|
517
|
-
|
518
|
-
|
519
|
-
begin
|
520
|
-
code = pgerror.result.result_error_field(PG::Result::PG_DIAG_SQLSTATE)
|
521
|
-
rescue
|
522
|
-
raise e
|
523
|
-
end
|
524
|
-
if FEATURE_NOT_SUPPORTED == code
|
525
|
-
@statements.delete sql_key(sql)
|
526
|
-
retry
|
498
|
+
raise unless is_cached_plan_failure?(e)
|
499
|
+
|
500
|
+
# Nothing we can do if we are in a transaction because all commands
|
501
|
+
# will raise InFailedSQLTransaction
|
502
|
+
if in_transaction?
|
503
|
+
raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
|
527
504
|
else
|
528
|
-
|
505
|
+
@lock.synchronize do
|
506
|
+
# outside of transactions we can simply flush this query and retry
|
507
|
+
@statements.delete sql_key(sql)
|
508
|
+
end
|
509
|
+
retry
|
529
510
|
end
|
530
511
|
end
|
531
512
|
|
513
|
+
# Annoyingly, the code for prepared statements whose return value may
|
514
|
+
# have changed is FEATURE_NOT_SUPPORTED.
|
515
|
+
#
|
516
|
+
# This covers various different error types so we need to do additional
|
517
|
+
# work to classify the exception definitively as a
|
518
|
+
# ActiveRecord::PreparedStatementCacheExpired
|
519
|
+
#
|
520
|
+
# Check here for more details:
|
521
|
+
# https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
|
522
|
+
CACHED_PLAN_HEURISTIC = "cached plan must not change result type"
|
523
|
+
def is_cached_plan_failure?(e)
|
524
|
+
pgerror = e.cause
|
525
|
+
code = pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE)
|
526
|
+
code == FEATURE_NOT_SUPPORTED && pgerror.message.include?(CACHED_PLAN_HEURISTIC)
|
527
|
+
rescue
|
528
|
+
false
|
529
|
+
end
|
530
|
+
|
532
531
|
# Returns the statement identifier for the client side cache
|
533
532
|
# of statements
|
534
533
|
def sql_key(sql)
|
@@ -537,34 +536,31 @@ module ActiveRecord
|
|
537
536
|
|
538
537
|
# Prepare the statement if it hasn't been prepared, return
|
539
538
|
# the statement key.
|
540
|
-
def prepare_statement(sql)
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
539
|
+
def prepare_statement(sql, binds)
|
540
|
+
@lock.synchronize do
|
541
|
+
sql_key = sql_key(sql)
|
542
|
+
unless @statements.key? sql_key
|
543
|
+
nextkey = @statements.next_key
|
544
|
+
begin
|
545
|
+
@connection.prepare nextkey, sql
|
546
|
+
rescue => e
|
547
|
+
raise translate_exception_class(e, sql, binds)
|
548
|
+
end
|
549
|
+
# Clear the queue
|
550
|
+
@connection.get_last_result
|
551
|
+
@statements[sql_key] = nextkey
|
548
552
|
end
|
549
|
-
|
550
|
-
@connection.get_last_result
|
551
|
-
@statements[sql_key] = nextkey
|
553
|
+
@statements[sql_key]
|
552
554
|
end
|
553
|
-
@statements[sql_key]
|
554
555
|
end
|
555
556
|
|
556
557
|
# Connects to a PostgreSQL server and sets up the adapter depending on the
|
557
558
|
# connected server's characteristics.
|
558
559
|
def connect
|
559
|
-
@connection = PG
|
560
|
-
|
560
|
+
@connection = PG.connect(@connection_parameters)
|
561
561
|
configure_connection
|
562
|
-
|
563
|
-
|
564
|
-
raise ActiveRecord::NoDatabaseError.new(error.message, error)
|
565
|
-
else
|
566
|
-
raise
|
567
|
-
end
|
562
|
+
add_pg_encoders
|
563
|
+
add_pg_decoders
|
568
564
|
end
|
569
565
|
|
570
566
|
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
|
@@ -575,17 +571,18 @@ module ActiveRecord
|
|
575
571
|
end
|
576
572
|
self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
|
577
573
|
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
elsif
|
586
|
-
|
574
|
+
variables = @config.fetch(:variables, {}).stringify_keys
|
575
|
+
|
576
|
+
# If using Active Record's time zone support configure the connection to return
|
577
|
+
# TIMESTAMP WITH ZONE types in UTC.
|
578
|
+
unless variables["timezone"]
|
579
|
+
if ActiveRecord::Base.default_timezone == :utc
|
580
|
+
variables["timezone"] = "UTC"
|
581
|
+
elsif @local_tz
|
582
|
+
variables["timezone"] = @local_tz
|
587
583
|
end
|
588
584
|
end
|
585
|
+
|
589
586
|
end
|
590
587
|
|
591
588
|
def last_insert_id_result(sequence_name) #:nodoc:
|
@@ -622,13 +619,111 @@ module ActiveRecord
|
|
622
619
|
end_sql
|
623
620
|
end
|
624
621
|
|
625
|
-
def extract_table_ref_from_insert_sql(sql)
|
622
|
+
def extract_table_ref_from_insert_sql(sql)
|
626
623
|
sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
|
627
624
|
$1.strip if $1
|
628
625
|
end
|
629
626
|
|
627
|
+
def arel_visitor
|
628
|
+
Arel::Visitors::PostgreSQL.new(self)
|
629
|
+
end
|
630
|
+
|
631
|
+
def build_statement_pool
|
632
|
+
StatementPool.new(@connection, self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
633
|
+
end
|
634
|
+
|
635
|
+
|
636
|
+
def can_perform_case_insensitive_comparison_for?(column)
|
637
|
+
@case_insensitive_cache ||= {}
|
638
|
+
@case_insensitive_cache[column.sql_type] ||= begin
|
639
|
+
sql = <<~SQL
|
640
|
+
SELECT exists(
|
641
|
+
SELECT * FROM pg_proc
|
642
|
+
WHERE proname = 'lower'
|
643
|
+
AND proargtypes = ARRAY[#{quote column.sql_type}::regtype]::oidvector
|
644
|
+
) OR exists(
|
645
|
+
SELECT * FROM pg_proc
|
646
|
+
INNER JOIN pg_cast
|
647
|
+
ON ARRAY[casttarget]::oidvector = proargtypes
|
648
|
+
WHERE proname = 'lower'
|
649
|
+
AND castsource = #{quote column.sql_type}::regtype
|
650
|
+
)
|
651
|
+
SQL
|
652
|
+
execute_and_clear(sql, "SCHEMA", []) do |result|
|
653
|
+
result.getvalue(0, 0)
|
654
|
+
end
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
def add_pg_encoders
|
659
|
+
map = PG::TypeMapByClass.new
|
660
|
+
map[Integer] = PG::TextEncoder::Integer.new
|
661
|
+
map[TrueClass] = PG::TextEncoder::Boolean.new
|
662
|
+
map[FalseClass] = PG::TextEncoder::Boolean.new
|
663
|
+
@connection.type_map_for_queries = map
|
664
|
+
end
|
665
|
+
|
666
|
+
def update_typemap_for_default_timezone
|
667
|
+
if @default_timezone != ActiveRecord::Base.default_timezone && @timestamp_decoder
|
668
|
+
decoder_class = ActiveRecord::Base.default_timezone == :utc ?
|
669
|
+
PG::TextDecoder::TimestampUtc :
|
670
|
+
PG::TextDecoder::TimestampWithoutTimeZone
|
671
|
+
|
672
|
+
@timestamp_decoder = decoder_class.new(@timestamp_decoder.to_h)
|
673
|
+
@connection.type_map_for_results.add_coder(@timestamp_decoder)
|
674
|
+
@default_timezone = ActiveRecord::Base.default_timezone
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
|
679
|
+
def add_pg_decoders
|
680
|
+
@default_timezone = nil
|
681
|
+
@timestamp_decoder = nil
|
682
|
+
|
683
|
+
coders_by_name = {
|
684
|
+
"int2" => PG::TextDecoder::Integer,
|
685
|
+
"int4" => PG::TextDecoder::Integer,
|
686
|
+
"int8" => PG::TextDecoder::Integer,
|
687
|
+
"oid" => PG::TextDecoder::Integer,
|
688
|
+
"float4" => PG::TextDecoder::Float,
|
689
|
+
"float8" => PG::TextDecoder::Float,
|
690
|
+
"bool" => PG::TextDecoder::Boolean,
|
691
|
+
}
|
692
|
+
|
693
|
+
if defined?(PG::TextDecoder::TimestampUtc)
|
694
|
+
# Use native PG encoders available since pg-1.1
|
695
|
+
coders_by_name["timestamp"] = PG::TextDecoder::TimestampUtc
|
696
|
+
coders_by_name["timestamptz"] = PG::TextDecoder::TimestampWithTimeZone
|
697
|
+
end
|
698
|
+
|
699
|
+
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
|
700
|
+
query = <<~SQL % known_coder_types.join(", ")
|
701
|
+
SELECT t.oid, t.typname
|
702
|
+
FROM pg_type as t
|
703
|
+
WHERE t.typname IN (%s)
|
704
|
+
SQL
|
705
|
+
coders = execute_and_clear(query, "SCHEMA", []) do |result|
|
706
|
+
result
|
707
|
+
.map { |row| construct_coder(row, coders_by_name[row["typname"]]) }
|
708
|
+
.compact
|
709
|
+
end
|
710
|
+
|
711
|
+
map = PG::TypeMapByOid.new
|
712
|
+
coders.each { |coder| map.add_coder(coder) }
|
713
|
+
@connection.type_map_for_results = map
|
714
|
+
|
715
|
+
# extract timestamp decoder for use in update_typemap_for_default_timezone
|
716
|
+
@timestamp_decoder = coders.find { |coder| coder.name == "timestamp" }
|
717
|
+
update_typemap_for_default_timezone
|
718
|
+
end
|
719
|
+
|
720
|
+
def construct_coder(row, coder_class)
|
721
|
+
return unless coder_class
|
722
|
+
coder_class.new(oid: row["oid"].to_i, name: row["typname"])
|
723
|
+
end
|
724
|
+
|
630
725
|
def create_table_definition(*args) # :nodoc:
|
631
|
-
Redshift::TableDefinition.new(*args)
|
726
|
+
Redshift::TableDefinition.new(self, *args)
|
632
727
|
end
|
633
728
|
end
|
634
729
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord6-redshift-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nancy Foen
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2020-08-04 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: pg
|
@@ -31,22 +31,22 @@ dependencies:
|
|
31
31
|
name: activerecord
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
requirements:
|
34
|
-
- - "~>"
|
35
|
-
- !ruby/object:Gem::Version
|
36
|
-
version: '6.0'
|
37
34
|
- - ">="
|
38
35
|
- !ruby/object:Gem::Version
|
39
36
|
version: 6.0.0
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '6.0'
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
|
-
- - "~>"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '6.0'
|
47
44
|
- - ">="
|
48
45
|
- !ruby/object:Gem::Version
|
49
46
|
version: 6.0.0
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '6.0'
|
50
50
|
description: Amazon Redshift _makeshift_ adapter for ActiveRecord 6.
|
51
51
|
email: fantast.d@gmail.com
|
52
52
|
executables: []
|
@@ -91,8 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
91
|
- !ruby/object:Gem::Version
|
92
92
|
version: '0'
|
93
93
|
requirements: []
|
94
|
-
|
95
|
-
rubygems_version: 2.5.2.3
|
94
|
+
rubygems_version: 3.0.3
|
96
95
|
signing_key:
|
97
96
|
specification_version: 4
|
98
97
|
summary: Amazon Redshift adapter for ActiveRecord
|