activerecord 5.2.4.2 → 6.0.2
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 +714 -570
- data/MIT-LICENSE +3 -1
- data/README.rdoc +4 -2
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +9 -2
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/association_relation.rb +15 -6
- data/lib/active_record/associations.rb +20 -15
- data/lib/active_record/associations/association.rb +61 -20
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +3 -13
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- 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 +12 -23
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -10
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +28 -28
- data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +39 -31
- data/lib/active_record/associations/preloader/association.rb +38 -36
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -22
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -53
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +17 -24
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +2 -2
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +5 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +104 -16
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +99 -123
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +132 -53
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +187 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +138 -195
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +53 -43
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +75 -13
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +164 -74
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -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 +42 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +129 -141
- data/lib/active_record/connection_handling.rb +155 -26
- data/lib/active_record/core.rb +103 -59
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +37 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +145 -472
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +13 -3
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +10 -2
- data/lib/active_record/locking/optimistic.rb +5 -6
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +100 -81
- data/lib/active_record/migration/command_recorder.rb +50 -6
- data/lib/active_record/migration/compatibility.rb +76 -49
- data/lib/active_record/model_schema.rb +33 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +228 -24
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +32 -20
- data/lib/active_record/railtie.rb +80 -43
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +199 -46
- data/lib/active_record/reflection.rb +32 -30
- data/lib/active_record/relation.rb +311 -80
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +53 -47
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +23 -27
- data/lib/active_record/relation/merger.rb +11 -20
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +213 -64
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +14 -10
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +5 -1
- data/lib/active_record/scoping.rb +8 -8
- data/lib/active_record/scoping/default.rb +4 -5
- data/lib/active_record/scoping/named.rb +20 -15
- data/lib/active_record/statement_cache.rb +30 -3
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/table_metadata.rb +10 -17
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +225 -0
- data/lib/active_record/timestamp.rb +39 -25
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +56 -65
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/arel.rb +58 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- 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 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +110 -25
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -22,7 +22,7 @@ module ActiveRecord
|
|
22
22
|
end
|
23
23
|
|
24
24
|
if prepared_statements
|
25
|
-
sql, binds = visitor.
|
25
|
+
sql, binds = visitor.compile(arel_or_sql_string.ast, collector)
|
26
26
|
|
27
27
|
if binds.length > bind_params_length
|
28
28
|
unprepared_statement do
|
@@ -31,7 +31,7 @@ module ActiveRecord
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
else
|
34
|
-
sql = visitor.
|
34
|
+
sql = visitor.compile(arel_or_sql_string.ast, collector)
|
35
35
|
end
|
36
36
|
[sql.freeze, binds]
|
37
37
|
else
|
@@ -45,11 +45,11 @@ module ActiveRecord
|
|
45
45
|
# can be used to query the database repeatedly.
|
46
46
|
def cacheable_query(klass, arel) # :nodoc:
|
47
47
|
if prepared_statements
|
48
|
-
sql, binds = visitor.
|
48
|
+
sql, binds = visitor.compile(arel.ast, collector)
|
49
49
|
query = klass.query(sql)
|
50
50
|
else
|
51
|
-
collector =
|
52
|
-
parts, binds = visitor.
|
51
|
+
collector = klass.partial_query_collector
|
52
|
+
parts, binds = visitor.compile(arel.ast, collector)
|
53
53
|
query = klass.partial_query(parts)
|
54
54
|
end
|
55
55
|
[query, binds]
|
@@ -106,6 +106,11 @@ module ActiveRecord
|
|
106
106
|
exec_query(sql, name).rows
|
107
107
|
end
|
108
108
|
|
109
|
+
# Determines whether the SQL statement is a write query.
|
110
|
+
def write_query?(sql)
|
111
|
+
raise NotImplementedError
|
112
|
+
end
|
113
|
+
|
109
114
|
# Executes the SQL statement in the context of this connection and returns
|
110
115
|
# the raw result from the connection adapter.
|
111
116
|
# Note: depending on your database connector, the result returned by this
|
@@ -126,7 +131,7 @@ module ActiveRecord
|
|
126
131
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
127
132
|
# the executed +sql+ statement.
|
128
133
|
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
129
|
-
sql, binds = sql_for_insert(sql, pk,
|
134
|
+
sql, binds = sql_for_insert(sql, pk, binds)
|
130
135
|
exec_query(sql, name, binds)
|
131
136
|
end
|
132
137
|
|
@@ -137,11 +142,6 @@ module ActiveRecord
|
|
137
142
|
exec_query(sql, name, binds)
|
138
143
|
end
|
139
144
|
|
140
|
-
# Executes the truncate statement.
|
141
|
-
def truncate(table_name, name = nil)
|
142
|
-
raise NotImplementedError
|
143
|
-
end
|
144
|
-
|
145
145
|
# Executes update +sql+ statement in the context of this connection using
|
146
146
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
147
147
|
# the executed +sql+ statement.
|
@@ -149,6 +149,10 @@ module ActiveRecord
|
|
149
149
|
exec_query(sql, name, binds)
|
150
150
|
end
|
151
151
|
|
152
|
+
def exec_insert_all(sql, name) # :nodoc:
|
153
|
+
exec_query(sql, name)
|
154
|
+
end
|
155
|
+
|
152
156
|
# Executes an INSERT query and returns the new record's ID
|
153
157
|
#
|
154
158
|
# +id_value+ will be returned unless the value is +nil+, in
|
@@ -176,12 +180,22 @@ module ActiveRecord
|
|
176
180
|
exec_delete(sql, name, binds)
|
177
181
|
end
|
178
182
|
|
179
|
-
#
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
+
# Executes the truncate statement.
|
184
|
+
def truncate(table_name, name = nil)
|
185
|
+
execute(build_truncate_statements(table_name), name)
|
186
|
+
end
|
187
|
+
|
188
|
+
def truncate_tables(*table_names) # :nodoc:
|
189
|
+
return if table_names.empty?
|
190
|
+
|
191
|
+
with_multi_statements do
|
192
|
+
disable_referential_integrity do
|
193
|
+
Array(build_truncate_statements(*table_names)).each do |sql|
|
194
|
+
execute_batch(sql, "Truncate Tables")
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
183
198
|
end
|
184
|
-
deprecate :supports_statement_cache?
|
185
199
|
|
186
200
|
# Runs the given block in a database transaction, and returns the result
|
187
201
|
# of the block.
|
@@ -272,7 +286,9 @@ module ActiveRecord
|
|
272
286
|
|
273
287
|
attr_reader :transaction_manager #:nodoc:
|
274
288
|
|
275
|
-
delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
|
289
|
+
delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
|
290
|
+
:commit_transaction, :rollback_transaction, :materialize_transactions,
|
291
|
+
:disable_lazy_transactions!, :enable_lazy_transactions!, to: :transaction_manager
|
276
292
|
|
277
293
|
def transaction_open?
|
278
294
|
current_transaction.open?
|
@@ -337,68 +353,30 @@ module ActiveRecord
|
|
337
353
|
|
338
354
|
# Inserts the given fixture into the table. Overridden in adapters that require
|
339
355
|
# something beyond a simple insert (eg. Oracle).
|
340
|
-
# Most of adapters should implement `
|
356
|
+
# Most of adapters should implement `insert_fixtures_set` that leverages bulk SQL insert.
|
341
357
|
# We keep this method to provide fallback
|
342
358
|
# for databases like sqlite that do not support bulk inserts.
|
343
359
|
def insert_fixture(fixture, table_name)
|
344
|
-
fixture
|
345
|
-
|
346
|
-
columns = schema_cache.columns_hash(table_name)
|
347
|
-
binds = fixture.map do |name, value|
|
348
|
-
if column = columns[name]
|
349
|
-
type = lookup_cast_type_from_column(column)
|
350
|
-
Relation::QueryAttribute.new(name, value, type)
|
351
|
-
else
|
352
|
-
raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
|
353
|
-
end
|
354
|
-
end
|
355
|
-
|
356
|
-
table = Arel::Table.new(table_name)
|
357
|
-
|
358
|
-
values = binds.map do |bind|
|
359
|
-
value = with_yaml_fallback(bind.value_for_database)
|
360
|
-
[table[bind.name], value]
|
361
|
-
end
|
362
|
-
|
363
|
-
manager = Arel::InsertManager.new
|
364
|
-
manager.into(table)
|
365
|
-
manager.insert(values)
|
366
|
-
execute manager.to_sql, "Fixture Insert"
|
367
|
-
end
|
368
|
-
|
369
|
-
# Inserts a set of fixtures into the table. Overridden in adapters that require
|
370
|
-
# something beyond a simple insert (eg. Oracle).
|
371
|
-
def insert_fixtures(fixtures, table_name)
|
372
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
373
|
-
`insert_fixtures` is deprecated and will be removed in the next version of Rails.
|
374
|
-
Consider using `insert_fixtures_set` for performance improvement.
|
375
|
-
MSG
|
376
|
-
return if fixtures.empty?
|
377
|
-
|
378
|
-
execute(build_fixture_sql(fixtures, table_name), "Fixtures Insert")
|
360
|
+
execute(build_fixture_sql(Array.wrap(fixture), table_name), "Fixture Insert")
|
379
361
|
end
|
380
362
|
|
381
363
|
def insert_fixtures_set(fixture_set, tables_to_delete = [])
|
382
|
-
fixture_inserts = fixture_set
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
transaction(requires_new: true) do
|
393
|
-
total_sql.each do |sql|
|
394
|
-
execute sql, "Fixtures Load"
|
395
|
-
yield if block_given?
|
364
|
+
fixture_inserts = build_fixture_statements(fixture_set)
|
365
|
+
table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name(table)}" }
|
366
|
+
total_sql = Array(combine_multi_statements(table_deletes + fixture_inserts))
|
367
|
+
|
368
|
+
with_multi_statements do
|
369
|
+
disable_referential_integrity do
|
370
|
+
transaction(requires_new: true) do
|
371
|
+
total_sql.each do |sql|
|
372
|
+
execute_batch(sql, "Fixtures Load")
|
373
|
+
end
|
396
374
|
end
|
397
375
|
end
|
398
376
|
end
|
399
377
|
end
|
400
378
|
|
401
|
-
def empty_insert_statement_value
|
379
|
+
def empty_insert_statement_value(primary_key = nil)
|
402
380
|
"DEFAULT VALUES"
|
403
381
|
end
|
404
382
|
|
@@ -416,25 +394,33 @@ module ActiveRecord
|
|
416
394
|
end
|
417
395
|
end
|
418
396
|
|
419
|
-
#
|
420
|
-
#
|
421
|
-
#
|
422
|
-
def
|
423
|
-
|
424
|
-
|
425
|
-
|
397
|
+
# Fixture value is quoted by Arel, however scalar values
|
398
|
+
# are not quotable. In this case we want to convert
|
399
|
+
# the column value to YAML.
|
400
|
+
def with_yaml_fallback(value) # :nodoc:
|
401
|
+
if value.is_a?(Hash) || value.is_a?(Array)
|
402
|
+
YAML.dump(value)
|
403
|
+
else
|
404
|
+
value
|
405
|
+
end
|
426
406
|
end
|
427
|
-
alias join_to_delete join_to_update
|
428
407
|
|
429
408
|
private
|
409
|
+
def execute_batch(sql, name = nil)
|
410
|
+
execute(sql, name)
|
411
|
+
end
|
412
|
+
|
413
|
+
DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
|
414
|
+
private_constant :DEFAULT_INSERT_VALUE
|
415
|
+
|
430
416
|
def default_insert_value(column)
|
431
|
-
|
417
|
+
DEFAULT_INSERT_VALUE
|
432
418
|
end
|
433
419
|
|
434
420
|
def build_fixture_sql(fixtures, table_name)
|
435
421
|
columns = schema_cache.columns_hash(table_name)
|
436
422
|
|
437
|
-
|
423
|
+
values_list = fixtures.map do |fixture|
|
438
424
|
fixture = fixture.stringify_keys
|
439
425
|
|
440
426
|
unknown_columns = fixture.keys - columns.keys
|
@@ -445,8 +431,7 @@ module ActiveRecord
|
|
445
431
|
columns.map do |name, column|
|
446
432
|
if fixture.key?(name)
|
447
433
|
type = lookup_cast_type_from_column(column)
|
448
|
-
|
449
|
-
with_yaml_fallback(bind.value_for_database)
|
434
|
+
with_yaml_fallback(type.serialize(fixture[name]))
|
450
435
|
else
|
451
436
|
default_insert_value(column)
|
452
437
|
end
|
@@ -456,21 +441,45 @@ module ActiveRecord
|
|
456
441
|
table = Arel::Table.new(table_name)
|
457
442
|
manager = Arel::InsertManager.new
|
458
443
|
manager.into(table)
|
459
|
-
columns.each_key { |column| manager.columns << table[column] }
|
460
|
-
manager.values = manager.create_values_list(values)
|
461
444
|
|
445
|
+
if values_list.size == 1
|
446
|
+
values = values_list.shift
|
447
|
+
new_values = []
|
448
|
+
columns.each_key.with_index { |column, i|
|
449
|
+
unless values[i].equal?(DEFAULT_INSERT_VALUE)
|
450
|
+
new_values << values[i]
|
451
|
+
manager.columns << table[column]
|
452
|
+
end
|
453
|
+
}
|
454
|
+
values_list << new_values
|
455
|
+
else
|
456
|
+
columns.each_key { |column| manager.columns << table[column] }
|
457
|
+
end
|
458
|
+
|
459
|
+
manager.values = manager.create_values_list(values_list)
|
462
460
|
manager.to_sql
|
463
461
|
end
|
464
462
|
|
465
|
-
def
|
466
|
-
|
463
|
+
def build_fixture_statements(fixture_set)
|
464
|
+
fixture_set.map do |table_name, fixtures|
|
465
|
+
next if fixtures.empty?
|
466
|
+
build_fixture_sql(fixtures, table_name)
|
467
|
+
end.compact
|
468
|
+
end
|
469
|
+
|
470
|
+
def build_truncate_statements(*table_names)
|
471
|
+
truncate_tables = table_names.map do |table_name|
|
472
|
+
"TRUNCATE TABLE #{quote_table_name(table_name)}"
|
473
|
+
end
|
474
|
+
combine_multi_statements(truncate_tables)
|
467
475
|
end
|
468
476
|
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
477
|
+
def with_multi_statements
|
478
|
+
yield
|
479
|
+
end
|
480
|
+
|
481
|
+
def combine_multi_statements(total_sql)
|
482
|
+
total_sql.join(";\n")
|
474
483
|
end
|
475
484
|
|
476
485
|
# Returns an ActiveRecord::Result instance.
|
@@ -482,7 +491,7 @@ module ActiveRecord
|
|
482
491
|
exec_query(sql, name, binds, prepare: true)
|
483
492
|
end
|
484
493
|
|
485
|
-
def sql_for_insert(sql, pk,
|
494
|
+
def sql_for_insert(sql, pk, binds)
|
486
495
|
[sql, binds]
|
487
496
|
end
|
488
497
|
|
@@ -502,39 +511,6 @@ module ActiveRecord
|
|
502
511
|
relation
|
503
512
|
end
|
504
513
|
end
|
505
|
-
|
506
|
-
# Fixture value is quoted by Arel, however scalar values
|
507
|
-
# are not quotable. In this case we want to convert
|
508
|
-
# the column value to YAML.
|
509
|
-
def with_yaml_fallback(value)
|
510
|
-
if value.is_a?(Hash) || value.is_a?(Array)
|
511
|
-
YAML.dump(value)
|
512
|
-
else
|
513
|
-
value
|
514
|
-
end
|
515
|
-
end
|
516
|
-
|
517
|
-
class PartialQueryCollector
|
518
|
-
def initialize
|
519
|
-
@parts = []
|
520
|
-
@binds = []
|
521
|
-
end
|
522
|
-
|
523
|
-
def <<(str)
|
524
|
-
@parts << str
|
525
|
-
self
|
526
|
-
end
|
527
|
-
|
528
|
-
def add_bind(obj)
|
529
|
-
@binds << obj
|
530
|
-
@parts << Arel::Nodes::BindParam.new(1)
|
531
|
-
self
|
532
|
-
end
|
533
|
-
|
534
|
-
def value
|
535
|
-
[@parts, @binds]
|
536
|
-
end
|
537
|
-
end
|
538
514
|
end
|
539
515
|
end
|
540
516
|
end
|
@@ -7,7 +7,8 @@ module ActiveRecord
|
|
7
7
|
module QueryCache
|
8
8
|
class << self
|
9
9
|
def included(base) #:nodoc:
|
10
|
-
dirties_query_cache base, :insert, :update, :delete, :
|
10
|
+
dirties_query_cache base, :insert, :update, :delete, :truncate, :truncate_tables,
|
11
|
+
:rollback_to_savepoint, :rollback_db_transaction, :exec_insert_all
|
11
12
|
|
12
13
|
base.set_callback :checkout, :after, :configure_query_cache!
|
13
14
|
base.set_callback :checkin, :after, :disable_query_cache!
|
@@ -17,7 +18,7 @@ module ActiveRecord
|
|
17
18
|
method_names.each do |method_name|
|
18
19
|
base.class_eval <<-end_code, __FILE__, __LINE__ + 1
|
19
20
|
def #{method_name}(*)
|
20
|
-
|
21
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread if @query_cache_enabled
|
21
22
|
super
|
22
23
|
end
|
23
24
|
end_code
|
@@ -115,12 +116,7 @@ module ActiveRecord
|
|
115
116
|
if @query_cache[sql].key?(binds)
|
116
117
|
ActiveSupport::Notifications.instrument(
|
117
118
|
"sql.active_record",
|
118
|
-
sql
|
119
|
-
binds: binds,
|
120
|
-
type_casted_binds: -> { type_casted_binds(binds) },
|
121
|
-
name: name,
|
122
|
-
connection_id: object_id,
|
123
|
-
cached: true,
|
119
|
+
cache_notification_info(sql, name, binds)
|
124
120
|
)
|
125
121
|
@query_cache[sql][binds]
|
126
122
|
else
|
@@ -130,6 +126,20 @@ module ActiveRecord
|
|
130
126
|
end
|
131
127
|
end
|
132
128
|
|
129
|
+
# Database adapters can override this method to
|
130
|
+
# provide custom cache information.
|
131
|
+
def cache_notification_info(sql, name, binds)
|
132
|
+
{
|
133
|
+
sql: sql,
|
134
|
+
binds: binds,
|
135
|
+
type_casted_binds: -> { type_casted_binds(binds) },
|
136
|
+
name: name,
|
137
|
+
connection_id: object_id,
|
138
|
+
connection: self,
|
139
|
+
cached: true
|
140
|
+
}
|
141
|
+
end
|
142
|
+
|
133
143
|
# If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
|
134
144
|
# queries should not be cached.
|
135
145
|
def locked?(arel)
|
@@ -60,7 +60,7 @@ module ActiveRecord
|
|
60
60
|
# Quotes a string, escaping any ' (single quote) and \ (backslash)
|
61
61
|
# characters.
|
62
62
|
def quote_string(s)
|
63
|
-
s.gsub('\\'
|
63
|
+
s.gsub('\\', '\&\&').gsub("'", "''") # ' (for ruby-mode)
|
64
64
|
end
|
65
65
|
|
66
66
|
# Quotes the column name. Defaults to no quoting.
|
@@ -95,7 +95,7 @@ module ActiveRecord
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def quoted_true
|
98
|
-
"TRUE"
|
98
|
+
"TRUE"
|
99
99
|
end
|
100
100
|
|
101
101
|
def unquoted_true
|
@@ -103,7 +103,7 @@ module ActiveRecord
|
|
103
103
|
end
|
104
104
|
|
105
105
|
def quoted_false
|
106
|
-
"FALSE"
|
106
|
+
"FALSE"
|
107
107
|
end
|
108
108
|
|
109
109
|
def unquoted_false
|
@@ -138,15 +138,72 @@ module ActiveRecord
|
|
138
138
|
"'#{quote_string(value.to_s)}'"
|
139
139
|
end
|
140
140
|
|
141
|
-
def
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
141
|
+
def sanitize_as_sql_comment(value) # :nodoc:
|
142
|
+
value.to_s.gsub(%r{ (/ (?: | \g<1>) \*) \+? \s* | \s* (\* (?: | \g<2>) /) }x, "")
|
143
|
+
end
|
144
|
+
|
145
|
+
def column_name_matcher # :nodoc:
|
146
|
+
COLUMN_NAME
|
147
147
|
end
|
148
148
|
|
149
|
+
def column_name_with_order_matcher # :nodoc:
|
150
|
+
COLUMN_NAME_WITH_ORDER
|
151
|
+
end
|
152
|
+
|
153
|
+
# Regexp for column names (with or without a table name prefix).
|
154
|
+
# Matches the following:
|
155
|
+
#
|
156
|
+
# "#{table_name}.#{column_name}"
|
157
|
+
# "#{column_name}"
|
158
|
+
COLUMN_NAME = /
|
159
|
+
\A
|
160
|
+
(
|
161
|
+
(?:
|
162
|
+
# table_name.column_name | function(one or no argument)
|
163
|
+
((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
|
164
|
+
)
|
165
|
+
(?:\s+AS\s+\w+)?
|
166
|
+
)
|
167
|
+
(?:\s*,\s*\g<1>)*
|
168
|
+
\z
|
169
|
+
/ix
|
170
|
+
|
171
|
+
# Regexp for column names with order (with or without a table name prefix,
|
172
|
+
# with or without various order modifiers). Matches the following:
|
173
|
+
#
|
174
|
+
# "#{table_name}.#{column_name}"
|
175
|
+
# "#{table_name}.#{column_name} #{direction}"
|
176
|
+
# "#{table_name}.#{column_name} #{direction} NULLS FIRST"
|
177
|
+
# "#{table_name}.#{column_name} NULLS LAST"
|
178
|
+
# "#{column_name}"
|
179
|
+
# "#{column_name} #{direction}"
|
180
|
+
# "#{column_name} #{direction} NULLS FIRST"
|
181
|
+
# "#{column_name} NULLS LAST"
|
182
|
+
COLUMN_NAME_WITH_ORDER = /
|
183
|
+
\A
|
184
|
+
(
|
185
|
+
(?:
|
186
|
+
# table_name.column_name | function(one or no argument)
|
187
|
+
((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
|
188
|
+
)
|
189
|
+
(?:\s+ASC|\s+DESC)?
|
190
|
+
(?:\s+NULLS\s+(?:FIRST|LAST))?
|
191
|
+
)
|
192
|
+
(?:\s*,\s*\g<1>)*
|
193
|
+
\z
|
194
|
+
/ix
|
195
|
+
|
196
|
+
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
197
|
+
|
149
198
|
private
|
199
|
+
def type_casted_binds(binds)
|
200
|
+
if binds.first.is_a?(Array)
|
201
|
+
binds.map { |column, value| type_cast(value, column) }
|
202
|
+
else
|
203
|
+
binds.map { |attr| type_cast(attr.value_for_database) }
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
150
207
|
def lookup_cast_type(sql_type)
|
151
208
|
type_map.lookup(sql_type)
|
152
209
|
end
|
@@ -157,13 +214,9 @@ module ActiveRecord
|
|
157
214
|
end
|
158
215
|
end
|
159
216
|
|
160
|
-
def types_which_need_no_typecasting
|
161
|
-
[nil, Numeric, String]
|
162
|
-
end
|
163
|
-
|
164
217
|
def _quote(value)
|
165
218
|
case value
|
166
|
-
when String, ActiveSupport::Multibyte::Chars
|
219
|
+
when String, Symbol, ActiveSupport::Multibyte::Chars
|
167
220
|
"'#{quote_string(value.to_s)}'"
|
168
221
|
when true then quoted_true
|
169
222
|
when false then quoted_false
|
@@ -174,7 +227,6 @@ module ActiveRecord
|
|
174
227
|
when Type::Binary::Data then quoted_binary(value)
|
175
228
|
when Type::Time::Value then "'#{quoted_time(value)}'"
|
176
229
|
when Date, Time then "'#{quoted_date(value)}'"
|
177
|
-
when Symbol then "'#{quote_string(value.to_s)}'"
|
178
230
|
when Class then "'#{value}'"
|
179
231
|
else raise TypeError, "can't quote #{value.class.name}"
|
180
232
|
end
|
@@ -188,10 +240,9 @@ module ActiveRecord
|
|
188
240
|
when false then unquoted_false
|
189
241
|
# BigDecimals need to be put in a non-normalized form and quoted.
|
190
242
|
when BigDecimal then value.to_s("F")
|
243
|
+
when nil, Numeric, String then value
|
191
244
|
when Type::Time::Value then quoted_time(value)
|
192
245
|
when Date, Time then quoted_date(value)
|
193
|
-
when *types_which_need_no_typecasting
|
194
|
-
value
|
195
246
|
else raise TypeError
|
196
247
|
end
|
197
248
|
end
|