activerecord 6.0.0.beta3 → 6.0.0.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 +286 -6
- data/README.rdoc +3 -1
- data/lib/active_record.rb +0 -1
- data/lib/active_record/associations.rb +3 -2
- data/lib/active_record/associations/association.rb +1 -1
- 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 +3 -13
- 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_proxy.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +4 -11
- data/lib/active_record/associations/preloader.rb +11 -6
- data/lib/active_record/associations/preloader/association.rb +32 -30
- data/lib/active_record/associations/preloader/through_association.rb +48 -28
- data/lib/active_record/attribute_methods.rb +4 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +42 -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 +13 -3
- data/lib/active_record/base.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +84 -61
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +10 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -7
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +70 -14
- data/lib/active_record/connection_adapters/abstract_adapter.rb +56 -11
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +65 -69
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -7
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +9 -6
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +6 -2
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +5 -1
- 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 +57 -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 +118 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +50 -112
- data/lib/active_record/connection_handling.rb +17 -10
- data/lib/active_record/core.rb +15 -20
- data/lib/active_record/database_configurations.rb +14 -14
- 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 +6 -0
- data/lib/active_record/errors.rb +1 -1
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/insert_all.rb +180 -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/migration.rb +25 -18
- data/lib/active_record/migration/command_recorder.rb +28 -14
- data/lib/active_record/migration/compatibility.rb +10 -0
- data/lib/active_record/persistence.rb +206 -13
- data/lib/active_record/querying.rb +17 -12
- data/lib/active_record/railties/databases.rake +68 -6
- data/lib/active_record/reflection.rb +2 -2
- data/lib/active_record/relation.rb +98 -20
- data/lib/active_record/relation/calculations.rb +39 -39
- data/lib/active_record/relation/delegation.rb +22 -30
- data/lib/active_record/relation/finder_methods.rb +3 -9
- data/lib/active_record/relation/merger.rb +7 -16
- data/lib/active_record/relation/query_methods.rb +153 -38
- data/lib/active_record/relation/where_clause.rb +9 -5
- data/lib/active_record/sanitization.rb +3 -2
- data/lib/active_record/schema_dumper.rb +5 -0
- 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 +1 -1
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/store.rb +48 -0
- data/lib/active_record/table_metadata.rb +3 -3
- data/lib/active_record/tasks/database_tasks.rb +36 -1
- data/lib/active_record/touch_later.rb +2 -2
- data/lib/active_record/transactions.rb +52 -41
- data/lib/active_record/validations/uniqueness.rb +3 -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 +6 -1
- 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 +87 -108
- 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 +12 -11
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/arel/nodes/values.rb +0 -16
@@ -7,7 +7,7 @@ require "active_record/database_configurations/url_config"
|
|
7
7
|
module ActiveRecord
|
8
8
|
# ActiveRecord::DatabaseConfigurations returns an array of DatabaseConfig
|
9
9
|
# objects (either a HashConfig or UrlConfig) that are constructed from the
|
10
|
-
# application's database configuration hash or
|
10
|
+
# application's database configuration hash or URL string.
|
11
11
|
class DatabaseConfigurations
|
12
12
|
attr_reader :configurations
|
13
13
|
delegate :any?, to: :configurations
|
@@ -17,22 +17,22 @@ module ActiveRecord
|
|
17
17
|
end
|
18
18
|
|
19
19
|
# Collects the configs for the environment and optionally the specification
|
20
|
-
# name passed in. To include replica configurations pass
|
20
|
+
# name passed in. To include replica configurations pass <tt>include_replicas: true</tt>.
|
21
21
|
#
|
22
22
|
# If a spec name is provided a single DatabaseConfig object will be
|
23
23
|
# returned, otherwise an array of DatabaseConfig objects will be
|
24
24
|
# returned that corresponds with the environment and type requested.
|
25
25
|
#
|
26
|
-
# Options
|
26
|
+
# ==== Options
|
27
27
|
#
|
28
|
-
# <tt>env_name:</tt> The environment name. Defaults to +nil+ which will collect
|
29
|
-
#
|
30
|
-
# <tt>spec_name:</tt> The specification name (i.e. primary, animals, etc.). Defaults
|
31
|
-
#
|
32
|
-
# <tt>include_replicas:</tt> Determines whether to include replicas in
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
28
|
+
# * <tt>env_name:</tt> The environment name. Defaults to +nil+ which will collect
|
29
|
+
# configs for all environments.
|
30
|
+
# * <tt>spec_name:</tt> The specification name (i.e. primary, animals, etc.). Defaults
|
31
|
+
# to +nil+.
|
32
|
+
# * <tt>include_replicas:</tt> Determines whether to include replicas in
|
33
|
+
# the returned list. Most of the time we're only iterating over the write
|
34
|
+
# connection (i.e. migrations don't need to run for the write and read connection).
|
35
|
+
# Defaults to +false+.
|
36
36
|
def configs_for(env_name: nil, spec_name: nil, include_replicas: false)
|
37
37
|
configs = env_with_configs(env_name)
|
38
38
|
|
@@ -53,7 +53,7 @@ module ActiveRecord
|
|
53
53
|
|
54
54
|
# Returns the config hash that corresponds with the environment
|
55
55
|
#
|
56
|
-
# If the application has multiple databases
|
56
|
+
# If the application has multiple databases +default_hash+ will
|
57
57
|
# return the first config hash for the environment.
|
58
58
|
#
|
59
59
|
# { database: "my_db", adapter: "mysql2" }
|
@@ -65,7 +65,7 @@ module ActiveRecord
|
|
65
65
|
|
66
66
|
# Returns a single DatabaseConfig object based on the requested environment.
|
67
67
|
#
|
68
|
-
# If the application has multiple databases
|
68
|
+
# If the application has multiple databases +find_db_config+ will return
|
69
69
|
# the first DatabaseConfig for the environment.
|
70
70
|
def find_db_config(env)
|
71
71
|
configurations.find do |db_config|
|
@@ -106,7 +106,7 @@ module ActiveRecord
|
|
106
106
|
|
107
107
|
build_db_config = configs.each_pair.flat_map do |env_name, config|
|
108
108
|
walk_configs(env_name.to_s, "primary", config)
|
109
|
-
end.compact
|
109
|
+
end.flatten.compact
|
110
110
|
|
111
111
|
if url = ENV["DATABASE_URL"]
|
112
112
|
build_url_config(url, build_db_config)
|
@@ -14,16 +14,16 @@ module ActiveRecord
|
|
14
14
|
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10
|
15
15
|
# @env_name="development", @spec_name="primary", @config={"database"=>"db_name"}>
|
16
16
|
#
|
17
|
-
# Options
|
17
|
+
# ==== Options
|
18
18
|
#
|
19
|
-
# <tt>:env_name</tt> - The Rails environment, i.e. "development"
|
20
|
-
# <tt>:spec_name</tt> - The specification name. In a standard two-tier
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
# <tt>:config</tt> - The config hash. This is the hash that contains the
|
25
|
-
#
|
26
|
-
#
|
19
|
+
# * <tt>:env_name</tt> - The Rails environment, i.e. "development".
|
20
|
+
# * <tt>:spec_name</tt> - The specification name. In a standard two-tier
|
21
|
+
# database configuration this will default to "primary". In a multiple
|
22
|
+
# database three-tier database configuration this corresponds to the name
|
23
|
+
# used in the second tier, for example "primary_readonly".
|
24
|
+
# * <tt>:config</tt> - The config hash. This is the hash that contains the
|
25
|
+
# database adapter, name, and other important information for database
|
26
|
+
# connections.
|
27
27
|
class HashConfig < DatabaseConfig
|
28
28
|
attr_reader :config
|
29
29
|
|
@@ -33,14 +33,14 @@ module ActiveRecord
|
|
33
33
|
end
|
34
34
|
|
35
35
|
# Determines whether a database configuration is for a replica / readonly
|
36
|
-
# connection. If the
|
36
|
+
# connection. If the +replica+ key is present in the config, +replica?+ will
|
37
37
|
# return +true+.
|
38
38
|
def replica?
|
39
39
|
config["replica"]
|
40
40
|
end
|
41
41
|
|
42
42
|
# The migrations paths for a database configuration. If the
|
43
|
-
#
|
43
|
+
# +migrations_paths+ key is present in the config, +migrations_paths+
|
44
44
|
# will return its value.
|
45
45
|
def migrations_paths
|
46
46
|
config["migrations_paths"]
|
@@ -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,13 @@ 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
|
200
203
|
klass.send(:detect_enum_conflict!, name, value_method_name, true)
|
201
204
|
klass.scope value_method_name, -> { where(attr => value) }
|
205
|
+
|
206
|
+
klass.send(:detect_enum_conflict!, name, "not_#{value_method_name}", true)
|
207
|
+
klass.scope "not_#{value_method_name}", -> { where.not(attr => value) }
|
202
208
|
end
|
203
209
|
end
|
204
210
|
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
|
|
@@ -0,0 +1,180 @@
|
|
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_query 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
|
+
|
114
|
+
class Builder
|
115
|
+
attr_reader :model
|
116
|
+
|
117
|
+
delegate :skip_duplicates?, :update_duplicates?, :keys, to: :insert_all
|
118
|
+
|
119
|
+
def initialize(insert_all)
|
120
|
+
@insert_all, @model, @connection = insert_all, insert_all.model, insert_all.connection
|
121
|
+
end
|
122
|
+
|
123
|
+
def into
|
124
|
+
"INTO #{model.quoted_table_name}(#{columns_list})"
|
125
|
+
end
|
126
|
+
|
127
|
+
def values_list
|
128
|
+
types = extract_types_from_columns_on(model.table_name, keys: keys)
|
129
|
+
|
130
|
+
values_list = insert_all.map_key_with_value do |key, value|
|
131
|
+
connection.with_yaml_fallback(types[key].serialize(value))
|
132
|
+
end
|
133
|
+
|
134
|
+
Arel::InsertManager.new.create_values_list(values_list).to_sql
|
135
|
+
end
|
136
|
+
|
137
|
+
def returning
|
138
|
+
format_columns(insert_all.returning) if insert_all.returning
|
139
|
+
end
|
140
|
+
|
141
|
+
def conflict_target
|
142
|
+
if index = insert_all.unique_by
|
143
|
+
sql = +"(#{format_columns(index.columns)})"
|
144
|
+
sql << " WHERE #{index.where}" if index.where
|
145
|
+
sql
|
146
|
+
elsif update_duplicates?
|
147
|
+
"(#{format_columns(insert_all.primary_keys)})"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def updatable_columns
|
152
|
+
quote_columns(insert_all.updatable_columns)
|
153
|
+
end
|
154
|
+
|
155
|
+
private
|
156
|
+
attr_reader :connection, :insert_all
|
157
|
+
|
158
|
+
def columns_list
|
159
|
+
format_columns(insert_all.keys)
|
160
|
+
end
|
161
|
+
|
162
|
+
def extract_types_from_columns_on(table_name, keys:)
|
163
|
+
columns = connection.schema_cache.columns_hash(table_name)
|
164
|
+
|
165
|
+
unknown_column = (keys - columns.keys).first
|
166
|
+
raise UnknownAttributeError.new(model.new, unknown_column) if unknown_column
|
167
|
+
|
168
|
+
keys.map { |key| [ key, connection.lookup_cast_type_from_column(columns[key]) ] }.to_h
|
169
|
+
end
|
170
|
+
|
171
|
+
def format_columns(columns)
|
172
|
+
quote_columns(columns).join(",")
|
173
|
+
end
|
174
|
+
|
175
|
+
def quote_columns(columns)
|
176
|
+
columns.map(&connection.method(:quote_column_name))
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
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
|
|