activerecord 4.0.0.beta1 → 4.0.0.rc1
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 +573 -30
- data/README.rdoc +3 -3
- data/lib/active_record.rb +8 -2
- data/lib/active_record/associations.rb +16 -9
- data/lib/active_record/associations/association.rb +8 -6
- data/lib/active_record/associations/association_scope.rb +2 -1
- data/lib/active_record/associations/belongs_to_association.rb +2 -2
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/belongs_to.rb +37 -5
- data/lib/active_record/associations/collection_association.rb +38 -14
- data/lib/active_record/associations/collection_proxy.rb +18 -15
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +3 -3
- data/lib/active_record/associations/has_many_association.rb +4 -3
- data/lib/active_record/associations/has_many_through_association.rb +1 -1
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +29 -8
- data/lib/active_record/associations/join_dependency/join_association.rb +26 -6
- data/lib/active_record/associations/join_dependency/join_base.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_part.rb +6 -6
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/preloader/has_many_through.rb +6 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +5 -5
- data/lib/active_record/attribute_methods.rb +20 -5
- data/lib/active_record/attribute_methods/dirty.rb +5 -1
- data/lib/active_record/attribute_methods/primary_key.rb +1 -1
- data/lib/active_record/attribute_methods/serialization.rb +9 -2
- data/lib/active_record/autosave_association.rb +19 -5
- data/lib/active_record/base.rb +3 -3
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +8 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +3 -9
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +2 -8
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +60 -61
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +13 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +291 -153
- data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +92 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +55 -29
- data/lib/active_record/connection_adapters/column.rb +4 -4
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -3
- data/lib/active_record/connection_adapters/mysql_adapter.rb +5 -5
- data/lib/active_record/connection_adapters/postgresql/cast.rb +22 -2
- data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -6
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +50 -9
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +53 -24
- data/lib/active_record/connection_adapters/schema_cache.rb +35 -7
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +13 -5
- data/lib/active_record/connection_handling.rb +7 -7
- data/lib/active_record/core.rb +43 -8
- data/lib/active_record/counter_cache.rb +2 -1
- data/lib/active_record/errors.rb +11 -10
- data/lib/active_record/explain.rb +9 -7
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +3 -2
- data/lib/active_record/fixture_set/file.rb +1 -2
- data/lib/active_record/fixtures.rb +13 -7
- data/lib/active_record/inheritance.rb +12 -4
- data/lib/active_record/integration.rb +3 -3
- data/lib/active_record/locking/optimistic.rb +2 -2
- data/lib/active_record/log_subscriber.rb +2 -2
- data/lib/active_record/migration.rb +69 -21
- data/lib/active_record/model_schema.rb +1 -1
- data/lib/active_record/nested_attributes.rb +98 -46
- data/lib/active_record/persistence.rb +3 -3
- data/lib/active_record/querying.rb +1 -1
- data/lib/active_record/railtie.rb +18 -4
- data/lib/active_record/railties/console_sandbox.rb +3 -2
- data/lib/active_record/railties/controller_runtime.rb +2 -1
- data/lib/active_record/railties/databases.rake +38 -80
- data/lib/active_record/reflection.rb +36 -3
- data/lib/active_record/relation.rb +18 -8
- data/lib/active_record/relation/calculations.rb +10 -5
- data/lib/active_record/relation/delegation.rb +3 -5
- data/lib/active_record/relation/finder_methods.rb +27 -14
- data/lib/active_record/relation/merger.rb +30 -2
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_methods.rb +113 -16
- data/lib/active_record/runtime_registry.rb +17 -0
- data/lib/active_record/schema_dumper.rb +5 -1
- data/lib/active_record/schema_migration.rb +8 -5
- data/lib/active_record/scoping.rb +56 -2
- data/lib/active_record/scoping/default.rb +12 -11
- data/lib/active_record/scoping/named.rb +7 -3
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/statement_cache.rb +26 -0
- data/lib/active_record/tasks/database_tasks.rb +55 -10
- data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +7 -2
- data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
- data/lib/active_record/timestamp.rb +6 -0
- data/lib/active_record/transactions.rb +7 -3
- data/lib/active_record/validations.rb +1 -2
- data/lib/active_record/validations/uniqueness.rb +7 -3
- data/lib/active_record/version.rb +7 -6
- data/lib/rails/generators/active_record/migration/migration_generator.rb +9 -2
- data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +4 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +4 -1
- metadata +17 -12
- data/examples/associations.png +0 -0
@@ -11,7 +11,7 @@ module ActiveRecord
|
|
11
11
|
# Person.count(:all)
|
12
12
|
# # => performs a COUNT(*) (:all is an alias for '*')
|
13
13
|
#
|
14
|
-
# Person.count(:age
|
14
|
+
# Person.distinct.count(:age)
|
15
15
|
# # => counts the number of different age values
|
16
16
|
#
|
17
17
|
# If +count+ is used with +group+, it returns a Hash whose keys represent the aggregated column,
|
@@ -82,7 +82,7 @@ module ActiveRecord
|
|
82
82
|
# puts values["Drake"]
|
83
83
|
# # => 43
|
84
84
|
#
|
85
|
-
# drake = Family.
|
85
|
+
# drake = Family.find_by(last_name: 'Drake')
|
86
86
|
# values = Person.group(:family).maximum(:age) # Person belongs_to :family
|
87
87
|
# puts values[drake]
|
88
88
|
# # => 43
|
@@ -135,7 +135,7 @@ module ActiveRecord
|
|
135
135
|
# # SELECT people.id, people.name FROM people
|
136
136
|
# # => [[1, 'David'], [2, 'Jeremy'], [3, 'Jose']]
|
137
137
|
#
|
138
|
-
# Person.
|
138
|
+
# Person.pluck('DISTINCT role')
|
139
139
|
# # SELECT DISTINCT role FROM people
|
140
140
|
# # => ['admin', 'member', 'guest']
|
141
141
|
#
|
@@ -198,8 +198,13 @@ module ActiveRecord
|
|
198
198
|
def perform_calculation(operation, column_name, options = {})
|
199
199
|
operation = operation.to_s.downcase
|
200
200
|
|
201
|
-
# If #count is used
|
202
|
-
distinct =
|
201
|
+
# If #count is used with #distinct / #uniq it is considered distinct. (eg. relation.distinct.count)
|
202
|
+
distinct = self.distinct_value
|
203
|
+
if options.has_key?(:distinct)
|
204
|
+
ActiveSupport::Deprecation.warn "The :distinct option for `Relation#count` is deprecated. " \
|
205
|
+
"Please use `Relation#distinct` instead. (eg. `relation.distinct.count`)"
|
206
|
+
distinct = options[:distinct]
|
207
|
+
end
|
203
208
|
|
204
209
|
if operation == "count"
|
205
210
|
column_name ||= (select_for_count || :all)
|
@@ -37,11 +37,9 @@ module ActiveRecord
|
|
37
37
|
end
|
38
38
|
RUBY
|
39
39
|
else
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
44
|
-
RUBY
|
40
|
+
define_method method do |*args, &block|
|
41
|
+
scoping { @klass.send(method, *args, &block) }
|
42
|
+
end
|
45
43
|
end
|
46
44
|
end
|
47
45
|
end
|
@@ -37,7 +37,7 @@ module ActiveRecord
|
|
37
37
|
end
|
38
38
|
|
39
39
|
# Finds the first record matching the specified conditions. There
|
40
|
-
# is no implied
|
40
|
+
# is no implied ordering so if order matters, you should specify it
|
41
41
|
# yourself.
|
42
42
|
#
|
43
43
|
# If no record is found, returns <tt>nil</tt>.
|
@@ -130,8 +130,8 @@ module ActiveRecord
|
|
130
130
|
last or raise RecordNotFound
|
131
131
|
end
|
132
132
|
|
133
|
-
# Returns
|
134
|
-
# conditions given, or
|
133
|
+
# Returns truthy if a record exists in the table that matches the +id+ or
|
134
|
+
# conditions given, or falsy otherwise. The argument can take six forms:
|
135
135
|
#
|
136
136
|
# * Integer - Finds the record with this primary key.
|
137
137
|
# * String - Finds the record with a primary key corresponding to this
|
@@ -176,6 +176,28 @@ module ActiveRecord
|
|
176
176
|
false
|
177
177
|
end
|
178
178
|
|
179
|
+
# This method is called whenever no records are found with either a single
|
180
|
+
# id or multiple ids and raises a +ActiveRecord::RecordNotFound+ exception.
|
181
|
+
#
|
182
|
+
# The error message is different depending on whether a single id or
|
183
|
+
# multiple ids are provided. If multiple ids are provided, then the number
|
184
|
+
# of results obtained should be provided in the +result_size+ argument and
|
185
|
+
# the expected number of results should be provided in the +expected_size+
|
186
|
+
# argument.
|
187
|
+
def raise_record_not_found_exception!(ids, result_size, expected_size) #:nodoc:
|
188
|
+
conditions = arel.where_sql
|
189
|
+
conditions = " [#{conditions}]" if conditions
|
190
|
+
|
191
|
+
if Array(ids).size == 1
|
192
|
+
error = "Couldn't find #{@klass.name} with #{primary_key}=#{ids}#{conditions}"
|
193
|
+
else
|
194
|
+
error = "Couldn't find all #{@klass.name.pluralize} with IDs "
|
195
|
+
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})"
|
196
|
+
end
|
197
|
+
|
198
|
+
raise RecordNotFound, error
|
199
|
+
end
|
200
|
+
|
179
201
|
protected
|
180
202
|
|
181
203
|
def find_with_associations
|
@@ -259,11 +281,7 @@ module ActiveRecord
|
|
259
281
|
relation.bind_values += [[column, id]]
|
260
282
|
record = relation.take
|
261
283
|
|
262
|
-
unless record
|
263
|
-
conditions = arel.where_sql
|
264
|
-
conditions = " [#{conditions}]" if conditions
|
265
|
-
raise RecordNotFound, "Couldn't find #{@klass.name} with #{primary_key}=#{id}#{conditions}"
|
266
|
-
end
|
284
|
+
raise_record_not_found_exception!(id, 0, 1) unless record
|
267
285
|
|
268
286
|
record
|
269
287
|
end
|
@@ -286,12 +304,7 @@ module ActiveRecord
|
|
286
304
|
if result.size == expected_size
|
287
305
|
result
|
288
306
|
else
|
289
|
-
|
290
|
-
conditions = " [#{conditions}]" if conditions
|
291
|
-
|
292
|
-
error = "Couldn't find all #{@klass.name.pluralize} with IDs "
|
293
|
-
error << "(#{ids.join(", ")})#{conditions} (found #{result.size} results, but was looking for #{expected_size})"
|
294
|
-
raise RecordNotFound, error
|
307
|
+
raise_record_not_found_exception!(ids, result.size, expected_size)
|
295
308
|
end
|
296
309
|
end
|
297
310
|
|
@@ -39,7 +39,7 @@ module ActiveRecord
|
|
39
39
|
end
|
40
40
|
|
41
41
|
class Merger # :nodoc:
|
42
|
-
attr_reader :relation, :values
|
42
|
+
attr_reader :relation, :values, :other
|
43
43
|
|
44
44
|
def initialize(relation, other)
|
45
45
|
if other.default_scoped? && other.klass != relation.klass
|
@@ -48,11 +48,12 @@ module ActiveRecord
|
|
48
48
|
|
49
49
|
@relation = relation
|
50
50
|
@values = other.values
|
51
|
+
@other = other
|
51
52
|
end
|
52
53
|
|
53
54
|
NORMAL_VALUES = Relation::SINGLE_VALUE_METHODS +
|
54
55
|
Relation::MULTI_VALUE_METHODS -
|
55
|
-
[:where, :order, :bind, :reverse_order, :lock, :create_with, :reordering, :from] # :nodoc:
|
56
|
+
[:joins, :where, :order, :bind, :reverse_order, :lock, :create_with, :reordering, :from] # :nodoc:
|
56
57
|
|
57
58
|
def normal_values
|
58
59
|
NORMAL_VALUES
|
@@ -66,12 +67,39 @@ module ActiveRecord
|
|
66
67
|
|
67
68
|
merge_multi_values
|
68
69
|
merge_single_values
|
70
|
+
merge_joins
|
69
71
|
|
70
72
|
relation
|
71
73
|
end
|
72
74
|
|
73
75
|
private
|
74
76
|
|
77
|
+
def merge_joins
|
78
|
+
return if values[:joins].blank?
|
79
|
+
|
80
|
+
if other.klass == relation.klass
|
81
|
+
relation.joins!(*values[:joins])
|
82
|
+
else
|
83
|
+
joins_dependency, rest = values[:joins].partition do |join|
|
84
|
+
case join
|
85
|
+
when Hash, Symbol, Array
|
86
|
+
true
|
87
|
+
else
|
88
|
+
false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
join_dependency = ActiveRecord::Associations::JoinDependency.new(other.klass,
|
93
|
+
joins_dependency,
|
94
|
+
[])
|
95
|
+
relation.joins! rest
|
96
|
+
|
97
|
+
join_dependency.join_associations.each do |association|
|
98
|
+
@relation = association.join_relation(relation)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
75
103
|
def merge_multi_values
|
76
104
|
relation.where_values = merged_wheres
|
77
105
|
relation.bind_values = merged_binds
|
@@ -48,7 +48,7 @@ module ActiveRecord
|
|
48
48
|
column = reflection.foreign_key
|
49
49
|
end
|
50
50
|
|
51
|
-
queries << build(table[column
|
51
|
+
queries << build(table[column], value)
|
52
52
|
queries
|
53
53
|
end
|
54
54
|
|
@@ -98,11 +98,6 @@ module ActiveRecord
|
|
98
98
|
when Class
|
99
99
|
# FIXME: I think we need to deprecate this behavior
|
100
100
|
attribute.eq(value.name)
|
101
|
-
when Integer, ActiveSupport::Duration
|
102
|
-
# Arel treats integers as literals, but they should be quoted when compared with strings
|
103
|
-
table = attribute.relation
|
104
|
-
column = table.engine.connection.schema_cache.columns_hash(table.name)[attribute.name.to_s]
|
105
|
-
attribute.eq(Arel::Nodes::SqlLiteral.new(table.engine.connection.quote(value, column)))
|
106
101
|
else
|
107
102
|
attribute.eq(value)
|
108
103
|
end
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
# WhereChain objects act as placeholder for queries in which #where does not have any parameter.
|
8
|
-
# In this case, #where must be chained with
|
8
|
+
# In this case, #where must be chained with #not to return a new relation.
|
9
9
|
class WhereChain
|
10
10
|
def initialize(scope)
|
11
11
|
@scope = scope
|
@@ -34,7 +34,6 @@ module ActiveRecord
|
|
34
34
|
#
|
35
35
|
# User.where.not(name: "Jon", role: "admin")
|
36
36
|
# # SELECT * FROM users WHERE name != 'Jon' AND role != 'admin'
|
37
|
-
#
|
38
37
|
def not(opts, *rest)
|
39
38
|
where_value = @scope.send(:build_where, opts, rest).map do |rel|
|
40
39
|
case rel
|
@@ -285,6 +284,11 @@ module ActiveRecord
|
|
285
284
|
references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
|
286
285
|
references!(references) if references.any?
|
287
286
|
|
287
|
+
# if a symbol is given we prepend the quoted table name
|
288
|
+
args = args.map { |arg|
|
289
|
+
arg.is_a?(Symbol) ? "#{quoted_table_name}.#{arg} ASC" : arg
|
290
|
+
}
|
291
|
+
|
288
292
|
self.order_values = args + self.order_values
|
289
293
|
self
|
290
294
|
end
|
@@ -312,6 +316,67 @@ module ActiveRecord
|
|
312
316
|
self
|
313
317
|
end
|
314
318
|
|
319
|
+
VALID_UNSCOPING_VALUES = Set.new([:where, :select, :group, :order, :lock,
|
320
|
+
:limit, :offset, :joins, :includes, :from,
|
321
|
+
:readonly, :having])
|
322
|
+
|
323
|
+
# Removes an unwanted relation that is already defined on a chain of relations.
|
324
|
+
# This is useful when passing around chains of relations and would like to
|
325
|
+
# modify the relations without reconstructing the entire chain.
|
326
|
+
#
|
327
|
+
# User.order('email DESC').unscope(:order) == User.all
|
328
|
+
#
|
329
|
+
# The method arguments are symbols which correspond to the names of the methods
|
330
|
+
# which should be unscoped. The valid arguments are given in VALID_UNSCOPING_VALUES.
|
331
|
+
# The method can also be called with multiple arguments. For example:
|
332
|
+
#
|
333
|
+
# User.order('email DESC').select('id').where(name: "John")
|
334
|
+
# .unscope(:order, :select, :where) == User.all
|
335
|
+
#
|
336
|
+
# One can additionally pass a hash as an argument to unscope specific :where values.
|
337
|
+
# This is done by passing a hash with a single key-value pair. The key should be
|
338
|
+
# :where and the value should be the where value to unscope. For example:
|
339
|
+
#
|
340
|
+
# User.where(name: "John", active: true).unscope(where: :name)
|
341
|
+
# == User.where(active: true)
|
342
|
+
#
|
343
|
+
# Note that this method is more generalized than ActiveRecord::SpawnMethods#except
|
344
|
+
# because #except will only affect a particular relation's values. It won't wipe
|
345
|
+
# the order, grouping, etc. when that relation is merged. For example:
|
346
|
+
#
|
347
|
+
# Post.comments.except(:order)
|
348
|
+
#
|
349
|
+
# will still have an order if it comes from the default_scope on Comment.
|
350
|
+
def unscope(*args)
|
351
|
+
check_if_method_has_arguments!("unscope", args)
|
352
|
+
spawn.unscope!(*args)
|
353
|
+
end
|
354
|
+
|
355
|
+
def unscope!(*args) # :nodoc:
|
356
|
+
args.flatten!
|
357
|
+
|
358
|
+
args.each do |scope|
|
359
|
+
case scope
|
360
|
+
when Symbol
|
361
|
+
symbol_unscoping(scope)
|
362
|
+
when Hash
|
363
|
+
scope.each do |key, target_value|
|
364
|
+
if key != :where
|
365
|
+
raise ArgumentError, "Hash arguments in .unscope(*args) must have :where as the key."
|
366
|
+
end
|
367
|
+
|
368
|
+
Array(target_value).each do |val|
|
369
|
+
where_unscoping(val)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
else
|
373
|
+
raise ArgumentError, "Unrecognized scoping: #{args.inspect}. Use .unscope(where: :attribute_name) or .unscope(:order), for example."
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
self
|
378
|
+
end
|
379
|
+
|
315
380
|
# Performs a joins on +args+:
|
316
381
|
#
|
317
382
|
# User.joins(:posts)
|
@@ -486,7 +551,6 @@ module ActiveRecord
|
|
486
551
|
# Order.having('SUM(price) > 30').group('user_id')
|
487
552
|
def having(opts, *rest)
|
488
553
|
opts.blank? ? self : spawn.having!(opts, *rest)
|
489
|
-
spawn.having!(opts, *rest)
|
490
554
|
end
|
491
555
|
|
492
556
|
def having!(opts, *rest) # :nodoc:
|
@@ -548,7 +612,7 @@ module ActiveRecord
|
|
548
612
|
#
|
549
613
|
# The returned <tt>ActiveRecord::NullRelation</tt> inherits from Relation and implements the
|
550
614
|
# Null Object pattern. It is an object with defined null behavior and always returns an empty
|
551
|
-
# array of records without
|
615
|
+
# array of records without querying the database.
|
552
616
|
#
|
553
617
|
# Any subsequent condition chained to the returned relation will continue
|
554
618
|
# generating an empty relation and will not fire any query to the database.
|
@@ -644,20 +708,22 @@ module ActiveRecord
|
|
644
708
|
# User.select(:name)
|
645
709
|
# # => Might return two records with the same name
|
646
710
|
#
|
647
|
-
# User.select(:name).
|
648
|
-
# # => Returns 1 record per
|
711
|
+
# User.select(:name).distinct
|
712
|
+
# # => Returns 1 record per distinct name
|
649
713
|
#
|
650
|
-
# User.select(:name).
|
714
|
+
# User.select(:name).distinct.distinct(false)
|
651
715
|
# # => You can also remove the uniqueness
|
652
|
-
def
|
653
|
-
spawn.
|
716
|
+
def distinct(value = true)
|
717
|
+
spawn.distinct!(value)
|
654
718
|
end
|
719
|
+
alias uniq distinct
|
655
720
|
|
656
|
-
# Like #
|
657
|
-
def
|
658
|
-
self.
|
721
|
+
# Like #distinct, but modifies relation in place.
|
722
|
+
def distinct!(value = true) # :nodoc:
|
723
|
+
self.distinct_value = value
|
659
724
|
self
|
660
725
|
end
|
726
|
+
alias uniq! distinct!
|
661
727
|
|
662
728
|
# Used to extend a scope with additional methods, either through
|
663
729
|
# a module or through a block provided.
|
@@ -748,7 +814,7 @@ module ActiveRecord
|
|
748
814
|
|
749
815
|
build_select(arel, select_values.uniq)
|
750
816
|
|
751
|
-
arel.distinct(
|
817
|
+
arel.distinct(distinct_value)
|
752
818
|
arel.from(build_from) if from_value
|
753
819
|
arel.lock(lock_value) if lock_value
|
754
820
|
|
@@ -757,6 +823,39 @@ module ActiveRecord
|
|
757
823
|
|
758
824
|
private
|
759
825
|
|
826
|
+
def symbol_unscoping(scope)
|
827
|
+
if !VALID_UNSCOPING_VALUES.include?(scope)
|
828
|
+
raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
|
829
|
+
end
|
830
|
+
|
831
|
+
single_val_method = Relation::SINGLE_VALUE_METHODS.include?(scope)
|
832
|
+
unscope_code = :"#{scope}_value#{'s' unless single_val_method}="
|
833
|
+
|
834
|
+
case scope
|
835
|
+
when :order
|
836
|
+
self.send(:reverse_order_value=, false)
|
837
|
+
result = []
|
838
|
+
else
|
839
|
+
result = [] unless single_val_method
|
840
|
+
end
|
841
|
+
|
842
|
+
self.send(unscope_code, result)
|
843
|
+
end
|
844
|
+
|
845
|
+
def where_unscoping(target_value)
|
846
|
+
target_value_sym = target_value.to_sym
|
847
|
+
|
848
|
+
where_values.reject! do |rel|
|
849
|
+
case rel
|
850
|
+
when Arel::Nodes::In, Arel::Nodes::Equality
|
851
|
+
subrelation = (rel.left.kind_of?(Arel::Attributes::Attribute) ? rel.left : rel.right)
|
852
|
+
subrelation.name.to_sym == target_value_sym
|
853
|
+
else
|
854
|
+
raise "unscope(where: #{target_value.inspect}) failed: unscoping #{rel.class} is unimplemented."
|
855
|
+
end
|
856
|
+
end
|
857
|
+
end
|
858
|
+
|
760
859
|
def custom_join_ast(table, joins)
|
761
860
|
joins = joins.reject { |join| join.blank? }
|
762
861
|
|
@@ -833,9 +932,7 @@ module ActiveRecord
|
|
833
932
|
association_joins = buckets[:association_join] || []
|
834
933
|
stashed_association_joins = buckets[:stashed_join] || []
|
835
934
|
join_nodes = (buckets[:join_node] || []).uniq
|
836
|
-
string_joins = (buckets[:string_join] || []).map { |x|
|
837
|
-
x.strip
|
838
|
-
}.uniq
|
935
|
+
string_joins = (buckets[:string_join] || []).map { |x| x.strip }.uniq
|
839
936
|
|
840
937
|
join_list = join_nodes + custom_join_ast(manager, string_joins)
|
841
938
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'active_support/per_thread_registry'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
# This is a thread locals registry for Active Record. For example:
|
5
|
+
#
|
6
|
+
# ActiveRecord::RuntimeRegistry.connection_handler
|
7
|
+
#
|
8
|
+
# returns the connection handler local to the current thread.
|
9
|
+
#
|
10
|
+
# See the documentation of <tt>ActiveSupport::PerThreadRegistry</tt>
|
11
|
+
# for further details.
|
12
|
+
class RuntimeRegistry # :nodoc:
|
13
|
+
extend ActiveSupport::PerThreadRegistry
|
14
|
+
|
15
|
+
attr_accessor :connection_handler, :sql_runtime, :connection_id
|
16
|
+
end
|
17
|
+
end
|
@@ -118,7 +118,7 @@ HEADER
|
|
118
118
|
|
119
119
|
# then dump all non-primary key columns
|
120
120
|
column_specs = columns.map do |column|
|
121
|
-
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'"
|
121
|
+
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
|
122
122
|
next if column.name == pk
|
123
123
|
@connection.column_spec(column, @types)
|
124
124
|
end.compact
|
@@ -185,6 +185,10 @@ HEADER
|
|
185
185
|
|
186
186
|
statement_parts << ('where: ' + index.where.inspect) if index.where
|
187
187
|
|
188
|
+
statement_parts << ('using: ' + index.using.inspect) if index.using
|
189
|
+
|
190
|
+
statement_parts << ('type: ' + index.type.inspect) if index.type
|
191
|
+
|
188
192
|
' ' + statement_parts.join(', ')
|
189
193
|
end
|
190
194
|
|