activerecord 4.1.16 → 4.2.0.beta1
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 +634 -2185
- data/README.rdoc +15 -10
- data/lib/active_record.rb +2 -1
- data/lib/active_record/aggregations.rb +12 -8
- data/lib/active_record/associations.rb +58 -33
- data/lib/active_record/associations/association.rb +1 -1
- data/lib/active_record/associations/association_scope.rb +53 -21
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -11
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +32 -44
- data/lib/active_record/associations/collection_proxy.rb +1 -10
- data/lib/active_record/associations/has_many_association.rb +60 -14
- data/lib/active_record/associations/has_many_through_association.rb +34 -23
- data/lib/active_record/associations/has_one_association.rb +0 -1
- data/lib/active_record/associations/join_dependency.rb +7 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +18 -14
- data/lib/active_record/associations/preloader.rb +2 -2
- data/lib/active_record/associations/preloader/association.rb +9 -5
- data/lib/active_record/associations/preloader/through_association.rb +3 -3
- data/lib/active_record/associations/singular_association.rb +16 -1
- data/lib/active_record/associations/through_association.rb +6 -22
- data/lib/active_record/attribute.rb +131 -0
- data/lib/active_record/attribute_assignment.rb +19 -11
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods.rb +53 -90
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
- data/lib/active_record/attribute_methods/dirty.rb +85 -42
- data/lib/active_record/attribute_methods/primary_key.rb +6 -8
- data/lib/active_record/attribute_methods/read.rb +14 -57
- data/lib/active_record/attribute_methods/serialization.rb +12 -146
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +32 -40
- data/lib/active_record/attribute_methods/write.rb +8 -23
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attribute_set/builder.rb +32 -0
- data/lib/active_record/attributes.rb +122 -0
- data/lib/active_record/autosave_association.rb +11 -21
- data/lib/active_record/base.rb +9 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +69 -45
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -42
- data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -60
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +37 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +102 -21
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +9 -33
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +178 -55
- data/lib/active_record/connection_adapters/abstract/transaction.rb +120 -115
- data/lib/active_record/connection_adapters/abstract_adapter.rb +143 -57
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +156 -107
- data/lib/active_record/connection_adapters/column.rb +13 -244
- data/lib/active_record/connection_adapters/connection_specification.rb +6 -20
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -15
- data/lib/active_record/connection_adapters/mysql_adapter.rb +55 -143
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -20
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +96 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +85 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +42 -122
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +154 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +86 -34
- data/lib/active_record/connection_adapters/postgresql/utils.rb +66 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +188 -452
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -47
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +119 -22
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +9 -10
- data/lib/active_record/errors.rb +27 -26
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixtures.rb +52 -45
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +33 -8
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/locking/optimistic.rb +34 -16
- data/lib/active_record/migration.rb +22 -32
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/model_schema.rb +39 -48
- data/lib/active_record/nested_attributes.rb +8 -18
- data/lib/active_record/persistence.rb +39 -22
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +1 -8
- data/lib/active_record/railtie.rb +17 -10
- data/lib/active_record/railties/databases.rake +47 -42
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +225 -92
- data/lib/active_record/relation.rb +35 -11
- data/lib/active_record/relation/batches.rb +0 -2
- data/lib/active_record/relation/calculations.rb +28 -32
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +42 -20
- data/lib/active_record/relation/merger.rb +0 -1
- data/lib/active_record/relation/predicate_builder.rb +1 -22
- data/lib/active_record/relation/predicate_builder/array_handler.rb +16 -11
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +0 -4
- data/lib/active_record/relation/query_methods.rb +98 -62
- data/lib/active_record/relation/spawn_methods.rb +6 -7
- data/lib/active_record/result.rb +16 -9
- data/lib/active_record/sanitization.rb +8 -1
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +51 -9
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping/default.rb +5 -4
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +79 -5
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +37 -5
- data/lib/active_record/tasks/mysql_database_tasks.rb +10 -16
- data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -2
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +35 -21
- data/lib/active_record/type.rb +20 -0
- data/lib/active_record/type/binary.rb +40 -0
- data/lib/active_record/type/boolean.rb +19 -0
- data/lib/active_record/type/date.rb +46 -0
- data/lib/active_record/type/date_time.rb +43 -0
- data/lib/active_record/type/decimal.rb +40 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +19 -0
- data/lib/active_record/type/integer.rb +23 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +51 -0
- data/lib/active_record/type/string.rb +36 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +48 -0
- data/lib/active_record/type/value.rb +101 -0
- data/lib/active_record/validations.rb +21 -16
- data/lib/active_record/validations/uniqueness.rb +9 -23
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +71 -14
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -1,4 +1,5 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
+
require 'arel/collectors/bind'
|
2
3
|
|
3
4
|
module ActiveRecord
|
4
5
|
# = Active Record Relation
|
@@ -11,6 +12,7 @@ module ActiveRecord
|
|
11
12
|
|
12
13
|
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering,
|
13
14
|
:reverse_order, :distinct, :create_with, :uniq]
|
15
|
+
INVALID_METHODS_FOR_DELETE_ALL = [:limit, :distinct, :offset, :group, :having]
|
14
16
|
|
15
17
|
VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS
|
16
18
|
|
@@ -230,6 +232,7 @@ module ActiveRecord
|
|
230
232
|
# Please see further details in the
|
231
233
|
# {Active Record Query Interface guide}[http://guides.rubyonrails.org/active_record_querying.html#running-explain].
|
232
234
|
def explain
|
235
|
+
#TODO: Fix for binds.
|
233
236
|
exec_explain(collecting_queries_for_explain { exec_queries })
|
234
237
|
end
|
235
238
|
|
@@ -239,6 +242,11 @@ module ActiveRecord
|
|
239
242
|
@records
|
240
243
|
end
|
241
244
|
|
245
|
+
# Serializes the relation objects Array.
|
246
|
+
def encode_with(coder)
|
247
|
+
coder.represent_seq(nil, to_a)
|
248
|
+
end
|
249
|
+
|
242
250
|
def as_json(options = nil) #:nodoc:
|
243
251
|
to_a.as_json(options)
|
244
252
|
end
|
@@ -330,7 +338,8 @@ module ActiveRecord
|
|
330
338
|
stmt.wheres = arel.constraints
|
331
339
|
end
|
332
340
|
|
333
|
-
|
341
|
+
bvs = bind_values + arel.bind_values
|
342
|
+
@klass.connection.update stmt, 'SQL', bvs
|
334
343
|
end
|
335
344
|
|
336
345
|
# Updates an object (or multiple objects) and saves it to the database, if validations pass.
|
@@ -434,12 +443,21 @@ module ActiveRecord
|
|
434
443
|
# If you need to destroy dependent associations or call your <tt>before_*</tt> or
|
435
444
|
# +after_destroy+ callbacks, use the +destroy_all+ method instead.
|
436
445
|
#
|
437
|
-
# If
|
446
|
+
# If an invalid method is supplied, +delete_all+ raises an ActiveRecord error:
|
438
447
|
#
|
439
448
|
# Post.limit(100).delete_all
|
440
|
-
# # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit
|
449
|
+
# # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit
|
441
450
|
def delete_all(conditions = nil)
|
442
|
-
|
451
|
+
invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select { |method|
|
452
|
+
if MULTI_VALUE_METHODS.include?(method)
|
453
|
+
send("#{method}_values").any?
|
454
|
+
else
|
455
|
+
send("#{method}_value")
|
456
|
+
end
|
457
|
+
}
|
458
|
+
if invalid_methods.any?
|
459
|
+
raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
|
460
|
+
end
|
443
461
|
|
444
462
|
if conditions
|
445
463
|
where(conditions).delete_all
|
@@ -523,11 +541,11 @@ module ActiveRecord
|
|
523
541
|
find_with_associations { |rel| relation = rel }
|
524
542
|
end
|
525
543
|
|
526
|
-
|
527
|
-
binds = relation.bind_values.dup
|
528
|
-
|
529
|
-
|
530
|
-
|
544
|
+
arel = relation.arel
|
545
|
+
binds = (arel.bind_values + relation.bind_values).dup
|
546
|
+
binds.map! { |bv| connection.quote(*bv.reverse) }
|
547
|
+
collect = visitor.accept(arel.ast, Arel::Collectors::Bind.new)
|
548
|
+
collect.substitute_binds(binds).join
|
531
549
|
end
|
532
550
|
end
|
533
551
|
|
@@ -544,7 +562,13 @@ module ActiveRecord
|
|
544
562
|
|
545
563
|
Hash[equalities.map { |where|
|
546
564
|
name = where.left.name
|
547
|
-
[name, binds.fetch(name.to_s) {
|
565
|
+
[name, binds.fetch(name.to_s) {
|
566
|
+
case where.right
|
567
|
+
when Array then where.right.map(&:val)
|
568
|
+
else
|
569
|
+
where.right.val
|
570
|
+
end
|
571
|
+
}]
|
548
572
|
}]
|
549
573
|
end
|
550
574
|
|
@@ -608,7 +632,7 @@ module ActiveRecord
|
|
608
632
|
private
|
609
633
|
|
610
634
|
def exec_queries
|
611
|
-
@records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, bind_values)
|
635
|
+
@records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, arel.bind_values + bind_values)
|
612
636
|
|
613
637
|
preload = preload_values
|
614
638
|
preload += includes_values unless eager_loading?
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
module ActiveRecord
|
3
2
|
module Batches
|
4
3
|
# Looping through a collection of records from the database
|
@@ -115,7 +114,6 @@ module ActiveRecord
|
|
115
114
|
end
|
116
115
|
|
117
116
|
relation = relation.reorder(batch_order).limit(batch_size)
|
118
|
-
relation.reverse_order_value = false
|
119
117
|
records = start ? relation.where(table[primary_key].gteq(start)).to_a : relation.to_a
|
120
118
|
|
121
119
|
while records.any?
|
@@ -19,14 +19,22 @@ module ActiveRecord
|
|
19
19
|
#
|
20
20
|
# Person.group(:city).count
|
21
21
|
# # => { 'Rome' => 5, 'Paris' => 3 }
|
22
|
-
#
|
22
|
+
#
|
23
|
+
# If +count+ is used with +group+ for multiple columns, it returns a Hash whose
|
24
|
+
# keys are an array containing the individual values of each column and the value
|
25
|
+
# of each key would be the +count+.
|
26
|
+
#
|
27
|
+
# Article.group(:status, :category).count
|
28
|
+
# # => {["draft", "business"]=>10, ["draft", "technology"]=>4,
|
29
|
+
# ["published", "business"]=>0, ["published", "technology"]=>2}
|
30
|
+
#
|
23
31
|
# If +count+ is used with +select+, it will count the selected columns:
|
24
32
|
#
|
25
33
|
# Person.select(:age).count
|
26
34
|
# # => counts the number of different age values
|
27
35
|
#
|
28
36
|
# Note: not all valid +select+ expressions are valid +count+ expressions. The specifics differ
|
29
|
-
# between databases. In invalid cases, an error from the
|
37
|
+
# between databases. In invalid cases, an error from the database is thrown.
|
30
38
|
def count(column_name = nil, options = {})
|
31
39
|
# TODO: Remove options argument as soon we remove support to
|
32
40
|
# activerecord-deprecated_finders.
|
@@ -170,21 +178,7 @@ module ActiveRecord
|
|
170
178
|
columns_hash.key?(cn) ? arel_table[cn] : cn
|
171
179
|
}
|
172
180
|
result = klass.connection.select_all(relation.arel, nil, bind_values)
|
173
|
-
|
174
|
-
klass.column_types.fetch(key) {
|
175
|
-
result.column_types.fetch(key) { result.identity_type }
|
176
|
-
}
|
177
|
-
end
|
178
|
-
|
179
|
-
result = result.rows.map do |values|
|
180
|
-
values = result.columns.zip(values).map do |column_name, value|
|
181
|
-
single_attr_hash = { column_name => value }
|
182
|
-
klass.initialize_attributes(single_attr_hash).values.first
|
183
|
-
end
|
184
|
-
|
185
|
-
columns.zip(values).map { |column, value| column.type_cast value }
|
186
|
-
end
|
187
|
-
columns.one? ? result.map!(&:first) : result
|
181
|
+
result.cast_values(klass.column_types)
|
188
182
|
end
|
189
183
|
end
|
190
184
|
|
@@ -246,11 +240,14 @@ module ActiveRecord
|
|
246
240
|
|
247
241
|
column_alias = column_name
|
248
242
|
|
243
|
+
bind_values = nil
|
244
|
+
|
249
245
|
if operation == "count" && (relation.limit_value || relation.offset_value)
|
250
246
|
# Shortcut when limit is zero.
|
251
247
|
return 0 if relation.limit_value == 0
|
252
248
|
|
253
249
|
query_builder = build_count_subquery(relation, column_name, distinct)
|
250
|
+
bind_values = query_builder.bind_values + relation.bind_values
|
254
251
|
else
|
255
252
|
column = aggregate_column(column_name)
|
256
253
|
|
@@ -260,13 +257,14 @@ module ActiveRecord
|
|
260
257
|
relation.select_values = [select_value]
|
261
258
|
|
262
259
|
query_builder = relation.arel
|
260
|
+
bind_values = query_builder.bind_values + relation.bind_values
|
263
261
|
end
|
264
262
|
|
265
|
-
result = @klass.connection.select_all(query_builder, nil,
|
263
|
+
result = @klass.connection.select_all(query_builder, nil, bind_values)
|
266
264
|
row = result.first
|
267
265
|
value = row && row.values.first
|
268
266
|
column = result.column_types.fetch(column_alias) do
|
269
|
-
|
267
|
+
type_for(column_name)
|
270
268
|
end
|
271
269
|
|
272
270
|
type_cast_calculated_value(value, column, operation)
|
@@ -277,7 +275,7 @@ module ActiveRecord
|
|
277
275
|
|
278
276
|
if group_attrs.first.respond_to?(:to_sym)
|
279
277
|
association = @klass._reflect_on_association(group_attrs.first.to_sym)
|
280
|
-
associated = group_attrs.size == 1 && association && association.
|
278
|
+
associated = group_attrs.size == 1 && association && association.belongs_to? # only count belongs_to associations
|
281
279
|
group_fields = Array(associated ? association.foreign_key : group_attrs)
|
282
280
|
else
|
283
281
|
group_fields = group_attrs
|
@@ -329,14 +327,14 @@ module ActiveRecord
|
|
329
327
|
Hash[calculated_data.map do |row|
|
330
328
|
key = group_columns.map { |aliaz, col_name|
|
331
329
|
column = calculated_data.column_types.fetch(aliaz) do
|
332
|
-
|
330
|
+
type_for(col_name)
|
333
331
|
end
|
334
332
|
type_cast_calculated_value(row[aliaz], column)
|
335
333
|
}
|
336
334
|
key = key.first if key.size == 1
|
337
335
|
key = key_records[key] if associated
|
338
336
|
|
339
|
-
column_type = calculated_data.column_types.fetch(aggregate_alias) {
|
337
|
+
column_type = calculated_data.column_types.fetch(aggregate_alias) { type_for(column_name) }
|
340
338
|
[key, type_cast_calculated_value(row[aggregate_alias], column_type, operation)]
|
341
339
|
end]
|
342
340
|
end
|
@@ -363,24 +361,20 @@ module ActiveRecord
|
|
363
361
|
@klass.connection.table_alias_for(table_name)
|
364
362
|
end
|
365
363
|
|
366
|
-
def
|
364
|
+
def type_for(field)
|
367
365
|
field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split('.').last
|
368
|
-
@klass.
|
366
|
+
@klass.type_for_attribute(field_name)
|
369
367
|
end
|
370
368
|
|
371
|
-
def type_cast_calculated_value(value,
|
369
|
+
def type_cast_calculated_value(value, type, operation = nil)
|
372
370
|
case operation
|
373
371
|
when 'count' then value.to_i
|
374
|
-
when 'sum' then
|
372
|
+
when 'sum' then type.type_cast_from_database(value || 0)
|
375
373
|
when 'average' then value.respond_to?(:to_d) ? value.to_d : value
|
376
|
-
else
|
374
|
+
else type.type_cast_from_database(value)
|
377
375
|
end
|
378
376
|
end
|
379
377
|
|
380
|
-
def type_cast_using_column(value, column)
|
381
|
-
column ? column.type_cast(value) : value
|
382
|
-
end
|
383
|
-
|
384
378
|
# TODO: refactor to allow non-string `select_values` (eg. Arel nodes).
|
385
379
|
def select_for_count
|
386
380
|
if select_values.present?
|
@@ -396,9 +390,11 @@ module ActiveRecord
|
|
396
390
|
|
397
391
|
aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias)
|
398
392
|
relation.select_values = [aliased_column]
|
399
|
-
|
393
|
+
arel = relation.arel
|
394
|
+
subquery = arel.as(subquery_alias)
|
400
395
|
|
401
396
|
sm = Arel::SelectManager.new relation.engine
|
397
|
+
sm.bind_values = arel.bind_values
|
402
398
|
select_value = operation_over_aggregate_column(column_alias, 'count', distinct)
|
403
399
|
sm.project(select_value).from(subquery)
|
404
400
|
end
|
@@ -40,7 +40,7 @@ module ActiveRecord
|
|
40
40
|
BLACKLISTED_ARRAY_METHODS = [
|
41
41
|
:compact!, :flatten!, :reject!, :reverse!, :rotate!, :map!,
|
42
42
|
:shuffle!, :slice!, :sort!, :sort_by!, :delete_if,
|
43
|
-
:keep_if, :pop, :shift, :delete_at, :select!
|
43
|
+
:keep_if, :pop, :shift, :delete_at, :compact, :select!
|
44
44
|
].to_set # :nodoc:
|
45
45
|
|
46
46
|
delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join, to: :to_a
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/deprecation'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module FinderMethods
|
3
5
|
ONE_AS_ONE = '1 AS one'
|
@@ -127,9 +129,9 @@ module ActiveRecord
|
|
127
129
|
#
|
128
130
|
def first(limit = nil)
|
129
131
|
if limit
|
130
|
-
find_nth_with_limit(
|
132
|
+
find_nth_with_limit(offset_index, limit)
|
131
133
|
else
|
132
|
-
find_nth(
|
134
|
+
find_nth(0, offset_index)
|
133
135
|
end
|
134
136
|
end
|
135
137
|
|
@@ -179,7 +181,7 @@ module ActiveRecord
|
|
179
181
|
# Person.offset(3).second # returns the second object from OFFSET 3 (which is OFFSET 4)
|
180
182
|
# Person.where(["user_name = :u", { u: user_name }]).second
|
181
183
|
def second
|
182
|
-
find_nth(
|
184
|
+
find_nth(1, offset_index)
|
183
185
|
end
|
184
186
|
|
185
187
|
# Same as +second+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
|
@@ -195,7 +197,7 @@ module ActiveRecord
|
|
195
197
|
# Person.offset(3).third # returns the third object from OFFSET 3 (which is OFFSET 5)
|
196
198
|
# Person.where(["user_name = :u", { u: user_name }]).third
|
197
199
|
def third
|
198
|
-
find_nth(
|
200
|
+
find_nth(2, offset_index)
|
199
201
|
end
|
200
202
|
|
201
203
|
# Same as +third+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
|
@@ -211,7 +213,7 @@ module ActiveRecord
|
|
211
213
|
# Person.offset(3).fourth # returns the fourth object from OFFSET 3 (which is OFFSET 6)
|
212
214
|
# Person.where(["user_name = :u", { u: user_name }]).fourth
|
213
215
|
def fourth
|
214
|
-
find_nth(
|
216
|
+
find_nth(3, offset_index)
|
215
217
|
end
|
216
218
|
|
217
219
|
# Same as +fourth+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
|
@@ -227,7 +229,7 @@ module ActiveRecord
|
|
227
229
|
# Person.offset(3).fifth # returns the fifth object from OFFSET 3 (which is OFFSET 7)
|
228
230
|
# Person.where(["user_name = :u", { u: user_name }]).fifth
|
229
231
|
def fifth
|
230
|
-
find_nth(
|
232
|
+
find_nth(4, offset_index)
|
231
233
|
end
|
232
234
|
|
233
235
|
# Same as +fifth+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
|
@@ -243,7 +245,7 @@ module ActiveRecord
|
|
243
245
|
# Person.offset(3).forty_two # returns the forty-second object from OFFSET 3 (which is OFFSET 44)
|
244
246
|
# Person.where(["user_name = :u", { u: user_name }]).forty_two
|
245
247
|
def forty_two
|
246
|
-
find_nth(
|
248
|
+
find_nth(41, offset_index)
|
247
249
|
end
|
248
250
|
|
249
251
|
# Same as +forty_two+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
|
@@ -280,7 +282,12 @@ module ActiveRecord
|
|
280
282
|
# Person.exists?(false)
|
281
283
|
# Person.exists?
|
282
284
|
def exists?(conditions = :none)
|
283
|
-
|
285
|
+
if Base === conditions
|
286
|
+
conditions = conditions.id
|
287
|
+
ActiveSupport::Deprecation.warn "You are passing an instance of ActiveRecord::Base to `exists?`." \
|
288
|
+
"Please pass the id of the object by calling `.id`"
|
289
|
+
end
|
290
|
+
|
284
291
|
return false if !conditions
|
285
292
|
|
286
293
|
relation = apply_join_dependency(self, construct_join_dependency)
|
@@ -292,10 +299,12 @@ module ActiveRecord
|
|
292
299
|
when Array, Hash
|
293
300
|
relation = relation.where(conditions)
|
294
301
|
else
|
295
|
-
|
302
|
+
unless conditions == :none
|
303
|
+
relation = where(primary_key => conditions)
|
304
|
+
end
|
296
305
|
end
|
297
306
|
|
298
|
-
connection.select_value(relation, "#{name} Exists", relation.bind_values) ? true : false
|
307
|
+
connection.select_value(relation, "#{name} Exists", relation.arel.bind_values + relation.bind_values) ? true : false
|
299
308
|
end
|
300
309
|
|
301
310
|
# This method is called whenever no records are found with either a single
|
@@ -322,6 +331,10 @@ module ActiveRecord
|
|
322
331
|
|
323
332
|
private
|
324
333
|
|
334
|
+
def offset_index
|
335
|
+
offset_value || 0
|
336
|
+
end
|
337
|
+
|
325
338
|
def find_with_associations
|
326
339
|
# NOTE: the JoinDependency constructed here needs to know about
|
327
340
|
# any joins already present in `self`, so pass them in
|
@@ -344,7 +357,8 @@ module ActiveRecord
|
|
344
357
|
if ActiveRecord::NullRelation === relation
|
345
358
|
[]
|
346
359
|
else
|
347
|
-
|
360
|
+
arel = relation.arel
|
361
|
+
rows = connection.select_all(arel, 'SQL', arel.bind_values + relation.bind_values)
|
348
362
|
join_dependency.instantiate(rows, aliases)
|
349
363
|
end
|
350
364
|
end
|
@@ -358,7 +372,7 @@ module ActiveRecord
|
|
358
372
|
def construct_relation_for_association_calculations
|
359
373
|
from = arel.froms.first
|
360
374
|
if Arel::Table === from
|
361
|
-
apply_join_dependency(self, construct_join_dependency
|
375
|
+
apply_join_dependency(self, construct_join_dependency)
|
362
376
|
else
|
363
377
|
# FIXME: as far as I can tell, `from` will always be an Arel::Table.
|
364
378
|
# There are no tests that test this branch, but presumably it's
|
@@ -418,7 +432,11 @@ module ActiveRecord
|
|
418
432
|
end
|
419
433
|
|
420
434
|
def find_one(id)
|
421
|
-
|
435
|
+
if ActiveRecord::Base === id
|
436
|
+
id = id.id
|
437
|
+
ActiveSupport::Deprecation.warn "You are passing an instance of ActiveRecord::Base to `find`." \
|
438
|
+
"Please pass the id of the object by calling `.id`"
|
439
|
+
end
|
422
440
|
|
423
441
|
column = columns_hash[primary_key]
|
424
442
|
substitute = connection.substitute_at(column, bind_values.length)
|
@@ -461,20 +479,24 @@ module ActiveRecord
|
|
461
479
|
end
|
462
480
|
end
|
463
481
|
|
464
|
-
def find_nth(
|
482
|
+
def find_nth(index, offset)
|
465
483
|
if loaded?
|
466
|
-
@records
|
484
|
+
@records[index]
|
467
485
|
else
|
486
|
+
offset += index
|
468
487
|
@offsets[offset] ||= find_nth_with_limit(offset, 1).first
|
469
488
|
end
|
470
489
|
end
|
471
490
|
|
472
491
|
def find_nth_with_limit(offset, limit)
|
473
|
-
if order_values.empty? && primary_key
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
492
|
+
relation = if order_values.empty? && primary_key
|
493
|
+
order(arel_table[primary_key].asc)
|
494
|
+
else
|
495
|
+
self
|
496
|
+
end
|
497
|
+
|
498
|
+
relation = relation.offset(offset) unless offset.zero?
|
499
|
+
relation.limit(limit).to_a
|
478
500
|
end
|
479
501
|
|
480
502
|
def find_last
|
@@ -147,7 +147,6 @@ module ActiveRecord
|
|
147
147
|
def merge_single_values
|
148
148
|
relation.from_value = values[:from] unless relation.from_value
|
149
149
|
relation.lock_value = values[:lock] unless relation.lock_value
|
150
|
-
relation.reverse_order_value = values[:reverse_order]
|
151
150
|
|
152
151
|
unless values[:create_with].blank?
|
153
152
|
relation.create_with_value = (relation.create_with_value || {}).merge(values[:create_with])
|
@@ -56,17 +56,11 @@ module ActiveRecord
|
|
56
56
|
# For polymorphic relationships, find the foreign key and type:
|
57
57
|
# PriceEstimate.where(estimate_of: treasure)
|
58
58
|
if klass && reflection = klass._reflect_on_association(column.to_sym)
|
59
|
-
base_class = polymorphic_base_class_from_value(value)
|
60
|
-
if reflection.polymorphic? && base_class
|
59
|
+
if reflection.polymorphic? && base_class = polymorphic_base_class_from_value(value)
|
61
60
|
queries << build(table[reflection.foreign_type], base_class)
|
62
61
|
end
|
63
62
|
|
64
63
|
column = reflection.foreign_key
|
65
|
-
|
66
|
-
if base_class
|
67
|
-
primary_key = reflection.association_primary_key(base_class)
|
68
|
-
value = convert_value_to_association_ids(value, primary_key)
|
69
|
-
end
|
70
64
|
end
|
71
65
|
|
72
66
|
queries << build(table[column], value)
|
@@ -119,8 +113,6 @@ module ActiveRecord
|
|
119
113
|
register_handler(Relation, RelationHandler.new)
|
120
114
|
register_handler(Array, ArrayHandler.new)
|
121
115
|
|
122
|
-
private
|
123
|
-
|
124
116
|
def self.build(attribute, value)
|
125
117
|
handler_for(value).call(attribute, value)
|
126
118
|
end
|
@@ -130,18 +122,5 @@ module ActiveRecord
|
|
130
122
|
@handlers.detect { |klass, _| klass === object }.last
|
131
123
|
end
|
132
124
|
private_class_method :handler_for
|
133
|
-
|
134
|
-
def self.convert_value_to_association_ids(value, primary_key)
|
135
|
-
case value
|
136
|
-
when Relation
|
137
|
-
value.select(primary_key)
|
138
|
-
when Array
|
139
|
-
value.map { |v| convert_value_to_association_ids(v, primary_key) }
|
140
|
-
when Base
|
141
|
-
value.read_attribute(primary_key)
|
142
|
-
else
|
143
|
-
value
|
144
|
-
end
|
145
|
-
end
|
146
125
|
end
|
147
126
|
end
|