activerecord 4.0.13 → 4.1.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 +745 -2700
- data/README.rdoc +2 -2
- data/examples/performance.rb +30 -18
- data/examples/simple.rb +4 -4
- data/lib/active_record.rb +2 -6
- data/lib/active_record/aggregations.rb +2 -1
- data/lib/active_record/association_relation.rb +0 -4
- data/lib/active_record/associations.rb +87 -43
- data/lib/active_record/associations/alias_tracker.rb +1 -3
- data/lib/active_record/associations/association.rb +8 -16
- data/lib/active_record/associations/association_scope.rb +5 -16
- data/lib/active_record/associations/belongs_to_association.rb +34 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +78 -54
- data/lib/active_record/associations/builder/belongs_to.rb +91 -58
- data/lib/active_record/associations/builder/collection_association.rb +47 -45
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -25
- data/lib/active_record/associations/builder/has_many.rb +2 -2
- data/lib/active_record/associations/builder/has_one.rb +5 -7
- data/lib/active_record/associations/builder/singular_association.rb +6 -7
- data/lib/active_record/associations/collection_association.rb +68 -105
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/has_many_association.rb +11 -9
- data/lib/active_record/associations/has_many_through_association.rb +16 -12
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +204 -165
- data/lib/active_record/associations/join_dependency/join_association.rb +43 -101
- data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
- data/lib/active_record/associations/join_helper.rb +2 -11
- data/lib/active_record/associations/preloader.rb +89 -34
- data/lib/active_record/associations/preloader/association.rb +43 -25
- data/lib/active_record/associations/preloader/collection_association.rb +2 -2
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +58 -26
- data/lib/active_record/associations/singular_association.rb +6 -5
- data/lib/active_record/associations/through_association.rb +2 -2
- data/lib/active_record/attribute_assignment.rb +5 -2
- data/lib/active_record/attribute_methods.rb +45 -40
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
- data/lib/active_record/attribute_methods/dirty.rb +8 -22
- data/lib/active_record/attribute_methods/primary_key.rb +1 -7
- data/lib/active_record/attribute_methods/read.rb +55 -28
- data/lib/active_record/attribute_methods/serialization.rb +12 -33
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -13
- data/lib/active_record/attribute_methods/write.rb +37 -12
- data/lib/active_record/autosave_association.rb +207 -207
- data/lib/active_record/base.rb +5 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +2 -7
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +11 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +12 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -5
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +84 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +52 -83
- data/lib/active_record/connection_adapters/abstract/transaction.rb +0 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +14 -97
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +58 -60
- data/lib/active_record/connection_adapters/column.rb +1 -35
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +3 -4
- data/lib/active_record/connection_adapters/mysql_adapter.rb +16 -15
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +24 -18
- data/lib/active_record/connection_adapters/postgresql/cast.rb +20 -16
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +23 -43
- data/lib/active_record/connection_adapters/postgresql/oid.rb +19 -12
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +28 -23
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +8 -30
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +92 -75
- data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +31 -64
- data/lib/active_record/connection_handling.rb +2 -2
- data/lib/active_record/core.rb +22 -43
- data/lib/active_record/counter_cache.rb +7 -7
- data/lib/active_record/enum.rb +100 -0
- data/lib/active_record/errors.rb +10 -5
- data/lib/active_record/fixture_set/file.rb +2 -1
- data/lib/active_record/fixtures.rb +171 -74
- data/lib/active_record/inheritance.rb +16 -22
- data/lib/active_record/integration.rb +52 -1
- data/lib/active_record/locking/optimistic.rb +7 -2
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +5 -12
- data/lib/active_record/migration.rb +62 -46
- data/lib/active_record/migration/command_recorder.rb +7 -13
- data/lib/active_record/model_schema.rb +7 -14
- data/lib/active_record/nested_attributes.rb +10 -8
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +3 -3
- data/lib/active_record/persistence.rb +16 -34
- data/lib/active_record/querying.rb +14 -12
- data/lib/active_record/railtie.rb +0 -50
- data/lib/active_record/railties/databases.rake +12 -15
- data/lib/active_record/readonly_attributes.rb +0 -6
- data/lib/active_record/reflection.rb +189 -75
- data/lib/active_record/relation.rb +69 -94
- data/lib/active_record/relation/batches.rb +57 -23
- data/lib/active_record/relation/calculations.rb +36 -43
- data/lib/active_record/relation/delegation.rb +54 -39
- data/lib/active_record/relation/finder_methods.rb +107 -62
- data/lib/active_record/relation/merger.rb +7 -20
- data/lib/active_record/relation/predicate_builder.rb +57 -38
- data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
- data/lib/active_record/relation/query_methods.rb +110 -98
- data/lib/active_record/relation/spawn_methods.rb +1 -2
- data/lib/active_record/result.rb +45 -6
- data/lib/active_record/runtime_registry.rb +5 -0
- data/lib/active_record/sanitization.rb +6 -8
- data/lib/active_record/schema_dumper.rb +16 -5
- data/lib/active_record/schema_migration.rb +24 -25
- data/lib/active_record/scoping/default.rb +5 -18
- data/lib/active_record/scoping/named.rb +8 -29
- data/lib/active_record/store.rb +56 -28
- data/lib/active_record/tasks/database_tasks.rb +8 -4
- data/lib/active_record/timestamp.rb +4 -4
- data/lib/active_record/transactions.rb +8 -10
- data/lib/active_record/validations/presence.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +1 -6
- data/lib/active_record/version.rb +1 -1
- data/lib/rails/generators/active_record.rb +2 -8
- data/lib/rails/generators/active_record/migration.rb +18 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
- metadata +32 -45
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
- data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
- data/lib/active_record/test_case.rb +0 -102
@@ -1,8 +1,35 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'set'
|
2
|
+
require 'active_support/concern'
|
3
|
+
require 'active_support/deprecation'
|
3
4
|
|
4
5
|
module ActiveRecord
|
5
6
|
module Delegation # :nodoc:
|
7
|
+
module DelegateCache
|
8
|
+
def relation_delegate_class(klass) # :nodoc:
|
9
|
+
@relation_delegate_cache[klass]
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize_relation_delegate_cache # :nodoc:
|
13
|
+
@relation_delegate_cache = cache = {}
|
14
|
+
[
|
15
|
+
ActiveRecord::Relation,
|
16
|
+
ActiveRecord::Associations::CollectionProxy,
|
17
|
+
ActiveRecord::AssociationRelation
|
18
|
+
].each do |klass|
|
19
|
+
delegate = Class.new(klass) {
|
20
|
+
include ClassSpecificRelation
|
21
|
+
}
|
22
|
+
const_set klass.name.gsub('::', '_'), delegate
|
23
|
+
cache[klass] = delegate
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def inherited(child_class)
|
28
|
+
child_class.initialize_relation_delegate_cache
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
6
33
|
extend ActiveSupport::Concern
|
7
34
|
|
8
35
|
# This module creates compiled delegation methods dynamically at runtime, which makes
|
@@ -10,7 +37,14 @@ module ActiveRecord
|
|
10
37
|
# may vary depending on the klass of a relation, so we create a subclass of Relation
|
11
38
|
# for each different klass, and the delegations are compiled into that subclass only.
|
12
39
|
|
13
|
-
|
40
|
+
BLACKLISTED_ARRAY_METHODS = [
|
41
|
+
:compact!, :flatten!, :reject!, :reverse!, :rotate!, :map!,
|
42
|
+
:shuffle!, :slice!, :sort!, :sort_by!, :delete_if,
|
43
|
+
:keep_if, :pop, :shift, :delete_at, :compact
|
44
|
+
].to_set # :nodoc:
|
45
|
+
|
46
|
+
delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, to: :to_a
|
47
|
+
|
14
48
|
delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
|
15
49
|
:connection, :columns_hash, :to => :klass
|
16
50
|
|
@@ -38,7 +72,7 @@ module ActiveRecord
|
|
38
72
|
RUBY
|
39
73
|
else
|
40
74
|
define_method method do |*args, &block|
|
41
|
-
scoping { @klass.
|
75
|
+
scoping { @klass.public_send(method, *args, &block) }
|
42
76
|
end
|
43
77
|
end
|
44
78
|
end
|
@@ -57,13 +91,10 @@ module ActiveRecord
|
|
57
91
|
def method_missing(method, *args, &block)
|
58
92
|
if @klass.respond_to?(method)
|
59
93
|
self.class.delegate_to_scoped_klass(method)
|
60
|
-
scoping { @klass.
|
61
|
-
elsif Array.method_defined?(method)
|
62
|
-
self.class.delegate method, :to => :to_a
|
63
|
-
to_a.send(method, *args, &block)
|
94
|
+
scoping { @klass.public_send(method, *args, &block) }
|
64
95
|
elsif arel.respond_to?(method)
|
65
96
|
self.class.delegate method, :to => :arel
|
66
|
-
arel.
|
97
|
+
arel.public_send(method, *args, &block)
|
67
98
|
else
|
68
99
|
super
|
69
100
|
end
|
@@ -71,52 +102,36 @@ module ActiveRecord
|
|
71
102
|
end
|
72
103
|
|
73
104
|
module ClassMethods # :nodoc:
|
74
|
-
|
75
|
-
|
76
|
-
def new(klass, *args)
|
77
|
-
relation = relation_class_for(klass).allocate
|
78
|
-
relation.__send__(:initialize, klass, *args)
|
79
|
-
relation
|
80
|
-
end
|
81
|
-
|
82
|
-
# This doesn't have to be thread-safe. relation_class_for guarantees that this will only be
|
83
|
-
# called exactly once for a given const name.
|
84
|
-
def const_missing(name)
|
85
|
-
const_set(name, Class.new(self) { include ClassSpecificRelation })
|
105
|
+
def create(klass, *args)
|
106
|
+
relation_class_for(klass).new(klass, *args)
|
86
107
|
end
|
87
108
|
|
88
109
|
private
|
89
|
-
|
90
|
-
# make instantiation significantly slower.
|
110
|
+
|
91
111
|
def relation_class_for(klass)
|
92
|
-
|
93
|
-
my_cache = @@subclasses.compute_if_absent(self) { ThreadSafe::Cache.new }
|
94
|
-
# This hash is keyed by klass.name to avoid memory leaks in development mode
|
95
|
-
my_cache.compute_if_absent(klass_name) do
|
96
|
-
# Cache#compute_if_absent guarantees that the block will only executed once for the given klass_name
|
97
|
-
const_get("#{name.gsub('::', '_')}_#{klass_name.gsub('::', '_')}", false)
|
98
|
-
end
|
99
|
-
else
|
100
|
-
ActiveRecord::Relation
|
101
|
-
end
|
112
|
+
klass.relation_delegate_class(self)
|
102
113
|
end
|
103
114
|
end
|
104
115
|
|
105
116
|
def respond_to?(method, include_private = false)
|
106
|
-
super ||
|
107
|
-
|
117
|
+
super || @klass.respond_to?(method, include_private) ||
|
118
|
+
array_delegable?(method) ||
|
108
119
|
arel.respond_to?(method, include_private)
|
109
120
|
end
|
110
121
|
|
111
122
|
protected
|
112
123
|
|
124
|
+
def array_delegable?(method)
|
125
|
+
Array.method_defined?(method) && BLACKLISTED_ARRAY_METHODS.exclude?(method)
|
126
|
+
end
|
127
|
+
|
113
128
|
def method_missing(method, *args, &block)
|
114
129
|
if @klass.respond_to?(method)
|
115
|
-
scoping { @klass.
|
116
|
-
elsif
|
117
|
-
to_a.
|
130
|
+
scoping { @klass.public_send(method, *args, &block) }
|
131
|
+
elsif array_delegable?(method)
|
132
|
+
to_a.public_send(method, *args, &block)
|
118
133
|
elsif arel.respond_to?(method)
|
119
|
-
arel.
|
134
|
+
arel.public_send(method, *args, &block)
|
120
135
|
else
|
121
136
|
super
|
122
137
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module FinderMethods
|
3
|
+
ONE_AS_ONE = '1 AS one'
|
4
|
+
|
3
5
|
# Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
|
4
6
|
# If no record can be found for all of the listed ids, then RecordNotFound will be raised. If the primary key
|
5
7
|
# is an integer, find by id coerces its arguments using +to_i+.
|
@@ -12,9 +14,11 @@ module ActiveRecord
|
|
12
14
|
# Person.find([1]) # returns an array for the object with ID = 1
|
13
15
|
# Person.where("administrator = 1").order("created_on DESC").find(1)
|
14
16
|
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
17
|
+
# <tt>ActiveRecord::RecordNotFound</tt> will be raised if one or more ids are not found.
|
18
|
+
#
|
19
|
+
# NOTE: The returned records may not be in the same order as the ids you
|
20
|
+
# provide since database rows are unordered. You'd need to provide an explicit <tt>order</tt>
|
21
|
+
# option if you want the results are sorted.
|
18
22
|
#
|
19
23
|
# ==== Find with lock
|
20
24
|
#
|
@@ -29,9 +33,37 @@ module ActiveRecord
|
|
29
33
|
# person.visits += 1
|
30
34
|
# person.save!
|
31
35
|
# end
|
36
|
+
#
|
37
|
+
# ==== Variations of +find+
|
38
|
+
#
|
39
|
+
# Person.where(name: 'Spartacus', rating: 4)
|
40
|
+
# # returns a chainable list (which can be empty).
|
41
|
+
#
|
42
|
+
# Person.find_by(name: 'Spartacus', rating: 4)
|
43
|
+
# # returns the first item or nil.
|
44
|
+
#
|
45
|
+
# Person.where(name: 'Spartacus', rating: 4).first_or_initialize
|
46
|
+
# # returns the first item or returns a new instance (requires you call .save to persist against the database).
|
47
|
+
#
|
48
|
+
# Person.where(name: 'Spartacus', rating: 4).first_or_create
|
49
|
+
# # returns the first item or creates it and returns it, available since Rails 3.2.1.
|
50
|
+
#
|
51
|
+
# ==== Alternatives for +find+
|
52
|
+
#
|
53
|
+
# Person.where(name: 'Spartacus', rating: 4).exists?(conditions = :none)
|
54
|
+
# # returns a boolean indicating if any record with the given conditions exist.
|
55
|
+
#
|
56
|
+
# Person.where(name: 'Spartacus', rating: 4).select("field1, field2, field3")
|
57
|
+
# # returns a chainable list of instances with only the mentioned fields.
|
58
|
+
#
|
59
|
+
# Person.where(name: 'Spartacus', rating: 4).ids
|
60
|
+
# # returns an Array of ids, available since Rails 3.2.1.
|
61
|
+
#
|
62
|
+
# Person.where(name: 'Spartacus', rating: 4).pluck(:field1, :field2)
|
63
|
+
# # returns an Array of the required fields, available since Rails 3.1.
|
32
64
|
def find(*args)
|
33
65
|
if block_given?
|
34
|
-
to_a.find
|
66
|
+
to_a.find { |*block_args| yield(*block_args) }
|
35
67
|
else
|
36
68
|
find_with_ids(*args)
|
37
69
|
end
|
@@ -80,13 +112,22 @@ module ActiveRecord
|
|
80
112
|
# Person.where(["user_name = :u", { u: user_name }]).first
|
81
113
|
# Person.order("created_on DESC").offset(5).first
|
82
114
|
# Person.first(3) # returns the first three objects fetched by SELECT * FROM people LIMIT 3
|
115
|
+
#
|
116
|
+
# ==== Rails 3
|
117
|
+
#
|
118
|
+
# Person.first # SELECT "people".* FROM "people" LIMIT 1
|
119
|
+
#
|
120
|
+
# NOTE: Rails 3 may not order this query by the primary key and the order
|
121
|
+
# will depend on the database implementation. In order to ensure that behavior,
|
122
|
+
# use <tt>User.order(:id).first</tt> instead.
|
123
|
+
#
|
124
|
+
# ==== Rails 4
|
125
|
+
#
|
126
|
+
# Person.first # SELECT "people".* FROM "people" ORDER BY "people"."id" ASC LIMIT 1
|
127
|
+
#
|
83
128
|
def first(limit = nil)
|
84
129
|
if limit
|
85
|
-
|
86
|
-
order(arel_table[primary_key].asc).limit(limit).to_a
|
87
|
-
else
|
88
|
-
limit(limit).to_a
|
89
|
-
end
|
130
|
+
find_first_with_limit(limit)
|
90
131
|
else
|
91
132
|
find_first
|
92
133
|
end
|
@@ -161,9 +202,10 @@ module ActiveRecord
|
|
161
202
|
conditions = conditions.id if Base === conditions
|
162
203
|
return false if !conditions
|
163
204
|
|
164
|
-
|
165
|
-
|
166
|
-
|
205
|
+
relation = apply_join_dependency(self, construct_join_dependency)
|
206
|
+
return false if ActiveRecord::NullRelation === relation
|
207
|
+
|
208
|
+
relation = relation.except(:select, :order).select(ONE_AS_ONE).limit(1)
|
167
209
|
|
168
210
|
case conditions
|
169
211
|
when Array, Hash
|
@@ -173,8 +215,6 @@ module ActiveRecord
|
|
173
215
|
end
|
174
216
|
|
175
217
|
connection.select_value(relation, "#{name} Exists", relation.bind_values) ? true : false
|
176
|
-
rescue ThrowResult
|
177
|
-
false
|
178
218
|
end
|
179
219
|
|
180
220
|
# This method is called whenever no records are found with either a single
|
@@ -199,64 +239,70 @@ module ActiveRecord
|
|
199
239
|
raise RecordNotFound, error
|
200
240
|
end
|
201
241
|
|
202
|
-
|
242
|
+
private
|
203
243
|
|
204
244
|
def find_with_associations
|
205
|
-
join_dependency =
|
206
|
-
relation = construct_relation_for_association_find(join_dependency)
|
207
|
-
rows = connection.select_all(relation, 'SQL', relation.bind_values.dup)
|
208
|
-
join_dependency.instantiate(rows)
|
209
|
-
rescue ThrowResult
|
210
|
-
[]
|
211
|
-
end
|
245
|
+
join_dependency = construct_join_dependency
|
212
246
|
|
213
|
-
|
214
|
-
|
215
|
-
|
247
|
+
aliases = join_dependency.aliases
|
248
|
+
relation = select aliases.columns
|
249
|
+
relation = apply_join_dependency(relation, join_dependency)
|
250
|
+
|
251
|
+
if block_given?
|
252
|
+
yield relation
|
253
|
+
else
|
254
|
+
if ActiveRecord::NullRelation === relation
|
255
|
+
[]
|
256
|
+
else
|
257
|
+
rows = connection.select_all(relation.arel, 'SQL', relation.bind_values.dup)
|
258
|
+
join_dependency.instantiate(rows, aliases)
|
259
|
+
end
|
260
|
+
end
|
216
261
|
end
|
217
262
|
|
218
|
-
def
|
219
|
-
including =
|
220
|
-
|
221
|
-
relation = except(:includes, :eager_load, :preload)
|
222
|
-
apply_join_dependency(relation, join_dependency)
|
263
|
+
def construct_join_dependency(joins = [])
|
264
|
+
including = eager_load_values + includes_values
|
265
|
+
ActiveRecord::Associations::JoinDependency.new(@klass, including, joins)
|
223
266
|
end
|
224
267
|
|
225
|
-
def
|
226
|
-
|
227
|
-
apply_join_dependency(relation, join_dependency)
|
268
|
+
def construct_relation_for_association_calculations
|
269
|
+
apply_join_dependency(self, construct_join_dependency(arel.froms.first))
|
228
270
|
end
|
229
271
|
|
230
272
|
def apply_join_dependency(relation, join_dependency)
|
231
|
-
|
232
|
-
|
233
|
-
end
|
234
|
-
|
235
|
-
limitable_reflections = using_limitable_reflections?(join_dependency.reflections)
|
273
|
+
relation = relation.except(:includes, :eager_load, :preload)
|
274
|
+
relation = relation.joins join_dependency
|
236
275
|
|
237
|
-
if
|
238
|
-
|
239
|
-
|
276
|
+
if using_limitable_reflections?(join_dependency.reflections)
|
277
|
+
relation
|
278
|
+
else
|
279
|
+
if relation.limit_value
|
280
|
+
limited_ids = limited_ids_for(relation)
|
281
|
+
limited_ids.empty? ? relation.none! : relation.where!(table[primary_key].in(limited_ids))
|
282
|
+
end
|
283
|
+
relation.except(:limit, :offset)
|
240
284
|
end
|
241
|
-
|
242
|
-
relation = relation.except(:limit, :offset) unless limitable_reflections
|
243
|
-
|
244
|
-
relation
|
245
285
|
end
|
246
286
|
|
247
|
-
def
|
248
|
-
|
249
|
-
|
287
|
+
def limited_ids_for(relation)
|
288
|
+
values = @klass.connection.columns_for_distinct(
|
289
|
+
"#{quoted_table_name}.#{quoted_primary_key}", relation.order_values)
|
250
290
|
|
251
|
-
relation = relation.
|
291
|
+
relation = relation.except(:select).select(values).distinct!
|
252
292
|
|
253
293
|
id_rows = @klass.connection.select_all(relation.arel, 'SQL', relation.bind_values)
|
254
|
-
|
294
|
+
id_rows.map {|row| row[primary_key]}
|
295
|
+
end
|
255
296
|
|
256
|
-
|
297
|
+
def using_limitable_reflections?(reflections)
|
298
|
+
reflections.none? { |r| r.collection? }
|
257
299
|
end
|
258
300
|
|
301
|
+
protected
|
302
|
+
|
259
303
|
def find_with_ids(*ids)
|
304
|
+
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
305
|
+
|
260
306
|
expects_array = ids.first.kind_of?(Array)
|
261
307
|
return ids.first if expects_array && ids.first.empty?
|
262
308
|
|
@@ -321,12 +367,15 @@ module ActiveRecord
|
|
321
367
|
if loaded?
|
322
368
|
@records.first
|
323
369
|
else
|
324
|
-
@first ||=
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
370
|
+
@first ||= find_first_with_limit(1).first
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
def find_first_with_limit(limit)
|
375
|
+
if order_values.empty? && primary_key
|
376
|
+
order(arel_table[primary_key].asc).limit(limit).to_a
|
377
|
+
else
|
378
|
+
limit(limit).to_a
|
330
379
|
end
|
331
380
|
end
|
332
381
|
|
@@ -335,16 +384,12 @@ module ActiveRecord
|
|
335
384
|
@records.last
|
336
385
|
else
|
337
386
|
@last ||=
|
338
|
-
if
|
387
|
+
if limit_value
|
339
388
|
to_a.last
|
340
389
|
else
|
341
390
|
reverse_order.limit(1).to_a.first
|
342
391
|
end
|
343
392
|
end
|
344
393
|
end
|
345
|
-
|
346
|
-
def using_limitable_reflections?(reflections)
|
347
|
-
reflections.none? { |r| r.collection? }
|
348
|
-
end
|
349
394
|
end
|
350
395
|
end
|
@@ -22,7 +22,7 @@ module ActiveRecord
|
|
22
22
|
# build a relation to merge in rather than directly merging
|
23
23
|
# the values.
|
24
24
|
def other
|
25
|
-
other = Relation.
|
25
|
+
other = Relation.create(relation.klass, relation.table)
|
26
26
|
hash.each { |k, v|
|
27
27
|
if k == :joins
|
28
28
|
if Hash === v
|
@@ -30,8 +30,6 @@ module ActiveRecord
|
|
30
30
|
else
|
31
31
|
other.joins!(*v)
|
32
32
|
end
|
33
|
-
elsif k == :select
|
34
|
-
other._select!(v)
|
35
33
|
else
|
36
34
|
other.send("#{k}!", v)
|
37
35
|
end
|
@@ -44,10 +42,6 @@ module ActiveRecord
|
|
44
42
|
attr_reader :relation, :values, :other
|
45
43
|
|
46
44
|
def initialize(relation, other)
|
47
|
-
if other.default_scoped? && other.klass != relation.klass
|
48
|
-
other = other.with_default_scope
|
49
|
-
end
|
50
|
-
|
51
45
|
@relation = relation
|
52
46
|
@values = other.values
|
53
47
|
@other = other
|
@@ -68,13 +62,7 @@ module ActiveRecord
|
|
68
62
|
# expensive), most of the time the value is going to be `nil` or `.blank?`, the only catch is that
|
69
63
|
# `false.blank?` returns `true`, so there needs to be an extra check so that explicit `false` values
|
70
64
|
# don't fall through the cracks.
|
71
|
-
unless value.nil? || (value.blank? && false != value)
|
72
|
-
if name == :select
|
73
|
-
relation._select!(*value)
|
74
|
-
else
|
75
|
-
relation.send("#{name}!", *value)
|
76
|
-
end
|
77
|
-
end
|
65
|
+
relation.send("#{name}!", *value) unless value.nil? || (value.blank? && false != value)
|
78
66
|
end
|
79
67
|
|
80
68
|
merge_multi_values
|
@@ -106,9 +94,7 @@ module ActiveRecord
|
|
106
94
|
[])
|
107
95
|
relation.joins! rest
|
108
96
|
|
109
|
-
|
110
|
-
@relation = association.join_relation(relation)
|
111
|
-
end
|
97
|
+
@relation = relation.joins join_dependency
|
112
98
|
end
|
113
99
|
end
|
114
100
|
|
@@ -143,7 +129,7 @@ module ActiveRecord
|
|
143
129
|
# override any order specified in the original relation
|
144
130
|
relation.reorder! values[:order]
|
145
131
|
elsif values[:order]
|
146
|
-
# merge in order_values from
|
132
|
+
# merge in order_values from relation
|
147
133
|
relation.order! values[:order]
|
148
134
|
end
|
149
135
|
|
@@ -161,7 +147,9 @@ module ActiveRecord
|
|
161
147
|
end
|
162
148
|
|
163
149
|
def filter_binds(lhs_binds, removed_wheres)
|
164
|
-
|
150
|
+
return lhs_binds if removed_wheres.empty?
|
151
|
+
|
152
|
+
set = Set.new removed_wheres.map { |x| x.left.name }
|
165
153
|
lhs_binds.dup.delete_if { |col,_| set.include? col.name }
|
166
154
|
end
|
167
155
|
|
@@ -182,7 +170,6 @@ module ActiveRecord
|
|
182
170
|
w.respond_to?(:operator) && w.operator == :== && seen.include?(w.left)
|
183
171
|
end
|
184
172
|
end
|
185
|
-
|
186
173
|
end
|
187
174
|
end
|
188
175
|
end
|