activerecord 5.1.7 → 5.2.6
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 +583 -673
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -5
- data/examples/performance.rb +2 -0
- data/examples/simple.rb +2 -0
- data/lib/active_record/aggregations.rb +6 -5
- data/lib/active_record/association_relation.rb +7 -5
- data/lib/active_record/associations/alias_tracker.rb +19 -27
- data/lib/active_record/associations/association.rb +41 -37
- data/lib/active_record/associations/association_scope.rb +38 -50
- data/lib/active_record/associations/belongs_to_association.rb +27 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +4 -7
- data/lib/active_record/associations/builder/belongs_to.rb +12 -4
- data/lib/active_record/associations/builder/collection_association.rb +3 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +2 -0
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +59 -47
- data/lib/active_record/associations/collection_proxy.rb +20 -49
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +12 -1
- data/lib/active_record/associations/has_many_through_association.rb +36 -30
- data/lib/active_record/associations/has_one_association.rb +12 -1
- data/lib/active_record/associations/has_one_through_association.rb +13 -8
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -63
- data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
- data/lib/active_record/associations/join_dependency.rb +48 -93
- data/lib/active_record/associations/preloader/association.rb +45 -61
- data/lib/active_record/associations/preloader/through_association.rb +71 -79
- data/lib/active_record/associations/preloader.rb +18 -38
- data/lib/active_record/associations/singular_association.rb +14 -16
- data/lib/active_record/associations/through_association.rb +26 -11
- data/lib/active_record/associations.rb +40 -63
- data/lib/active_record/attribute_assignment.rb +2 -5
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +30 -214
- data/lib/active_record/attribute_methods/primary_key.rb +7 -6
- data/lib/active_record/attribute_methods/query.rb +2 -0
- data/lib/active_record/attribute_methods/read.rb +9 -3
- data/lib/active_record/attribute_methods/serialization.rb +23 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
- data/lib/active_record/attribute_methods/write.rb +21 -9
- data/lib/active_record/attribute_methods.rb +65 -24
- data/lib/active_record/attributes.rb +6 -5
- data/lib/active_record/autosave_association.rb +35 -19
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +8 -6
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +2 -0
- data/lib/active_record/collection_cache_key.rb +12 -8
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +139 -41
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +174 -33
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +15 -5
- data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -31
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +152 -81
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
- data/lib/active_record/connection_adapters/abstract_adapter.rb +84 -97
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +92 -165
- data/lib/active_record/connection_adapters/column.rb +3 -1
- data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +233 -111
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +57 -73
- data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +81 -94
- data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
- data/lib/active_record/connection_handling.rb +4 -2
- data/lib/active_record/core.rb +41 -61
- data/lib/active_record/counter_cache.rb +10 -3
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +18 -13
- data/lib/active_record/errors.rb +42 -3
- data/lib/active_record/explain.rb +3 -1
- data/lib/active_record/explain_registry.rb +2 -0
- data/lib/active_record/explain_subscriber.rb +2 -0
- data/lib/active_record/fixture_set/file.rb +2 -0
- data/lib/active_record/fixtures.rb +67 -60
- data/lib/active_record/gem_version.rb +4 -2
- data/lib/active_record/inheritance.rb +49 -19
- data/lib/active_record/integration.rb +58 -19
- data/lib/active_record/internal_metadata.rb +2 -0
- data/lib/active_record/legacy_yaml_adapter.rb +3 -1
- data/lib/active_record/locking/optimistic.rb +14 -17
- data/lib/active_record/locking/pessimistic.rb +9 -6
- data/lib/active_record/log_subscriber.rb +43 -0
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +47 -9
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/migration.rb +189 -139
- data/lib/active_record/model_schema.rb +16 -21
- data/lib/active_record/nested_attributes.rb +18 -6
- data/lib/active_record/no_touching.rb +3 -1
- data/lib/active_record/null_relation.rb +2 -0
- data/lib/active_record/persistence.rb +167 -16
- data/lib/active_record/query_cache.rb +6 -8
- data/lib/active_record/querying.rb +4 -2
- data/lib/active_record/railtie.rb +62 -6
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +2 -0
- data/lib/active_record/railties/databases.rake +46 -36
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +108 -194
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/batches.rb +20 -5
- data/lib/active_record/relation/calculations.rb +45 -19
- data/lib/active_record/relation/delegation.rb +45 -27
- data/lib/active_record/relation/finder_methods.rb +75 -76
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +53 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +60 -79
- data/lib/active_record/relation/query_attribute.rb +28 -2
- data/lib/active_record/relation/query_methods.rb +128 -99
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -2
- data/lib/active_record/relation/where_clause.rb +65 -68
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- data/lib/active_record/relation.rb +120 -214
- data/lib/active_record/result.rb +2 -0
- data/lib/active_record/runtime_registry.rb +2 -0
- data/lib/active_record/sanitization.rb +129 -121
- data/lib/active_record/schema.rb +4 -2
- data/lib/active_record/schema_dumper.rb +36 -26
- data/lib/active_record/schema_migration.rb +2 -0
- data/lib/active_record/scoping/default.rb +8 -9
- data/lib/active_record/scoping/named.rb +23 -7
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/secure_token.rb +2 -0
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +23 -13
- data/lib/active_record/store.rb +3 -1
- data/lib/active_record/suppressor.rb +2 -0
- data/lib/active_record/table_metadata.rb +12 -3
- data/lib/active_record/tasks/database_tasks.rb +25 -14
- data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
- data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +33 -28
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +2 -0
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +2 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +2 -0
- data/lib/active_record/type/text.rb +2 -0
- data/lib/active_record/type/time.rb +2 -0
- data/lib/active_record/type/type_map.rb +2 -0
- data/lib/active_record/type/unsigned_integer.rb +2 -0
- data/lib/active_record/type.rb +4 -1
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.rb +2 -0
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +2 -0
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +2 -0
- data/lib/active_record/validations/uniqueness.rb +35 -5
- data/lib/active_record/validations.rb +2 -0
- data/lib/active_record/version.rb +2 -0
- data/lib/active_record.rb +11 -4
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration.rb +2 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +3 -1
- metadata +23 -36
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -15
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -18
- data/lib/active_record/attribute/user_provided_default.rb +0 -30
- data/lib/active_record/attribute.rb +0 -240
- data/lib/active_record/attribute_mutation_tracker.rb +0 -122
- data/lib/active_record/attribute_set/builder.rb +0 -126
- data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
- data/lib/active_record/attribute_set.rb +0 -113
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
- data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_record/relation/from_clause"
|
2
4
|
require "active_record/relation/query_attribute"
|
3
5
|
require "active_record/relation/where_clause"
|
@@ -74,31 +76,6 @@ module ActiveRecord
|
|
74
76
|
CODE
|
75
77
|
end
|
76
78
|
|
77
|
-
def bound_attributes
|
78
|
-
if limit_value
|
79
|
-
limit_bind = Attribute.with_cast_value(
|
80
|
-
"LIMIT".freeze,
|
81
|
-
connection.sanitize_limit(limit_value),
|
82
|
-
Type.default_value,
|
83
|
-
)
|
84
|
-
end
|
85
|
-
if offset_value
|
86
|
-
offset_bind = Attribute.with_cast_value(
|
87
|
-
"OFFSET".freeze,
|
88
|
-
offset_value.to_i,
|
89
|
-
Type.default_value,
|
90
|
-
)
|
91
|
-
end
|
92
|
-
connection.combine_bind_parameters(
|
93
|
-
from_clause: from_clause.binds,
|
94
|
-
join_clause: arel.bind_values,
|
95
|
-
where_clause: where_clause.binds,
|
96
|
-
having_clause: having_clause.binds,
|
97
|
-
limit: limit_bind,
|
98
|
-
offset: offset_bind,
|
99
|
-
)
|
100
|
-
end
|
101
|
-
|
102
79
|
alias extensions extending_values
|
103
80
|
|
104
81
|
# Specify relationships to be included in the result set. For
|
@@ -202,12 +179,13 @@ module ActiveRecord
|
|
202
179
|
|
203
180
|
# Works in two unique ways.
|
204
181
|
#
|
205
|
-
# First: takes a block so it can be used just like
|
182
|
+
# First: takes a block so it can be used just like <tt>Array#select</tt>.
|
206
183
|
#
|
207
184
|
# Model.all.select { |m| m.field == value }
|
208
185
|
#
|
209
186
|
# This will build an array of objects from the database for the scope,
|
210
|
-
# converting them into an array and iterating through them using
|
187
|
+
# converting them into an array and iterating through them using
|
188
|
+
# <tt>Array#select</tt>.
|
211
189
|
#
|
212
190
|
# Second: Modifies the SELECT statement for the query so that only certain
|
213
191
|
# fields are retrieved:
|
@@ -248,15 +226,12 @@ module ActiveRecord
|
|
248
226
|
return super()
|
249
227
|
end
|
250
228
|
|
251
|
-
raise ArgumentError, "Call
|
229
|
+
raise ArgumentError, "Call `select' with at least one field" if fields.empty?
|
252
230
|
spawn._select!(*fields)
|
253
231
|
end
|
254
232
|
|
255
233
|
def _select!(*fields) # :nodoc:
|
256
234
|
fields.flatten!
|
257
|
-
fields.map! do |field|
|
258
|
-
klass.attribute_alias?(field) ? klass.attribute_alias(field).to_sym : field
|
259
|
-
end
|
260
235
|
self.select_values += fields
|
261
236
|
self
|
262
237
|
end
|
@@ -317,6 +292,7 @@ module ActiveRecord
|
|
317
292
|
spawn.order!(*args)
|
318
293
|
end
|
319
294
|
|
295
|
+
# Same as #order but operates on relation in-place instead of copying.
|
320
296
|
def order!(*args) # :nodoc:
|
321
297
|
preprocess_order_args(args)
|
322
298
|
|
@@ -338,6 +314,7 @@ module ActiveRecord
|
|
338
314
|
spawn.reorder!(*args)
|
339
315
|
end
|
340
316
|
|
317
|
+
# Same as #reorder but operates on relation in-place instead of copying.
|
341
318
|
def reorder!(*args) # :nodoc:
|
342
319
|
preprocess_order_args(args)
|
343
320
|
|
@@ -347,8 +324,8 @@ module ActiveRecord
|
|
347
324
|
end
|
348
325
|
|
349
326
|
VALID_UNSCOPING_VALUES = Set.new([:where, :select, :group, :order, :lock,
|
350
|
-
:limit, :offset, :joins, :
|
351
|
-
:readonly, :having])
|
327
|
+
:limit, :offset, :joins, :left_outer_joins,
|
328
|
+
:includes, :from, :readonly, :having])
|
352
329
|
|
353
330
|
# Removes an unwanted relation that is already defined on a chain of relations.
|
354
331
|
# This is useful when passing around chains of relations and would like to
|
@@ -395,10 +372,11 @@ module ActiveRecord
|
|
395
372
|
args.each do |scope|
|
396
373
|
case scope
|
397
374
|
when Symbol
|
375
|
+
scope = :left_outer_joins if scope == :left_joins
|
398
376
|
if !VALID_UNSCOPING_VALUES.include?(scope)
|
399
377
|
raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
|
400
378
|
end
|
401
|
-
set_value(scope,
|
379
|
+
set_value(scope, DEFAULT_VALUES[scope])
|
402
380
|
when Hash
|
403
381
|
scope.each do |key, target_value|
|
404
382
|
if key != :where
|
@@ -463,16 +441,14 @@ module ActiveRecord
|
|
463
441
|
# => SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
|
464
442
|
#
|
465
443
|
def left_outer_joins(*args)
|
466
|
-
check_if_method_has_arguments!(
|
467
|
-
|
468
|
-
args.compact!
|
469
|
-
args.flatten!
|
470
|
-
|
444
|
+
check_if_method_has_arguments!(__callee__, args)
|
471
445
|
spawn.left_outer_joins!(*args)
|
472
446
|
end
|
473
447
|
alias :left_joins :left_outer_joins
|
474
448
|
|
475
449
|
def left_outer_joins!(*args) # :nodoc:
|
450
|
+
args.compact!
|
451
|
+
args.flatten!
|
476
452
|
self.left_outer_joins_values += args
|
477
453
|
self
|
478
454
|
end
|
@@ -657,6 +633,7 @@ module ActiveRecord
|
|
657
633
|
|
658
634
|
self.where_clause = self.where_clause.or(other.where_clause)
|
659
635
|
self.having_clause = having_clause.or(other.having_clause)
|
636
|
+
self.references_values += other.references_values
|
660
637
|
|
661
638
|
self
|
662
639
|
end
|
@@ -797,7 +774,7 @@ module ActiveRecord
|
|
797
774
|
value = sanitize_forbidden_attributes(value)
|
798
775
|
self.create_with_value = create_with_value.merge(value)
|
799
776
|
else
|
800
|
-
self.create_with_value =
|
777
|
+
self.create_with_value = FROZEN_EMPTY_HASH
|
801
778
|
end
|
802
779
|
|
803
780
|
self
|
@@ -913,21 +890,28 @@ module ActiveRecord
|
|
913
890
|
self
|
914
891
|
end
|
915
892
|
|
893
|
+
def skip_query_cache!(value = true) # :nodoc:
|
894
|
+
self.skip_query_cache_value = value
|
895
|
+
self
|
896
|
+
end
|
897
|
+
|
916
898
|
# Returns the Arel object associated with the relation.
|
917
|
-
def arel # :nodoc:
|
918
|
-
@arel ||= build_arel
|
899
|
+
def arel(aliases = nil) # :nodoc:
|
900
|
+
@arel ||= build_arel(aliases)
|
919
901
|
end
|
920
902
|
|
921
903
|
# Returns a relation value with a given name
|
922
904
|
def get_value(name) # :nodoc:
|
923
|
-
@values[name]
|
905
|
+
@values.fetch(name, DEFAULT_VALUES[name])
|
924
906
|
end
|
925
907
|
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
908
|
+
protected
|
909
|
+
|
910
|
+
# Sets the relation value with the given name
|
911
|
+
def set_value(name, value) # :nodoc:
|
912
|
+
assert_mutability!
|
913
|
+
@values[name] = value
|
914
|
+
end
|
931
915
|
|
932
916
|
private
|
933
917
|
|
@@ -936,16 +920,30 @@ module ActiveRecord
|
|
936
920
|
raise ImmutableRelation if defined?(@arel) && @arel
|
937
921
|
end
|
938
922
|
|
939
|
-
def build_arel
|
923
|
+
def build_arel(aliases)
|
940
924
|
arel = Arel::SelectManager.new(table)
|
941
925
|
|
942
|
-
build_joins(arel, joins_values.flatten) unless joins_values.empty?
|
943
|
-
build_left_outer_joins(arel, left_outer_joins_values.flatten) unless left_outer_joins_values.empty?
|
926
|
+
aliases = build_joins(arel, joins_values.flatten, aliases) unless joins_values.empty?
|
927
|
+
build_left_outer_joins(arel, left_outer_joins_values.flatten, aliases) unless left_outer_joins_values.empty?
|
944
928
|
|
945
929
|
arel.where(where_clause.ast) unless where_clause.empty?
|
946
930
|
arel.having(having_clause.ast) unless having_clause.empty?
|
947
|
-
|
948
|
-
|
931
|
+
if limit_value
|
932
|
+
limit_attribute = ActiveModel::Attribute.with_cast_value(
|
933
|
+
"LIMIT".freeze,
|
934
|
+
connection.sanitize_limit(limit_value),
|
935
|
+
Type.default_value,
|
936
|
+
)
|
937
|
+
arel.take(Arel::Nodes::BindParam.new(limit_attribute))
|
938
|
+
end
|
939
|
+
if offset_value
|
940
|
+
offset_attribute = ActiveModel::Attribute.with_cast_value(
|
941
|
+
"OFFSET".freeze,
|
942
|
+
offset_value.to_i,
|
943
|
+
Type.default_value,
|
944
|
+
)
|
945
|
+
arel.skip(Arel::Nodes::BindParam.new(offset_attribute))
|
946
|
+
end
|
949
947
|
arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty?
|
950
948
|
|
951
949
|
build_order(arel)
|
@@ -964,6 +962,9 @@ module ActiveRecord
|
|
964
962
|
name = from_clause.name
|
965
963
|
case opts
|
966
964
|
when Relation
|
965
|
+
if opts.eager_loading?
|
966
|
+
opts = opts.send(:apply_join_dependency)
|
967
|
+
end
|
967
968
|
name ||= "subquery"
|
968
969
|
opts.arel.as(name.to_s)
|
969
970
|
else
|
@@ -971,20 +972,22 @@ module ActiveRecord
|
|
971
972
|
end
|
972
973
|
end
|
973
974
|
|
974
|
-
def build_left_outer_joins(manager, outer_joins)
|
975
|
+
def build_left_outer_joins(manager, outer_joins, aliases)
|
975
976
|
buckets = outer_joins.group_by do |join|
|
976
977
|
case join
|
977
978
|
when Hash, Symbol, Array
|
978
979
|
:association_join
|
980
|
+
when ActiveRecord::Associations::JoinDependency
|
981
|
+
:stashed_join
|
979
982
|
else
|
980
983
|
raise ArgumentError, "only Hash, Symbol and Array are allowed"
|
981
984
|
end
|
982
985
|
end
|
983
986
|
|
984
|
-
build_join_query(manager, buckets, Arel::Nodes::OuterJoin)
|
987
|
+
build_join_query(manager, buckets, Arel::Nodes::OuterJoin, aliases)
|
985
988
|
end
|
986
989
|
|
987
|
-
def build_joins(manager, joins)
|
990
|
+
def build_joins(manager, joins, aliases)
|
988
991
|
buckets = joins.group_by do |join|
|
989
992
|
case join
|
990
993
|
when String
|
@@ -1000,38 +1003,33 @@ module ActiveRecord
|
|
1000
1003
|
end
|
1001
1004
|
end
|
1002
1005
|
|
1003
|
-
build_join_query(manager, buckets, Arel::Nodes::InnerJoin)
|
1006
|
+
build_join_query(manager, buckets, Arel::Nodes::InnerJoin, aliases)
|
1004
1007
|
end
|
1005
1008
|
|
1006
|
-
def build_join_query(manager, buckets, join_type)
|
1009
|
+
def build_join_query(manager, buckets, join_type, aliases)
|
1007
1010
|
buckets.default = []
|
1008
1011
|
|
1009
|
-
association_joins
|
1010
|
-
|
1011
|
-
join_nodes
|
1012
|
-
string_joins
|
1012
|
+
association_joins = buckets[:association_join]
|
1013
|
+
stashed_joins = buckets[:stashed_join]
|
1014
|
+
join_nodes = buckets[:join_node].uniq
|
1015
|
+
string_joins = buckets[:string_join].map(&:strip).uniq
|
1013
1016
|
|
1014
|
-
join_list = join_nodes + convert_join_strings_to_ast(
|
1017
|
+
join_list = join_nodes + convert_join_strings_to_ast(string_joins)
|
1018
|
+
alias_tracker = alias_tracker(join_list, aliases)
|
1015
1019
|
|
1016
1020
|
join_dependency = ActiveRecord::Associations::JoinDependency.new(
|
1017
|
-
|
1018
|
-
association_joins,
|
1019
|
-
join_list
|
1021
|
+
klass, table, association_joins
|
1020
1022
|
)
|
1021
1023
|
|
1022
|
-
|
1023
|
-
|
1024
|
-
join_infos.each do |info|
|
1025
|
-
info.joins.each { |join| manager.from(join) }
|
1026
|
-
manager.bind_values.concat info.binds
|
1027
|
-
end
|
1024
|
+
joins = join_dependency.join_constraints(stashed_joins, join_type, alias_tracker)
|
1025
|
+
joins.each { |join| manager.from(join) }
|
1028
1026
|
|
1029
1027
|
manager.join_sources.concat(join_list)
|
1030
1028
|
|
1031
|
-
|
1029
|
+
alias_tracker.aliases
|
1032
1030
|
end
|
1033
1031
|
|
1034
|
-
def convert_join_strings_to_ast(
|
1032
|
+
def convert_join_strings_to_ast(joins)
|
1035
1033
|
joins
|
1036
1034
|
.flatten
|
1037
1035
|
.reject(&:blank?)
|
@@ -1044,22 +1042,42 @@ module ActiveRecord
|
|
1044
1042
|
elsif klass.ignored_columns.any?
|
1045
1043
|
arel.project(*klass.column_names.map { |field| arel_attribute(field) })
|
1046
1044
|
else
|
1047
|
-
arel.project(
|
1045
|
+
arel.project(table[Arel.star])
|
1048
1046
|
end
|
1049
1047
|
end
|
1050
1048
|
|
1051
1049
|
def arel_columns(columns)
|
1052
|
-
columns.
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1050
|
+
columns.flat_map do |field|
|
1051
|
+
case field
|
1052
|
+
when Symbol
|
1053
|
+
arel_column(field.to_s) do |attr_name|
|
1054
|
+
connection.quote_table_name(attr_name)
|
1055
|
+
end
|
1056
|
+
when String
|
1057
|
+
arel_column(field, &:itself)
|
1058
|
+
when Proc
|
1059
|
+
field.call
|
1057
1060
|
else
|
1058
1061
|
field
|
1059
1062
|
end
|
1060
1063
|
end
|
1061
1064
|
end
|
1062
1065
|
|
1066
|
+
def arel_column(field)
|
1067
|
+
field = klass.attribute_alias(field) if klass.attribute_alias?(field)
|
1068
|
+
from = from_clause.name || from_clause.value
|
1069
|
+
|
1070
|
+
if klass.columns_hash.key?(field) && (!from || table_name_matches?(from))
|
1071
|
+
arel_attribute(field)
|
1072
|
+
else
|
1073
|
+
yield field
|
1074
|
+
end
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
def table_name_matches?(from)
|
1078
|
+
/(?:\A|(?<!FROM)\s)(?:\b#{table.name}\b|#{connection.quote_table_name(table.name)})(?!\.)/i.match?(from.to_s)
|
1079
|
+
end
|
1080
|
+
|
1063
1081
|
def reverse_sql_order(order_query)
|
1064
1082
|
if order_query.empty?
|
1065
1083
|
return [arel_attribute(primary_key).desc] if primary_key
|
@@ -1088,6 +1106,10 @@ module ActiveRecord
|
|
1088
1106
|
end
|
1089
1107
|
|
1090
1108
|
def does_not_support_reverse?(order)
|
1109
|
+
# Account for String subclasses like Arel::Nodes::SqlLiteral that
|
1110
|
+
# override methods like #count.
|
1111
|
+
order = String.new(order) unless order.instance_of?(String)
|
1112
|
+
|
1091
1113
|
# Uses SQL function with multiple arguments.
|
1092
1114
|
(order.include?(",") && order.split(",").find { |section| section.count("(") != section.count(")") }) ||
|
1093
1115
|
# Uses "nulls first" like construction.
|
@@ -1102,41 +1124,49 @@ module ActiveRecord
|
|
1102
1124
|
end
|
1103
1125
|
|
1104
1126
|
VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
|
1105
|
-
"asc", "desc", "ASC", "DESC"] # :nodoc:
|
1127
|
+
"asc", "desc", "ASC", "DESC"].to_set # :nodoc:
|
1106
1128
|
|
1107
1129
|
def validate_order_args(args)
|
1108
1130
|
args.each do |arg|
|
1109
1131
|
next unless arg.is_a?(Hash)
|
1110
1132
|
arg.each do |_key, value|
|
1111
|
-
|
1112
|
-
|
1133
|
+
unless VALID_DIRECTIONS.include?(value)
|
1134
|
+
raise ArgumentError,
|
1135
|
+
"Direction \"#{value}\" is invalid. Valid directions are: #{VALID_DIRECTIONS.to_a.inspect}"
|
1136
|
+
end
|
1113
1137
|
end
|
1114
1138
|
end
|
1115
1139
|
end
|
1116
1140
|
|
1117
1141
|
def preprocess_order_args(order_args)
|
1118
1142
|
order_args.map! do |arg|
|
1119
|
-
klass.
|
1143
|
+
klass.sanitize_sql_for_order(arg)
|
1120
1144
|
end
|
1121
1145
|
order_args.flatten!
|
1146
|
+
|
1147
|
+
@klass.enforce_raw_sql_whitelist(
|
1148
|
+
order_args.flat_map { |a| a.is_a?(Hash) ? a.keys : a },
|
1149
|
+
whitelist: AttributeMethods::ClassMethods::COLUMN_NAME_ORDER_WHITELIST
|
1150
|
+
)
|
1151
|
+
|
1122
1152
|
validate_order_args(order_args)
|
1123
1153
|
|
1124
1154
|
references = order_args.grep(String)
|
1125
|
-
references.map! { |arg| arg =~
|
1155
|
+
references.map! { |arg| arg =~ /^\W?(\w+)\W?\./ && $1 }.compact!
|
1126
1156
|
references!(references) if references.any?
|
1127
1157
|
|
1128
1158
|
# if a symbol is given we prepend the quoted table name
|
1129
1159
|
order_args.map! do |arg|
|
1130
1160
|
case arg
|
1131
1161
|
when Symbol
|
1132
|
-
|
1162
|
+
order_column(arg.to_s).asc
|
1133
1163
|
when Hash
|
1134
1164
|
arg.map { |field, dir|
|
1135
1165
|
case field
|
1136
1166
|
when Arel::Nodes::SqlLiteral
|
1137
1167
|
field.send(dir.downcase)
|
1138
1168
|
else
|
1139
|
-
|
1169
|
+
order_column(field.to_s).send(dir.downcase)
|
1140
1170
|
end
|
1141
1171
|
}
|
1142
1172
|
else
|
@@ -1145,6 +1175,16 @@ module ActiveRecord
|
|
1145
1175
|
end.flatten!
|
1146
1176
|
end
|
1147
1177
|
|
1178
|
+
def order_column(field)
|
1179
|
+
arel_column(field) do |attr_name|
|
1180
|
+
if attr_name == "count" && !group_values.empty?
|
1181
|
+
arel_attribute(attr_name)
|
1182
|
+
else
|
1183
|
+
Arel.sql(connection.quote_table_name(attr_name))
|
1184
|
+
end
|
1185
|
+
end
|
1186
|
+
end
|
1187
|
+
|
1148
1188
|
# Checks to make sure that the arguments are not blank. Note that if some
|
1149
1189
|
# blank-like object were initially passed into the query method, then this
|
1150
1190
|
# method will not raise an error.
|
@@ -1167,7 +1207,7 @@ module ActiveRecord
|
|
1167
1207
|
end
|
1168
1208
|
end
|
1169
1209
|
|
1170
|
-
STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having]
|
1210
|
+
STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having, :unscope, :references]
|
1171
1211
|
def structurally_incompatible_values_for_or(other)
|
1172
1212
|
STRUCTURAL_OR_METHODS.reject do |method|
|
1173
1213
|
get_value(method) == other.get_value(method)
|
@@ -1181,7 +1221,6 @@ module ActiveRecord
|
|
1181
1221
|
|
1182
1222
|
DEFAULT_VALUES = {
|
1183
1223
|
create_with: FROZEN_EMPTY_HASH,
|
1184
|
-
readonly: false,
|
1185
1224
|
where: Relation::WhereClause.empty,
|
1186
1225
|
having: Relation::WhereClause.empty,
|
1187
1226
|
from: Relation::FromClause.empty
|
@@ -1190,15 +1229,5 @@ module ActiveRecord
|
|
1190
1229
|
Relation::MULTI_VALUE_METHODS.each do |value|
|
1191
1230
|
DEFAULT_VALUES[value] ||= FROZEN_EMPTY_ARRAY
|
1192
1231
|
end
|
1193
|
-
|
1194
|
-
Relation::SINGLE_VALUE_METHODS.each do |value|
|
1195
|
-
DEFAULT_VALUES[value] = nil if DEFAULT_VALUES[value].nil?
|
1196
|
-
end
|
1197
|
-
|
1198
|
-
def default_value_for(name)
|
1199
|
-
DEFAULT_VALUES.fetch(name) do
|
1200
|
-
raise ArgumentError, "unknown relation value #{name.inspect}"
|
1201
|
-
end
|
1202
|
-
end
|
1203
1232
|
end
|
1204
1233
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/hash/except"
|
2
4
|
require "active_support/core_ext/hash/slice"
|
3
5
|
require "active_record/relation/merger"
|
@@ -6,7 +8,7 @@ module ActiveRecord
|
|
6
8
|
module SpawnMethods
|
7
9
|
# This is overridden by Associations::CollectionProxy
|
8
10
|
def spawn #:nodoc:
|
9
|
-
clone
|
11
|
+
@delegate_to_klass ? klass.all : clone
|
10
12
|
end
|
11
13
|
|
12
14
|
# Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an ActiveRecord::Relation.
|
@@ -67,7 +69,7 @@ module ActiveRecord
|
|
67
69
|
private
|
68
70
|
|
69
71
|
def relation_with(values)
|
70
|
-
result = Relation.create(klass,
|
72
|
+
result = Relation.create(klass, values: values)
|
71
73
|
result.extend(*extending_values) if extending_values.any?
|
72
74
|
result
|
73
75
|
end
|