activerecord 6.0.0.beta2 → 6.0.2.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +471 -9
- data/README.rdoc +3 -1
- data/lib/active_record.rb +0 -1
- data/lib/active_record/association_relation.rb +15 -6
- data/lib/active_record/associations.rb +4 -3
- data/lib/active_record/associations/association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +5 -2
- data/lib/active_record/associations/builder/collection_association.rb +5 -15
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +6 -2
- data/lib/active_record/associations/collection_proxy.rb +2 -2
- data/lib/active_record/associations/has_many_through_association.rb +4 -11
- data/lib/active_record/associations/join_dependency.rb +14 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +12 -3
- data/lib/active_record/associations/preloader.rb +13 -8
- data/lib/active_record/associations/preloader/association.rb +34 -30
- data/lib/active_record/associations/preloader/through_association.rb +48 -28
- data/lib/active_record/attribute_methods.rb +3 -53
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +47 -14
- data/lib/active_record/attribute_methods/primary_key.rb +7 -15
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +3 -9
- data/lib/active_record/attribute_methods/write.rb +6 -12
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +21 -7
- data/lib/active_record/base.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -11
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +88 -61
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +6 -4
- data/lib/active_record/connection_adapters/abstract/quoting.rb +63 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -7
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +79 -22
- data/lib/active_record/connection_adapters/abstract/transaction.rb +12 -4
- data/lib/active_record/connection_adapters/abstract_adapter.rb +114 -34
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +78 -73
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -2
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +48 -8
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -5
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +10 -7
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +18 -5
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +39 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +34 -38
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +68 -27
- data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -114
- data/lib/active_record/connection_handling.rb +31 -13
- data/lib/active_record/core.rb +23 -24
- data/lib/active_record/database_configurations.rb +73 -44
- data/lib/active_record/database_configurations/hash_config.rb +11 -11
- data/lib/active_record/database_configurations/url_config.rb +12 -12
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +15 -0
- data/lib/active_record/errors.rb +1 -1
- data/lib/active_record/fixtures.rb +11 -6
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +13 -1
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +3 -4
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/middleware/database_selector.rb +3 -3
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -6
- data/lib/active_record/migration.rb +62 -44
- data/lib/active_record/migration/command_recorder.rb +28 -14
- data/lib/active_record/migration/compatibility.rb +10 -0
- data/lib/active_record/model_schema.rb +3 -0
- data/lib/active_record/persistence.rb +206 -13
- data/lib/active_record/querying.rb +17 -12
- data/lib/active_record/railtie.rb +0 -1
- data/lib/active_record/railties/databases.rake +127 -25
- data/lib/active_record/reflection.rb +3 -3
- data/lib/active_record/relation.rb +99 -20
- data/lib/active_record/relation/calculations.rb +38 -40
- data/lib/active_record/relation/delegation.rb +22 -30
- data/lib/active_record/relation/finder_methods.rb +17 -12
- data/lib/active_record/relation/merger.rb +11 -16
- data/lib/active_record/relation/query_methods.rb +228 -76
- data/lib/active_record/relation/where_clause.rb +9 -5
- data/lib/active_record/sanitization.rb +33 -4
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +10 -1
- data/lib/active_record/schema_migration.rb +1 -1
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +3 -2
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/store.rb +48 -0
- data/lib/active_record/table_metadata.rb +9 -13
- data/lib/active_record/tasks/database_tasks.rb +109 -6
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -1
- data/lib/active_record/test_databases.rb +1 -16
- data/lib/active_record/test_fixtures.rb +1 -0
- data/lib/active_record/timestamp.rb +26 -16
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +56 -46
- data/lib/active_record/type_caster/connection.rb +16 -10
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record/validations/uniqueness.rb +3 -5
- data/lib/arel.rb +12 -5
- data/lib/arel/insert_manager.rb +3 -3
- data/lib/arel/nodes.rb +2 -1
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/select_core.rb +16 -12
- data/lib/arel/nodes/unary.rb +1 -0
- data/lib/arel/nodes/values_list.rb +2 -17
- data/lib/arel/select_manager.rb +10 -10
- data/lib/arel/visitors/depth_first.rb +7 -2
- data/lib/arel/visitors/dot.rb +7 -2
- data/lib/arel/visitors/ibm_db.rb +13 -0
- data/lib/arel/visitors/informix.rb +6 -0
- data/lib/arel/visitors/mssql.rb +15 -1
- data/lib/arel/visitors/oracle12.rb +4 -5
- data/lib/arel/visitors/postgresql.rb +4 -10
- data/lib/arel/visitors/to_sql.rb +107 -131
- data/lib/arel/visitors/visitor.rb +9 -5
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +16 -12
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/arel/nodes/values.rb +0 -16
@@ -17,17 +17,17 @@ module ActiveRecord
|
|
17
17
|
# @config={"adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost"},
|
18
18
|
# @url="postgres://localhost/foo">
|
19
19
|
#
|
20
|
-
# Options
|
20
|
+
# ==== Options
|
21
21
|
#
|
22
|
-
# <tt>:env_name</tt> - The Rails environment, ie "development"
|
23
|
-
# <tt>:spec_name</tt> - The specification name. In a standard two-tier
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
# <tt>:url</tt> - The database URL.
|
28
|
-
# <tt>:config</tt> - The config hash. This is the hash that contains the
|
29
|
-
#
|
30
|
-
#
|
22
|
+
# * <tt>:env_name</tt> - The Rails environment, ie "development".
|
23
|
+
# * <tt>:spec_name</tt> - The specification name. In a standard two-tier
|
24
|
+
# database configuration this will default to "primary". In a multiple
|
25
|
+
# database three-tier database configuration this corresponds to the name
|
26
|
+
# used in the second tier, for example "primary_readonly".
|
27
|
+
# * <tt>:url</tt> - The database URL.
|
28
|
+
# * <tt>:config</tt> - The config hash. This is the hash that contains the
|
29
|
+
# database adapter, name, and other important information for database
|
30
|
+
# connections.
|
31
31
|
class UrlConfig < DatabaseConfig
|
32
32
|
attr_reader :url, :config
|
33
33
|
|
@@ -42,14 +42,14 @@ module ActiveRecord
|
|
42
42
|
end
|
43
43
|
|
44
44
|
# Determines whether a database configuration is for a replica / readonly
|
45
|
-
# connection. If the
|
45
|
+
# connection. If the +replica+ key is present in the config, +replica?+ will
|
46
46
|
# return +true+.
|
47
47
|
def replica?
|
48
48
|
config["replica"]
|
49
49
|
end
|
50
50
|
|
51
51
|
# The migrations paths for a database configuration. If the
|
52
|
-
#
|
52
|
+
# +migrations_paths+ key is present in the config, +migrations_paths+
|
53
53
|
# will return its value.
|
54
54
|
def migrations_paths
|
55
55
|
config["migrations_paths"]
|
@@ -53,7 +53,7 @@ module ActiveRecord
|
|
53
53
|
@model = model
|
54
54
|
@name = name.to_s
|
55
55
|
@attribute_names = @name.match(self.class.pattern)[1].split("_and_")
|
56
|
-
@attribute_names.map! { |
|
56
|
+
@attribute_names.map! { |name| @model.attribute_aliases[name] || name }
|
57
57
|
end
|
58
58
|
|
59
59
|
def valid?
|
data/lib/active_record/enum.rb
CHANGED
@@ -31,7 +31,9 @@ module ActiveRecord
|
|
31
31
|
# as well. With the above example:
|
32
32
|
#
|
33
33
|
# Conversation.active
|
34
|
+
# Conversation.not_active
|
34
35
|
# Conversation.archived
|
36
|
+
# Conversation.not_archived
|
35
37
|
#
|
36
38
|
# Of course, you can also query them directly if the scopes don't fit your
|
37
39
|
# needs:
|
@@ -196,9 +198,15 @@ module ActiveRecord
|
|
196
198
|
define_method("#{value_method_name}!") { update!(attr => value) }
|
197
199
|
|
198
200
|
# scope :active, -> { where(status: 0) }
|
201
|
+
# scope :not_active, -> { where.not(status: 0) }
|
199
202
|
if enum_scopes != false
|
203
|
+
klass.send(:detect_negative_condition!, value_method_name)
|
204
|
+
|
200
205
|
klass.send(:detect_enum_conflict!, name, value_method_name, true)
|
201
206
|
klass.scope value_method_name, -> { where(attr => value) }
|
207
|
+
|
208
|
+
klass.send(:detect_enum_conflict!, name, "not_#{value_method_name}", true)
|
209
|
+
klass.scope "not_#{value_method_name}", -> { where.not(attr => value) }
|
202
210
|
end
|
203
211
|
end
|
204
212
|
end
|
@@ -255,5 +263,12 @@ module ActiveRecord
|
|
255
263
|
source: source
|
256
264
|
}
|
257
265
|
end
|
266
|
+
|
267
|
+
def detect_negative_condition!(method_name)
|
268
|
+
if method_name.start_with?("not_") && logger
|
269
|
+
logger.warn "An enum element in #{self.name} uses the prefix 'not_'." \
|
270
|
+
" This will cause a conflict with auto generated negative scopes."
|
271
|
+
end
|
272
|
+
end
|
258
273
|
end
|
259
274
|
end
|
data/lib/active_record/errors.rb
CHANGED
@@ -68,7 +68,7 @@ module ActiveRecord
|
|
68
68
|
|
69
69
|
# Raised by {ActiveRecord::Base#save!}[rdoc-ref:Persistence#save!] and
|
70
70
|
# {ActiveRecord::Base.create!}[rdoc-ref:Persistence::ClassMethods#create!]
|
71
|
-
# methods when a record is invalid and
|
71
|
+
# methods when a record is invalid and cannot be saved.
|
72
72
|
class RecordNotSaved < ActiveRecordError
|
73
73
|
attr_reader :record
|
74
74
|
|
@@ -531,15 +531,15 @@ module ActiveRecord
|
|
531
531
|
end
|
532
532
|
end
|
533
533
|
|
534
|
-
def create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
|
534
|
+
def create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base, &block)
|
535
535
|
fixture_set_names = Array(fixture_set_names).map(&:to_s)
|
536
536
|
class_names = ClassCache.new class_names, config
|
537
537
|
|
538
538
|
# FIXME: Apparently JK uses this.
|
539
|
-
connection = block_given? ?
|
539
|
+
connection = block_given? ? block : lambda { ActiveRecord::Base.connection }
|
540
540
|
|
541
541
|
fixture_files_to_read = fixture_set_names.reject do |fs_name|
|
542
|
-
fixture_is_cached?(connection, fs_name)
|
542
|
+
fixture_is_cached?(connection.call, fs_name)
|
543
543
|
end
|
544
544
|
|
545
545
|
if fixture_files_to_read.any?
|
@@ -549,9 +549,9 @@ module ActiveRecord
|
|
549
549
|
class_names,
|
550
550
|
connection,
|
551
551
|
)
|
552
|
-
cache_fixtures(connection, fixtures_map)
|
552
|
+
cache_fixtures(connection.call, fixtures_map)
|
553
553
|
end
|
554
|
-
cached_fixtures(connection, fixture_set_names)
|
554
|
+
cached_fixtures(connection.call, fixture_set_names)
|
555
555
|
end
|
556
556
|
|
557
557
|
# Returns a consistent, platform-independent identifier for +label+.
|
@@ -591,7 +591,11 @@ module ActiveRecord
|
|
591
591
|
|
592
592
|
def insert(fixture_sets, connection) # :nodoc:
|
593
593
|
fixture_sets_by_connection = fixture_sets.group_by do |fixture_set|
|
594
|
-
fixture_set.model_class
|
594
|
+
if fixture_set.model_class
|
595
|
+
fixture_set.model_class.connection
|
596
|
+
else
|
597
|
+
connection.call
|
598
|
+
end
|
595
599
|
end
|
596
600
|
|
597
601
|
fixture_sets_by_connection.each do |conn, set|
|
@@ -602,6 +606,7 @@ module ActiveRecord
|
|
602
606
|
table_rows_for_connection[table].unshift(*rows)
|
603
607
|
end
|
604
608
|
end
|
609
|
+
|
605
610
|
conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
|
606
611
|
|
607
612
|
# Cap primary key sequences to max(pk).
|
@@ -0,0 +1,179 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class InsertAll # :nodoc:
|
5
|
+
attr_reader :model, :connection, :inserts, :keys
|
6
|
+
attr_reader :on_duplicate, :returning, :unique_by
|
7
|
+
|
8
|
+
def initialize(model, inserts, on_duplicate:, returning: nil, unique_by: nil)
|
9
|
+
raise ArgumentError, "Empty list of attributes passed" if inserts.blank?
|
10
|
+
|
11
|
+
@model, @connection, @inserts, @keys = model, model.connection, inserts, inserts.first.keys.map(&:to_s).to_set
|
12
|
+
@on_duplicate, @returning, @unique_by = on_duplicate, returning, unique_by
|
13
|
+
|
14
|
+
@returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
|
15
|
+
@returning = false if @returning == []
|
16
|
+
|
17
|
+
@unique_by = find_unique_index_for(unique_by) if unique_by
|
18
|
+
@on_duplicate = :skip if @on_duplicate == :update && updatable_columns.empty?
|
19
|
+
|
20
|
+
ensure_valid_options_for_connection!
|
21
|
+
end
|
22
|
+
|
23
|
+
def execute
|
24
|
+
message = +"#{model} "
|
25
|
+
message << "Bulk " if inserts.many?
|
26
|
+
message << (on_duplicate == :update ? "Upsert" : "Insert")
|
27
|
+
connection.exec_insert_all to_sql, message
|
28
|
+
end
|
29
|
+
|
30
|
+
def updatable_columns
|
31
|
+
keys - readonly_columns - unique_by_columns
|
32
|
+
end
|
33
|
+
|
34
|
+
def primary_keys
|
35
|
+
Array(model.primary_key)
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def skip_duplicates?
|
40
|
+
on_duplicate == :skip
|
41
|
+
end
|
42
|
+
|
43
|
+
def update_duplicates?
|
44
|
+
on_duplicate == :update
|
45
|
+
end
|
46
|
+
|
47
|
+
def map_key_with_value
|
48
|
+
inserts.map do |attributes|
|
49
|
+
attributes = attributes.stringify_keys
|
50
|
+
verify_attributes(attributes)
|
51
|
+
|
52
|
+
keys.map do |key|
|
53
|
+
yield key, attributes[key]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def find_unique_index_for(unique_by)
|
60
|
+
match = Array(unique_by).map(&:to_s)
|
61
|
+
|
62
|
+
if index = unique_indexes.find { |i| match.include?(i.name) || i.columns == match }
|
63
|
+
index
|
64
|
+
else
|
65
|
+
raise ArgumentError, "No unique index found for #{unique_by}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def unique_indexes
|
70
|
+
connection.schema_cache.indexes(model.table_name).select(&:unique)
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
def ensure_valid_options_for_connection!
|
75
|
+
if returning && !connection.supports_insert_returning?
|
76
|
+
raise ArgumentError, "#{connection.class} does not support :returning"
|
77
|
+
end
|
78
|
+
|
79
|
+
if skip_duplicates? && !connection.supports_insert_on_duplicate_skip?
|
80
|
+
raise ArgumentError, "#{connection.class} does not support skipping duplicates"
|
81
|
+
end
|
82
|
+
|
83
|
+
if update_duplicates? && !connection.supports_insert_on_duplicate_update?
|
84
|
+
raise ArgumentError, "#{connection.class} does not support upsert"
|
85
|
+
end
|
86
|
+
|
87
|
+
if unique_by && !connection.supports_insert_conflict_target?
|
88
|
+
raise ArgumentError, "#{connection.class} does not support :unique_by"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
def to_sql
|
94
|
+
connection.build_insert_sql(ActiveRecord::InsertAll::Builder.new(self))
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
def readonly_columns
|
99
|
+
primary_keys + model.readonly_attributes.to_a
|
100
|
+
end
|
101
|
+
|
102
|
+
def unique_by_columns
|
103
|
+
Array(unique_by&.columns)
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
def verify_attributes(attributes)
|
108
|
+
if keys != attributes.keys.to_set
|
109
|
+
raise ArgumentError, "All objects being inserted must have the same keys"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class Builder # :nodoc:
|
114
|
+
attr_reader :model
|
115
|
+
|
116
|
+
delegate :skip_duplicates?, :update_duplicates?, :keys, to: :insert_all
|
117
|
+
|
118
|
+
def initialize(insert_all)
|
119
|
+
@insert_all, @model, @connection = insert_all, insert_all.model, insert_all.connection
|
120
|
+
end
|
121
|
+
|
122
|
+
def into
|
123
|
+
"INTO #{model.quoted_table_name}(#{columns_list})"
|
124
|
+
end
|
125
|
+
|
126
|
+
def values_list
|
127
|
+
types = extract_types_from_columns_on(model.table_name, keys: keys)
|
128
|
+
|
129
|
+
values_list = insert_all.map_key_with_value do |key, value|
|
130
|
+
connection.with_yaml_fallback(types[key].serialize(value))
|
131
|
+
end
|
132
|
+
|
133
|
+
Arel::InsertManager.new.create_values_list(values_list).to_sql
|
134
|
+
end
|
135
|
+
|
136
|
+
def returning
|
137
|
+
format_columns(insert_all.returning) if insert_all.returning
|
138
|
+
end
|
139
|
+
|
140
|
+
def conflict_target
|
141
|
+
if index = insert_all.unique_by
|
142
|
+
sql = +"(#{format_columns(index.columns)})"
|
143
|
+
sql << " WHERE #{index.where}" if index.where
|
144
|
+
sql
|
145
|
+
elsif update_duplicates?
|
146
|
+
"(#{format_columns(insert_all.primary_keys)})"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def updatable_columns
|
151
|
+
quote_columns(insert_all.updatable_columns)
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
attr_reader :connection, :insert_all
|
156
|
+
|
157
|
+
def columns_list
|
158
|
+
format_columns(insert_all.keys)
|
159
|
+
end
|
160
|
+
|
161
|
+
def extract_types_from_columns_on(table_name, keys:)
|
162
|
+
columns = connection.schema_cache.columns_hash(table_name)
|
163
|
+
|
164
|
+
unknown_column = (keys - columns.keys).first
|
165
|
+
raise UnknownAttributeError.new(model.new, unknown_column) if unknown_column
|
166
|
+
|
167
|
+
keys.map { |key| [ key, connection.lookup_cast_type_from_column(columns[key]) ] }.to_h
|
168
|
+
end
|
169
|
+
|
170
|
+
def format_columns(columns)
|
171
|
+
quote_columns(columns).join(",")
|
172
|
+
end
|
173
|
+
|
174
|
+
def quote_columns(columns)
|
175
|
+
columns.map(&connection.method(:quote_column_name))
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
@@ -22,6 +22,14 @@ module ActiveRecord
|
|
22
22
|
#
|
23
23
|
# This is +true+, by default on Rails 5.2 and above.
|
24
24
|
class_attribute :cache_versioning, instance_writer: false, default: false
|
25
|
+
|
26
|
+
##
|
27
|
+
# :singleton-method:
|
28
|
+
# Indicates whether to use a stable #cache_key method that is accompanied
|
29
|
+
# by a changing version in the #cache_version method on collections.
|
30
|
+
#
|
31
|
+
# This is +false+, by default until Rails 6.1.
|
32
|
+
class_attribute :collection_cache_versioning, instance_writer: false, default: false
|
25
33
|
end
|
26
34
|
|
27
35
|
# Returns a +String+, which Action Pack uses for constructing a URL to this
|
@@ -152,6 +160,10 @@ module ActiveRecord
|
|
152
160
|
end
|
153
161
|
end
|
154
162
|
end
|
163
|
+
|
164
|
+
def collection_cache_key(collection = all, timestamp_column = :updated_at) # :nodoc:
|
165
|
+
collection.send(:compute_cache_key, timestamp_column)
|
166
|
+
end
|
155
167
|
end
|
156
168
|
|
157
169
|
private
|
@@ -180,7 +192,7 @@ module ActiveRecord
|
|
180
192
|
# raw_timestamp_to_cache_version(timestamp)
|
181
193
|
# # => "20181015200215266505"
|
182
194
|
#
|
183
|
-
#
|
195
|
+
# PostgreSQL truncates trailing zeros,
|
184
196
|
# https://github.com/postgres/postgres/commit/3e1beda2cde3495f41290e1ece5d544525810214
|
185
197
|
# to account for this we pad the output with zeros
|
186
198
|
def raw_timestamp_to_cache_version(timestamp)
|
@@ -17,7 +17,7 @@ module ActiveRecord
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def table_name
|
20
|
-
"#{table_name_prefix}#{
|
20
|
+
"#{table_name_prefix}#{internal_metadata_table_name}#{table_name_suffix}"
|
21
21
|
end
|
22
22
|
|
23
23
|
def []=(key, value)
|
@@ -44,6 +44,10 @@ module ActiveRecord
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
47
|
+
|
48
|
+
def drop_table
|
49
|
+
connection.drop_table table_name, if_exists: true
|
50
|
+
end
|
47
51
|
end
|
48
52
|
end
|
49
53
|
end
|
@@ -71,9 +71,8 @@ module ActiveRecord
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def _touch_row(attribute_names, time)
|
74
|
+
@_touch_attr_names << self.class.locking_column if locking_enabled?
|
74
75
|
super
|
75
|
-
ensure
|
76
|
-
clear_attribute_change(self.class.locking_column) if locking_enabled?
|
77
76
|
end
|
78
77
|
|
79
78
|
def _update_row(attribute_names, attempted_action = "update")
|
@@ -88,7 +87,7 @@ module ActiveRecord
|
|
88
87
|
|
89
88
|
affected_rows = self.class._update_record(
|
90
89
|
attributes_with_values(attribute_names),
|
91
|
-
|
90
|
+
@primary_key => id_in_database,
|
92
91
|
locking_column => previous_lock_value
|
93
92
|
)
|
94
93
|
|
@@ -111,7 +110,7 @@ module ActiveRecord
|
|
111
110
|
locking_column = self.class.locking_column
|
112
111
|
|
113
112
|
affected_rows = self.class._delete_record(
|
114
|
-
|
113
|
+
@primary_key => id_in_database,
|
115
114
|
locking_column => read_attribute_before_type_cast(locking_column)
|
116
115
|
)
|
117
116
|
|
@@ -35,10 +35,10 @@ module ActiveRecord
|
|
35
35
|
# config.active_record.database_resolver = MyResolver
|
36
36
|
# config.active_record.database_resolver_context = MyResolver::MySession
|
37
37
|
class DatabaseSelector
|
38
|
-
def initialize(app, resolver_klass =
|
38
|
+
def initialize(app, resolver_klass = nil, context_klass = nil, options = {})
|
39
39
|
@app = app
|
40
|
-
@resolver_klass = resolver_klass
|
41
|
-
@context_klass = context_klass
|
40
|
+
@resolver_klass = resolver_klass || Resolver
|
41
|
+
@context_klass = context_klass || Resolver::Session
|
42
42
|
@options = options
|
43
43
|
end
|
44
44
|
|