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
@@ -2,28 +2,33 @@ module ActiveRecord
|
|
2
2
|
class PredicateBuilder
|
3
3
|
class ArrayHandler # :nodoc:
|
4
4
|
def call(attribute, value)
|
5
|
+
return attribute.in([]) if value.empty?
|
6
|
+
|
5
7
|
values = value.map { |x| x.is_a?(Base) ? x.id : x }
|
6
8
|
ranges, values = values.partition { |v| v.is_a?(Range) }
|
9
|
+
nils, values = values.partition(&:nil?)
|
7
10
|
|
8
|
-
values_predicate =
|
9
|
-
values = values.compact
|
10
|
-
|
11
|
+
values_predicate =
|
11
12
|
case values.length
|
12
|
-
when 0
|
13
|
-
|
14
|
-
|
15
|
-
attribute.eq(values.first).or(attribute.eq(nil))
|
16
|
-
else
|
17
|
-
attribute.in(values).or(attribute.eq(nil))
|
13
|
+
when 0 then NullPredicate
|
14
|
+
when 1 then attribute.eq(values.first)
|
15
|
+
else attribute.in(values)
|
18
16
|
end
|
19
|
-
|
20
|
-
|
17
|
+
|
18
|
+
unless nils.empty?
|
19
|
+
values_predicate = values_predicate.or(attribute.eq(nil))
|
21
20
|
end
|
22
21
|
|
23
22
|
array_predicates = ranges.map { |range| attribute.in(range) }
|
24
23
|
array_predicates << values_predicate
|
25
24
|
array_predicates.inject { |composite, predicate| composite.or(predicate) }
|
26
25
|
end
|
26
|
+
|
27
|
+
module NullPredicate
|
28
|
+
def self.or(other)
|
29
|
+
other
|
30
|
+
end
|
31
|
+
end
|
27
32
|
end
|
28
33
|
end
|
29
34
|
end
|
@@ -67,6 +67,7 @@ module ActiveRecord
|
|
67
67
|
#
|
68
68
|
def #{name}_values=(values) # def select_values=(values)
|
69
69
|
raise ImmutableRelation if @loaded # raise ImmutableRelation if @loaded
|
70
|
+
check_cached_relation
|
70
71
|
@values[:#{name}] = values # @values[:select] = values
|
71
72
|
end # end
|
72
73
|
CODE
|
@@ -84,11 +85,22 @@ module ActiveRecord
|
|
84
85
|
class_eval <<-CODE, __FILE__, __LINE__ + 1
|
85
86
|
def #{name}_value=(value) # def readonly_value=(value)
|
86
87
|
raise ImmutableRelation if @loaded # raise ImmutableRelation if @loaded
|
88
|
+
check_cached_relation
|
87
89
|
@values[:#{name}] = value # @values[:readonly] = value
|
88
90
|
end # end
|
89
91
|
CODE
|
90
92
|
end
|
91
93
|
|
94
|
+
def check_cached_relation # :nodoc:
|
95
|
+
if defined?(@arel) && @arel
|
96
|
+
@arel = nil
|
97
|
+
ActiveSupport::Deprecation.warn <<-WARNING
|
98
|
+
Modifying already cached Relation. The cache will be reset.
|
99
|
+
Use a cloned Relation to prevent this warning.
|
100
|
+
WARNING
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
92
104
|
def create_with_value # :nodoc:
|
93
105
|
@values[:create_with] || {}
|
94
106
|
end
|
@@ -173,7 +185,7 @@ module ActiveRecord
|
|
173
185
|
|
174
186
|
# Use to indicate that the given +table_names+ are referenced by an SQL string,
|
175
187
|
# and should therefore be JOINed in any query rather than loaded separately.
|
176
|
-
# This method only works in
|
188
|
+
# This method only works in conjunction with +includes+.
|
177
189
|
# See #includes for more details.
|
178
190
|
#
|
179
191
|
# User.includes(:posts).where("posts.name = 'foo'")
|
@@ -207,7 +219,7 @@ module ActiveRecord
|
|
207
219
|
# fields are retrieved:
|
208
220
|
#
|
209
221
|
# Model.select(:field)
|
210
|
-
# # => [#<Model field:value>]
|
222
|
+
# # => [#<Model id: nil, field: "value">]
|
211
223
|
#
|
212
224
|
# Although in the above example it looks as though this method returns an
|
213
225
|
# array, it actually returns a relation object and can have other query
|
@@ -216,12 +228,12 @@ module ActiveRecord
|
|
216
228
|
# The argument to the method can also be an array of fields.
|
217
229
|
#
|
218
230
|
# Model.select(:field, :other_field, :and_one_more)
|
219
|
-
# # => [#<Model field: "value", other_field: "value", and_one_more: "value">]
|
231
|
+
# # => [#<Model id: nil, field: "value", other_field: "value", and_one_more: "value">]
|
220
232
|
#
|
221
233
|
# You can also use one or more strings, which will be used unchanged as SELECT fields.
|
222
234
|
#
|
223
235
|
# Model.select('field AS field_one', 'other_field AS field_two')
|
224
|
-
# # => [#<Model field: "value", other_field: "value">]
|
236
|
+
# # => [#<Model id: nil, field: "value", other_field: "value">]
|
225
237
|
#
|
226
238
|
# If an alias was specified, it will be accessible from the resulting objects:
|
227
239
|
#
|
@@ -229,7 +241,7 @@ module ActiveRecord
|
|
229
241
|
# # => "value"
|
230
242
|
#
|
231
243
|
# Accessing attributes of an object that do not have fields retrieved by a select
|
232
|
-
# will throw <tt>ActiveModel::MissingAttributeError</tt>:
|
244
|
+
# except +id+ will throw <tt>ActiveModel::MissingAttributeError</tt>:
|
233
245
|
#
|
234
246
|
# Model.select(:field).first.other_field
|
235
247
|
# # => ActiveModel::MissingAttributeError: missing attribute: other_field
|
@@ -266,6 +278,10 @@ module ActiveRecord
|
|
266
278
|
#
|
267
279
|
# User.group('name AS grouped_name, age')
|
268
280
|
# => [#<User id: 3, name: "Foo", age: 21, ...>, #<User id: 2, name: "Oscar", age: 21, ...>, #<User id: 5, name: "Foo", age: 23, ...>]
|
281
|
+
#
|
282
|
+
# Passing in an array of attributes to group by is also supported.
|
283
|
+
# User.select([:id, :first_name]).group(:id, :first_name).first(3)
|
284
|
+
# => [#<User id: 1, first_name: "Bill">, #<User id: 2, first_name: "Earl">, #<User id: 3, first_name: "Beto">]
|
269
285
|
def group(*args)
|
270
286
|
check_if_method_has_arguments!(:group, args)
|
271
287
|
spawn.group!(*args)
|
@@ -280,15 +296,6 @@ module ActiveRecord
|
|
280
296
|
|
281
297
|
# Allows to specify an order attribute:
|
282
298
|
#
|
283
|
-
# User.order('name')
|
284
|
-
# => SELECT "users".* FROM "users" ORDER BY name
|
285
|
-
#
|
286
|
-
# User.order('name DESC')
|
287
|
-
# => SELECT "users".* FROM "users" ORDER BY name DESC
|
288
|
-
#
|
289
|
-
# User.order('name DESC, email')
|
290
|
-
# => SELECT "users".* FROM "users" ORDER BY name DESC, email
|
291
|
-
#
|
292
299
|
# User.order(:name)
|
293
300
|
# => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC
|
294
301
|
#
|
@@ -297,6 +304,15 @@ module ActiveRecord
|
|
297
304
|
#
|
298
305
|
# User.order(:name, email: :desc)
|
299
306
|
# => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC
|
307
|
+
#
|
308
|
+
# User.order('name')
|
309
|
+
# => SELECT "users".* FROM "users" ORDER BY name
|
310
|
+
#
|
311
|
+
# User.order('name DESC')
|
312
|
+
# => SELECT "users".* FROM "users" ORDER BY name DESC
|
313
|
+
#
|
314
|
+
# User.order('name DESC, email')
|
315
|
+
# => SELECT "users".* FROM "users" ORDER BY name DESC, email
|
300
316
|
def order(*args)
|
301
317
|
check_if_method_has_arguments!(:order, args)
|
302
318
|
spawn.order!(*args)
|
@@ -560,18 +576,14 @@ module ActiveRecord
|
|
560
576
|
end
|
561
577
|
end
|
562
578
|
|
563
|
-
def where!(opts
|
564
|
-
if
|
565
|
-
|
566
|
-
|
567
|
-
if Hash === opts
|
568
|
-
opts = sanitize_forbidden_attributes(opts)
|
569
|
-
references!(PredicateBuilder.references(opts))
|
570
|
-
end
|
571
|
-
|
572
|
-
self.where_values += build_where(opts, rest)
|
573
|
-
self
|
579
|
+
def where!(opts, *rest) # :nodoc:
|
580
|
+
if Hash === opts
|
581
|
+
opts = sanitize_forbidden_attributes(opts)
|
582
|
+
references!(PredicateBuilder.references(opts))
|
574
583
|
end
|
584
|
+
|
585
|
+
self.where_values += build_where(opts, rest)
|
586
|
+
self
|
575
587
|
end
|
576
588
|
|
577
589
|
# Allows you to change a previously set where condition for a given attribute, instead of appending to that condition.
|
@@ -677,11 +689,11 @@ module ActiveRecord
|
|
677
689
|
# end
|
678
690
|
#
|
679
691
|
def none
|
680
|
-
|
692
|
+
extending(NullRelation)
|
681
693
|
end
|
682
694
|
|
683
695
|
def none! # :nodoc:
|
684
|
-
|
696
|
+
extending!(NullRelation)
|
685
697
|
end
|
686
698
|
|
687
699
|
# Sets readonly attributes for the returned relation. If value is
|
@@ -833,7 +845,9 @@ module ActiveRecord
|
|
833
845
|
end
|
834
846
|
|
835
847
|
def reverse_order! # :nodoc:
|
836
|
-
|
848
|
+
orders = order_values.uniq
|
849
|
+
orders.reject!(&:blank?)
|
850
|
+
self.order_values = reverse_sql_order(orders)
|
837
851
|
self
|
838
852
|
end
|
839
853
|
|
@@ -849,25 +863,26 @@ module ActiveRecord
|
|
849
863
|
|
850
864
|
build_joins(arel, joins_values.flatten) unless joins_values.empty?
|
851
865
|
|
852
|
-
collapse_wheres(arel, (where_values - [''])
|
866
|
+
collapse_wheres(arel, (where_values - [''])) #TODO: Add uniq with real value comparison / ignore uniqs that have binds
|
853
867
|
|
854
868
|
arel.having(*having_values.uniq.reject(&:blank?)) unless having_values.empty?
|
855
869
|
|
856
870
|
arel.take(connection.sanitize_limit(limit_value)) if limit_value
|
857
871
|
arel.skip(offset_value.to_i) if offset_value
|
858
|
-
|
872
|
+
|
873
|
+
arel.group(*group_values.uniq.reject(&:blank?)) unless group_values.empty?
|
859
874
|
|
860
875
|
build_order(arel)
|
861
876
|
|
862
|
-
build_select(arel)
|
877
|
+
build_select(arel, select_values.uniq)
|
863
878
|
|
864
879
|
arel.distinct(distinct_value)
|
865
880
|
arel.from(build_from) if from_value
|
866
881
|
arel.lock(lock_value) if lock_value
|
867
882
|
|
868
883
|
# Reorder bind indexes if joins produced bind values
|
869
|
-
|
870
|
-
|
884
|
+
if arel.bind_values.any?
|
885
|
+
bvs = arel.bind_values + bind_values
|
871
886
|
arel.ast.grep(Arel::Nodes::BindParam).each_with_index do |bp, i|
|
872
887
|
column = bvs[i].first
|
873
888
|
bp.replace connection.substitute_at(column, i)
|
@@ -887,8 +902,9 @@ module ActiveRecord
|
|
887
902
|
|
888
903
|
case scope
|
889
904
|
when :order
|
890
|
-
self.reverse_order_value = false
|
891
905
|
result = []
|
906
|
+
when :where
|
907
|
+
self.bind_values = []
|
892
908
|
else
|
893
909
|
result = [] unless single_val_method
|
894
910
|
end
|
@@ -939,18 +955,15 @@ module ActiveRecord
|
|
939
955
|
def build_where(opts, other = [])
|
940
956
|
case opts
|
941
957
|
when String, Array
|
942
|
-
#TODO: Remove duplication with: /activerecord/lib/active_record/sanitization.rb:113
|
943
|
-
values = Hash === other.first ? other.first.values : other
|
944
|
-
|
945
|
-
values.grep(ActiveRecord::Relation) do |rel|
|
946
|
-
self.bind_values += rel.bind_values
|
947
|
-
end
|
948
|
-
|
949
958
|
[@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
|
950
959
|
when Hash
|
951
960
|
opts = PredicateBuilder.resolve_column_aliases(klass, opts)
|
952
|
-
attributes = @klass.send(:expand_hash_conditions_for_aggregates, opts)
|
953
961
|
|
962
|
+
bv_len = bind_values.length
|
963
|
+
tmp_opts, bind_values = create_binds(opts, bv_len)
|
964
|
+
self.bind_values += bind_values
|
965
|
+
|
966
|
+
attributes = @klass.send(:expand_hash_conditions_for_aggregates, tmp_opts)
|
954
967
|
add_relations_to_bind_values(attributes)
|
955
968
|
|
956
969
|
PredicateBuilder.build_from_hash(klass, attributes, table)
|
@@ -959,6 +972,29 @@ module ActiveRecord
|
|
959
972
|
end
|
960
973
|
end
|
961
974
|
|
975
|
+
def create_binds(opts, idx)
|
976
|
+
bindable, non_binds = opts.partition do |column, value|
|
977
|
+
case value
|
978
|
+
when String, Integer, ActiveRecord::StatementCache::Substitute
|
979
|
+
@klass.columns_hash.include? column.to_s
|
980
|
+
else
|
981
|
+
false
|
982
|
+
end
|
983
|
+
end
|
984
|
+
|
985
|
+
new_opts = {}
|
986
|
+
binds = []
|
987
|
+
|
988
|
+
bindable.each_with_index do |(column,value), index|
|
989
|
+
binds.push [@klass.columns_hash[column.to_s], value]
|
990
|
+
new_opts[column] = connection.substitute_at(column, index + idx)
|
991
|
+
end
|
992
|
+
|
993
|
+
non_binds.each { |column,value| new_opts[column] = value }
|
994
|
+
|
995
|
+
[new_opts, binds]
|
996
|
+
end
|
997
|
+
|
962
998
|
def build_from
|
963
999
|
opts, name = from_value
|
964
1000
|
case opts
|
@@ -1000,33 +1036,29 @@ module ActiveRecord
|
|
1000
1036
|
join_list
|
1001
1037
|
)
|
1002
1038
|
|
1003
|
-
|
1039
|
+
join_infos = join_dependency.join_constraints stashed_association_joins
|
1004
1040
|
|
1005
|
-
|
1041
|
+
join_infos.each do |info|
|
1042
|
+
info.joins.each { |join| manager.from(join) }
|
1043
|
+
manager.bind_values.concat info.binds
|
1044
|
+
end
|
1006
1045
|
|
1007
1046
|
manager.join_sources.concat(join_list)
|
1008
1047
|
|
1009
1048
|
manager
|
1010
1049
|
end
|
1011
1050
|
|
1012
|
-
def build_select(arel)
|
1013
|
-
if
|
1014
|
-
|
1051
|
+
def build_select(arel, selects)
|
1052
|
+
if !selects.empty?
|
1053
|
+
expanded_select = selects.map do |field|
|
1054
|
+
columns_hash.key?(field.to_s) ? arel_table[field] : field
|
1055
|
+
end
|
1056
|
+
arel.project(*expanded_select)
|
1015
1057
|
else
|
1016
1058
|
arel.project(@klass.arel_table[Arel.star])
|
1017
1059
|
end
|
1018
1060
|
end
|
1019
1061
|
|
1020
|
-
def arel_columns(columns)
|
1021
|
-
columns.map do |field|
|
1022
|
-
if columns_hash.key?(field.to_s)
|
1023
|
-
arel_table[field]
|
1024
|
-
else
|
1025
|
-
field
|
1026
|
-
end
|
1027
|
-
end
|
1028
|
-
end
|
1029
|
-
|
1030
1062
|
def reverse_sql_order(order_query)
|
1031
1063
|
order_query = ["#{quoted_table_name}.#{quoted_primary_key} ASC"] if order_query.empty?
|
1032
1064
|
|
@@ -1052,15 +1084,19 @@ module ActiveRecord
|
|
1052
1084
|
def build_order(arel)
|
1053
1085
|
orders = order_values.uniq
|
1054
1086
|
orders.reject!(&:blank?)
|
1055
|
-
orders = reverse_sql_order(orders) if reverse_order_value
|
1056
1087
|
|
1057
1088
|
arel.order(*orders) unless orders.empty?
|
1058
1089
|
end
|
1059
1090
|
|
1091
|
+
VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
|
1092
|
+
'asc', 'desc', 'ASC', 'DESC'] # :nodoc:
|
1093
|
+
|
1060
1094
|
def validate_order_args(args)
|
1061
|
-
args.
|
1062
|
-
unless (
|
1063
|
-
|
1095
|
+
args.each do |arg|
|
1096
|
+
next unless arg.is_a?(Hash)
|
1097
|
+
arg.each do |_key, value|
|
1098
|
+
raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \
|
1099
|
+
"directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value)
|
1064
1100
|
end
|
1065
1101
|
end
|
1066
1102
|
end
|
@@ -1082,7 +1118,7 @@ module ActiveRecord
|
|
1082
1118
|
when Hash
|
1083
1119
|
arg.map { |field, dir|
|
1084
1120
|
field = klass.attribute_alias(field) if klass.attribute_alias?(field)
|
1085
|
-
table[field].send(dir)
|
1121
|
+
table[field].send(dir.downcase)
|
1086
1122
|
}
|
1087
1123
|
else
|
1088
1124
|
arg
|
@@ -12,7 +12,6 @@ module ActiveRecord
|
|
12
12
|
|
13
13
|
# Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an <tt>ActiveRecord::Relation</tt>.
|
14
14
|
# Returns an array representing the intersection of the resulting records with <tt>other</tt>, if <tt>other</tt> is an array.
|
15
|
-
#
|
16
15
|
# Post.where(published: true).joins(:comments).merge( Comment.where(spam: false) )
|
17
16
|
# # Performs a single join query with both where conditions.
|
18
17
|
#
|
@@ -38,14 +37,11 @@ module ActiveRecord
|
|
38
37
|
end
|
39
38
|
|
40
39
|
def merge!(other) # :nodoc:
|
41
|
-
if other.is_a?(
|
42
|
-
Relation::HashMerger.new(self, other).merge
|
43
|
-
elsif other.is_a?(Relation)
|
44
|
-
Relation::Merger.new(self, other).merge
|
45
|
-
elsif other.respond_to?(:to_proc)
|
40
|
+
if !other.is_a?(Relation) && other.respond_to?(:to_proc)
|
46
41
|
instance_exec(&other)
|
47
42
|
else
|
48
|
-
|
43
|
+
klass = other.is_a?(Hash) ? Relation::HashMerger : Relation::Merger
|
44
|
+
klass.new(self, other).merge
|
49
45
|
end
|
50
46
|
end
|
51
47
|
|
@@ -62,6 +58,9 @@ module ActiveRecord
|
|
62
58
|
# Post.order('id asc').only(:where) # discards the order condition
|
63
59
|
# Post.order('id asc').only(:where, :order) # uses the specified order
|
64
60
|
def only(*onlies)
|
61
|
+
if onlies.any? { |o| o == :where }
|
62
|
+
onlies << :bind
|
63
|
+
end
|
65
64
|
relation_with values.slice(*onlies)
|
66
65
|
end
|
67
66
|
|
data/lib/active_record/result.rb
CHANGED
@@ -31,7 +31,7 @@ module ActiveRecord
|
|
31
31
|
class Result
|
32
32
|
include Enumerable
|
33
33
|
|
34
|
-
IDENTITY_TYPE =
|
34
|
+
IDENTITY_TYPE = Type::Value.new # :nodoc:
|
35
35
|
|
36
36
|
attr_reader :columns, :rows, :column_types
|
37
37
|
|
@@ -42,14 +42,6 @@ module ActiveRecord
|
|
42
42
|
@column_types = column_types
|
43
43
|
end
|
44
44
|
|
45
|
-
def identity_type # :nodoc:
|
46
|
-
IDENTITY_TYPE
|
47
|
-
end
|
48
|
-
|
49
|
-
def column_type(name)
|
50
|
-
@column_types[name] || identity_type
|
51
|
-
end
|
52
|
-
|
53
45
|
def each
|
54
46
|
if block_given?
|
55
47
|
hash_rows.each { |row| yield row }
|
@@ -82,6 +74,15 @@ module ActiveRecord
|
|
82
74
|
hash_rows.last
|
83
75
|
end
|
84
76
|
|
77
|
+
def cast_values(type_overrides = {}) # :nodoc:
|
78
|
+
types = columns.map { |name| column_type(name, type_overrides) }
|
79
|
+
result = rows.map do |values|
|
80
|
+
types.zip(values).map { |type, value| type.type_cast_from_database(value) }
|
81
|
+
end
|
82
|
+
|
83
|
+
columns.one? ? result.map!(&:first) : result
|
84
|
+
end
|
85
|
+
|
85
86
|
def initialize_copy(other)
|
86
87
|
@columns = columns.dup
|
87
88
|
@rows = rows.dup
|
@@ -91,6 +92,12 @@ module ActiveRecord
|
|
91
92
|
|
92
93
|
private
|
93
94
|
|
95
|
+
def column_type(name, type_overrides = {})
|
96
|
+
type_overrides.fetch(name) do
|
97
|
+
column_types.fetch(name, IDENTITY_TYPE)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
94
101
|
def hash_rows
|
95
102
|
@hash_rows ||=
|
96
103
|
begin
|