activerecord 4.0.4 → 4.1.16
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 +1632 -1797
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/examples/performance.rb +30 -18
- data/examples/simple.rb +4 -4
- data/lib/active_record/aggregations.rb +2 -1
- data/lib/active_record/association_relation.rb +4 -0
- data/lib/active_record/associations/alias_tracker.rb +49 -29
- data/lib/active_record/associations/association.rb +9 -17
- data/lib/active_record/associations/association_scope.rb +59 -49
- data/lib/active_record/associations/belongs_to_association.rb +34 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +6 -1
- data/lib/active_record/associations/builder/association.rb +84 -54
- data/lib/active_record/associations/builder/belongs_to.rb +90 -58
- data/lib/active_record/associations/builder/collection_association.rb +47 -45
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +119 -25
- data/lib/active_record/associations/builder/has_many.rb +3 -3
- 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 +121 -111
- data/lib/active_record/associations/collection_proxy.rb +73 -18
- data/lib/active_record/associations/has_many_association.rb +14 -11
- data/lib/active_record/associations/has_many_through_association.rb +33 -6
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +46 -104
- 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_dependency.rb +208 -168
- data/lib/active_record/associations/preloader/association.rb +69 -27
- 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/preloader.rb +63 -49
- data/lib/active_record/associations/singular_association.rb +6 -5
- data/lib/active_record/associations/through_association.rb +30 -9
- data/lib/active_record/associations.rb +116 -42
- data/lib/active_record/attribute_assignment.rb +6 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
- data/lib/active_record/attribute_methods/dirty.rb +35 -26
- data/lib/active_record/attribute_methods/primary_key.rb +8 -1
- data/lib/active_record/attribute_methods/read.rb +56 -29
- data/lib/active_record/attribute_methods/serialization.rb +44 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +13 -1
- data/lib/active_record/attribute_methods/write.rb +59 -26
- data/lib/active_record/attribute_methods.rb +82 -43
- data/lib/active_record/autosave_association.rb +209 -194
- data/lib/active_record/base.rb +6 -2
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +5 -10
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +14 -24
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -13
- data/lib/active_record/connection_adapters/abstract/quoting.rb +6 -3
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +90 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +45 -70
- data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -96
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +74 -66
- data/lib/active_record/connection_adapters/column.rb +1 -35
- data/lib/active_record/connection_adapters/connection_specification.rb +231 -43
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -5
- data/lib/active_record/connection_adapters/mysql_adapter.rb +24 -17
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +22 -15
- data/lib/active_record/connection_adapters/postgresql/cast.rb +12 -4
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -44
- data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -14
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +37 -12
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +20 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +98 -52
- data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -60
- data/lib/active_record/connection_handling.rb +39 -5
- data/lib/active_record/core.rb +38 -54
- data/lib/active_record/counter_cache.rb +9 -10
- data/lib/active_record/dynamic_matchers.rb +6 -2
- data/lib/active_record/enum.rb +199 -0
- data/lib/active_record/errors.rb +22 -5
- data/lib/active_record/fixture_set/file.rb +2 -1
- data/lib/active_record/fixtures.rb +173 -76
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +23 -9
- data/lib/active_record/integration.rb +54 -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 +6 -13
- data/lib/active_record/migration/command_recorder.rb +8 -2
- data/lib/active_record/migration.rb +91 -56
- data/lib/active_record/model_schema.rb +7 -14
- data/lib/active_record/nested_attributes.rb +25 -13
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +26 -6
- data/lib/active_record/persistence.rb +23 -29
- data/lib/active_record/querying.rb +15 -12
- data/lib/active_record/railtie.rb +12 -61
- data/lib/active_record/railties/databases.rake +37 -56
- data/lib/active_record/readonly_attributes.rb +0 -6
- data/lib/active_record/reflection.rb +230 -79
- data/lib/active_record/relation/batches.rb +74 -24
- data/lib/active_record/relation/calculations.rb +52 -48
- data/lib/active_record/relation/delegation.rb +54 -39
- data/lib/active_record/relation/finder_methods.rb +210 -67
- data/lib/active_record/relation/merger.rb +15 -12
- data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder.rb +81 -40
- data/lib/active_record/relation/query_methods.rb +185 -108
- data/lib/active_record/relation/spawn_methods.rb +8 -5
- data/lib/active_record/relation.rb +79 -84
- data/lib/active_record/result.rb +45 -6
- data/lib/active_record/runtime_registry.rb +5 -0
- data/lib/active_record/sanitization.rb +4 -4
- data/lib/active_record/schema_dumper.rb +18 -6
- data/lib/active_record/schema_migration.rb +31 -18
- data/lib/active_record/scoping/default.rb +5 -18
- data/lib/active_record/scoping/named.rb +14 -29
- data/lib/active_record/scoping.rb +5 -0
- data/lib/active_record/store.rb +67 -18
- data/lib/active_record/tasks/database_tasks.rb +66 -26
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -10
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/transactions.rb +10 -12
- data/lib/active_record/validations/presence.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +19 -9
- data/lib/active_record/version.rb +4 -7
- data/lib/active_record.rb +5 -7
- data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
- data/lib/rails/generators/active_record/migration.rb +18 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
- data/lib/rails/generators/active_record.rb +2 -8
- metadata +18 -30
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
- data/lib/active_record/associations/join_helper.rb +0 -45
- 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 -96
@@ -7,7 +7,7 @@ module ActiveRecord
|
|
7
7
|
|
8
8
|
MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
|
9
9
|
:order, :joins, :where, :having, :bind, :references,
|
10
|
-
:extending]
|
10
|
+
:extending, :unscope]
|
11
11
|
|
12
12
|
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering,
|
13
13
|
:reverse_order, :distinct, :create_with, :uniq]
|
@@ -17,18 +17,15 @@ module ActiveRecord
|
|
17
17
|
include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
|
18
18
|
|
19
19
|
attr_reader :table, :klass, :loaded
|
20
|
-
attr_accessor :default_scoped
|
21
20
|
alias :model :klass
|
22
21
|
alias :loaded? :loaded
|
23
|
-
alias :default_scoped? :default_scoped
|
24
22
|
|
25
23
|
def initialize(klass, table, values = {})
|
26
|
-
@klass
|
27
|
-
@table
|
28
|
-
@values
|
29
|
-
@
|
30
|
-
@loaded
|
31
|
-
@default_scoped = false
|
24
|
+
@klass = klass
|
25
|
+
@table = table
|
26
|
+
@values = values
|
27
|
+
@offsets = {}
|
28
|
+
@loaded = false
|
32
29
|
end
|
33
30
|
|
34
31
|
def initialize_copy(other)
|
@@ -39,7 +36,7 @@ module ActiveRecord
|
|
39
36
|
reset
|
40
37
|
end
|
41
38
|
|
42
|
-
def insert(values)
|
39
|
+
def insert(values) # :nodoc:
|
43
40
|
primary_key_value = nil
|
44
41
|
|
45
42
|
if primary_key && Hash === values
|
@@ -56,16 +53,7 @@ module ActiveRecord
|
|
56
53
|
im = arel.create_insert
|
57
54
|
im.into @table
|
58
55
|
|
59
|
-
|
60
|
-
|
61
|
-
substitutes = values.sort_by { |arel_attr,_| arel_attr.name }
|
62
|
-
binds = substitutes.map do |arel_attr, value|
|
63
|
-
[@klass.columns_hash[arel_attr.name], value]
|
64
|
-
end
|
65
|
-
|
66
|
-
substitutes.each_with_index do |tuple, i|
|
67
|
-
tuple[1] = conn.substitute_at(binds[i][0], i)
|
68
|
-
end
|
56
|
+
substitutes, binds = substitute_values values
|
69
57
|
|
70
58
|
if values.empty? # empty insert
|
71
59
|
im.values = Arel.sql(connection.empty_insert_statement_value)
|
@@ -73,7 +61,7 @@ module ActiveRecord
|
|
73
61
|
im.insert substitutes
|
74
62
|
end
|
75
63
|
|
76
|
-
|
64
|
+
@klass.connection.insert(
|
77
65
|
im,
|
78
66
|
'SQL',
|
79
67
|
primary_key,
|
@@ -82,6 +70,36 @@ module ActiveRecord
|
|
82
70
|
binds)
|
83
71
|
end
|
84
72
|
|
73
|
+
def _update_record(values, id, id_was) # :nodoc:
|
74
|
+
substitutes, binds = substitute_values values
|
75
|
+
|
76
|
+
scope = @klass.unscoped
|
77
|
+
|
78
|
+
if @klass.finder_needs_type_condition?
|
79
|
+
scope.unscope!(where: @klass.inheritance_column)
|
80
|
+
end
|
81
|
+
|
82
|
+
um = scope.where(@klass.arel_table[@klass.primary_key].eq(id_was || id)).arel.compile_update(substitutes, @klass.primary_key)
|
83
|
+
|
84
|
+
@klass.connection.update(
|
85
|
+
um,
|
86
|
+
'SQL',
|
87
|
+
binds)
|
88
|
+
end
|
89
|
+
|
90
|
+
def substitute_values(values) # :nodoc:
|
91
|
+
substitutes = values.sort_by { |arel_attr,_| arel_attr.name }
|
92
|
+
binds = substitutes.map do |arel_attr, value|
|
93
|
+
[@klass.columns_hash[arel_attr.name], value]
|
94
|
+
end
|
95
|
+
|
96
|
+
substitutes.each_with_index do |tuple, i|
|
97
|
+
tuple[1] = @klass.connection.substitute_at(binds[i][0], i)
|
98
|
+
end
|
99
|
+
|
100
|
+
[substitutes, binds]
|
101
|
+
end
|
102
|
+
|
85
103
|
# Initializes new record from relation while maintaining the current
|
86
104
|
# scope.
|
87
105
|
#
|
@@ -227,15 +245,19 @@ module ActiveRecord
|
|
227
245
|
|
228
246
|
# Returns size of the records.
|
229
247
|
def size
|
230
|
-
loaded? ? @records.length : count
|
248
|
+
loaded? ? @records.length : count(:all)
|
231
249
|
end
|
232
250
|
|
233
251
|
# Returns true if there are no records.
|
234
252
|
def empty?
|
235
253
|
return @records.empty? if loaded?
|
236
254
|
|
237
|
-
|
238
|
-
|
255
|
+
if limit_value == 0
|
256
|
+
true
|
257
|
+
else
|
258
|
+
c = count(:all)
|
259
|
+
c.respond_to?(:zero?) ? c.zero? : c.empty?
|
260
|
+
end
|
239
261
|
end
|
240
262
|
|
241
263
|
# Returns true if there are any records.
|
@@ -300,7 +322,7 @@ module ActiveRecord
|
|
300
322
|
stmt.table(table)
|
301
323
|
stmt.key = table[primary_key]
|
302
324
|
|
303
|
-
if
|
325
|
+
if joins_values.any?
|
304
326
|
@klass.connection.join_to_update(stmt, arel)
|
305
327
|
else
|
306
328
|
stmt.take(arel.limit)
|
@@ -425,7 +447,7 @@ module ActiveRecord
|
|
425
447
|
stmt = Arel::DeleteManager.new(arel.engine)
|
426
448
|
stmt.from(table)
|
427
449
|
|
428
|
-
if
|
450
|
+
if joins_values.any?
|
429
451
|
@klass.connection.join_to_delete(stmt, arel, table[primary_key])
|
430
452
|
else
|
431
453
|
stmt.wheres = arel.constraints
|
@@ -480,9 +502,10 @@ module ActiveRecord
|
|
480
502
|
end
|
481
503
|
|
482
504
|
def reset
|
483
|
-
@
|
505
|
+
@last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
|
484
506
|
@should_eager_load = @join_dependency = nil
|
485
507
|
@records = []
|
508
|
+
@offsets = {}
|
486
509
|
self
|
487
510
|
end
|
488
511
|
|
@@ -491,16 +514,30 @@ module ActiveRecord
|
|
491
514
|
# User.where(name: 'Oscar').to_sql
|
492
515
|
# # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
|
493
516
|
def to_sql
|
494
|
-
@to_sql ||=
|
517
|
+
@to_sql ||= begin
|
518
|
+
relation = self
|
519
|
+
connection = klass.connection
|
520
|
+
visitor = connection.visitor
|
521
|
+
|
522
|
+
if eager_loading?
|
523
|
+
find_with_associations { |rel| relation = rel }
|
524
|
+
end
|
525
|
+
|
526
|
+
ast = relation.arel.ast
|
527
|
+
binds = relation.bind_values.dup
|
528
|
+
visitor.accept(ast) do
|
529
|
+
connection.quote(*binds.shift.reverse)
|
530
|
+
end
|
531
|
+
end
|
495
532
|
end
|
496
533
|
|
497
534
|
# Returns a hash of where conditions.
|
498
535
|
#
|
499
536
|
# User.where(name: 'Oscar').where_values_hash
|
500
537
|
# # => {name: "Oscar"}
|
501
|
-
def where_values_hash
|
502
|
-
equalities =
|
503
|
-
node.left.relation.name ==
|
538
|
+
def where_values_hash(relation_table_name = table_name)
|
539
|
+
equalities = where_values.grep(Arel::Nodes::Equality).find_all { |node|
|
540
|
+
node.left.relation.name == relation_table_name
|
504
541
|
}
|
505
542
|
|
506
543
|
binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
|
@@ -539,6 +576,8 @@ module ActiveRecord
|
|
539
576
|
# Compares two relations for equality.
|
540
577
|
def ==(other)
|
541
578
|
case other
|
579
|
+
when Associations::CollectionProxy, AssociationRelation
|
580
|
+
self == other.to_a
|
542
581
|
when Relation
|
543
582
|
other.to_sql == to_sql
|
544
583
|
when Array
|
@@ -550,16 +589,6 @@ module ActiveRecord
|
|
550
589
|
q.pp(self.to_a)
|
551
590
|
end
|
552
591
|
|
553
|
-
def with_default_scope #:nodoc:
|
554
|
-
if default_scoped? && default_scope = klass.send(:build_default_scope)
|
555
|
-
default_scope = default_scope.merge(self)
|
556
|
-
default_scope.default_scoped = false
|
557
|
-
default_scope
|
558
|
-
else
|
559
|
-
self
|
560
|
-
end
|
561
|
-
end
|
562
|
-
|
563
592
|
# Returns true if relation is blank.
|
564
593
|
def blank?
|
565
594
|
to_a.blank?
|
@@ -579,25 +608,17 @@ module ActiveRecord
|
|
579
608
|
private
|
580
609
|
|
581
610
|
def exec_queries
|
582
|
-
|
583
|
-
|
584
|
-
if default_scoped.equal?(self)
|
585
|
-
@records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, bind_values)
|
611
|
+
@records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, bind_values)
|
586
612
|
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
# @readonly_value is true only if set explicitly. @implicit_readonly is true if there
|
594
|
-
# are JOINS and no explicit SELECT.
|
595
|
-
readonly = readonly_value.nil? ? @implicit_readonly : readonly_value
|
596
|
-
@records.each { |record| record.readonly! } if readonly
|
597
|
-
else
|
598
|
-
@records = default_scoped.to_a
|
613
|
+
preload = preload_values
|
614
|
+
preload += includes_values unless eager_loading?
|
615
|
+
preloader = ActiveRecord::Associations::Preloader.new
|
616
|
+
preload.each do |associations|
|
617
|
+
preloader.preload @records, associations
|
599
618
|
end
|
600
619
|
|
620
|
+
@records.each { |record| record.readonly! } if readonly_value
|
621
|
+
|
601
622
|
@loaded = true
|
602
623
|
@records
|
603
624
|
end
|
@@ -615,34 +636,8 @@ module ActiveRecord
|
|
615
636
|
|
616
637
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
617
638
|
joined_tables = joined_tables.flatten.compact.map { |t| t.downcase }.uniq
|
618
|
-
string_tables = tables_in_string(to_sql)
|
619
639
|
|
620
|
-
|
621
|
-
true
|
622
|
-
elsif !ActiveRecord::Base.disable_implicit_join_references &&
|
623
|
-
(string_tables - joined_tables).any?
|
624
|
-
ActiveSupport::Deprecation.warn(
|
625
|
-
"It looks like you are eager loading table(s) (one of: #{string_tables.join(', ')}) " \
|
626
|
-
"that are referenced in a string SQL snippet. For example: \n" \
|
627
|
-
"\n" \
|
628
|
-
" Post.includes(:comments).where(\"comments.title = 'foo'\")\n" \
|
629
|
-
"\n" \
|
630
|
-
"Currently, Active Record recognizes the table in the string, and knows to JOIN the " \
|
631
|
-
"comments table to the query, rather than loading comments in a separate query. " \
|
632
|
-
"However, doing this without writing a full-blown SQL parser is inherently flawed. " \
|
633
|
-
"Since we don't want to write an SQL parser, we are removing this functionality. " \
|
634
|
-
"From now on, you must explicitly tell Active Record when you are referencing a table " \
|
635
|
-
"from a string:\n" \
|
636
|
-
"\n" \
|
637
|
-
" Post.includes(:comments).where(\"comments.title = 'foo'\").references(:comments)\n" \
|
638
|
-
"\n" \
|
639
|
-
"If you don't rely on implicit join references you can disable the feature entirely " \
|
640
|
-
"by setting `config.active_record.disable_implicit_join_references = true`."
|
641
|
-
)
|
642
|
-
true
|
643
|
-
else
|
644
|
-
false
|
645
|
-
end
|
640
|
+
(references_values - joined_tables).any?
|
646
641
|
end
|
647
642
|
|
648
643
|
def tables_in_string(string)
|
data/lib/active_record/result.rb
CHANGED
@@ -3,11 +3,36 @@ module ActiveRecord
|
|
3
3
|
# This class encapsulates a Result returned from calling +exec_query+ on any
|
4
4
|
# database connection adapter. For example:
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# result = ActiveRecord::Base.connection.exec_query('SELECT id, title, body FROM posts')
|
7
|
+
# result # => #<ActiveRecord::Result:0xdeadbeef>
|
8
|
+
#
|
9
|
+
# # Get the column names of the result:
|
10
|
+
# result.columns
|
11
|
+
# # => ["id", "title", "body"]
|
12
|
+
#
|
13
|
+
# # Get the record values of the result:
|
14
|
+
# result.rows
|
15
|
+
# # => [[1, "title_1", "body_1"],
|
16
|
+
# [2, "title_2", "body_2"],
|
17
|
+
# ...
|
18
|
+
# ]
|
19
|
+
#
|
20
|
+
# # Get an array of hashes representing the result (column => value):
|
21
|
+
# result.to_hash
|
22
|
+
# # => [{"id" => 1, "title" => "title_1", "body" => "body_1"},
|
23
|
+
# {"id" => 2, "title" => "title_2", "body" => "body_2"},
|
24
|
+
# ...
|
25
|
+
# ]
|
26
|
+
#
|
27
|
+
# # ActiveRecord::Result also includes Enumerable.
|
28
|
+
# result.each do |row|
|
29
|
+
# puts row['title'] + " " + row['body']
|
30
|
+
# end
|
8
31
|
class Result
|
9
32
|
include Enumerable
|
10
33
|
|
34
|
+
IDENTITY_TYPE = Class.new { def type_cast(v); v; end }.new # :nodoc:
|
35
|
+
|
11
36
|
attr_reader :columns, :rows, :column_types
|
12
37
|
|
13
38
|
def initialize(columns, rows, column_types = {})
|
@@ -17,8 +42,20 @@ module ActiveRecord
|
|
17
42
|
@column_types = column_types
|
18
43
|
end
|
19
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
|
+
|
20
53
|
def each
|
21
|
-
|
54
|
+
if block_given?
|
55
|
+
hash_rows.each { |row| yield row }
|
56
|
+
else
|
57
|
+
hash_rows.to_enum { @rows.size }
|
58
|
+
end
|
22
59
|
end
|
23
60
|
|
24
61
|
def to_hash
|
@@ -46,12 +83,14 @@ module ActiveRecord
|
|
46
83
|
end
|
47
84
|
|
48
85
|
def initialize_copy(other)
|
49
|
-
@columns
|
50
|
-
@rows
|
51
|
-
@
|
86
|
+
@columns = columns.dup
|
87
|
+
@rows = rows.dup
|
88
|
+
@column_types = column_types.dup
|
89
|
+
@hash_rows = nil
|
52
90
|
end
|
53
91
|
|
54
92
|
private
|
93
|
+
|
55
94
|
def hash_rows
|
56
95
|
@hash_rows ||=
|
57
96
|
begin
|
@@ -13,5 +13,10 @@ module ActiveRecord
|
|
13
13
|
extend ActiveSupport::PerThreadRegistry
|
14
14
|
|
15
15
|
attr_accessor :connection_handler, :sql_runtime, :connection_id
|
16
|
+
|
17
|
+
[:connection_handler, :sql_runtime, :connection_id].each do |val|
|
18
|
+
class_eval %{ def self.#{val}; instance.#{val}; end }, __FILE__, __LINE__
|
19
|
+
class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__
|
20
|
+
end
|
16
21
|
end
|
17
22
|
end
|
@@ -3,8 +3,8 @@ module ActiveRecord
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
module ClassMethods
|
6
|
-
def quote_value(value, column
|
7
|
-
connection.quote(value,column)
|
6
|
+
def quote_value(value, column) #:nodoc:
|
7
|
+
connection.quote(value, column)
|
8
8
|
end
|
9
9
|
|
10
10
|
# Used to sanitize objects before they're used in an SQL SELECT statement. Delegates to <tt>connection.quote</tt>.
|
@@ -29,6 +29,7 @@ module ActiveRecord
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
alias_method :sanitize_sql, :sanitize_sql_for_conditions
|
32
|
+
alias_method :sanitize_conditions, :sanitize_sql
|
32
33
|
|
33
34
|
# Accepts an array, hash, or string of SQL conditions and sanitizes
|
34
35
|
# them into a valid SQL fragment for a SET clause.
|
@@ -86,6 +87,7 @@ module ActiveRecord
|
|
86
87
|
# { address: Address.new("123 abc st.", "chicago") }
|
87
88
|
# # => "address_street='123 abc st.' and address_city='chicago'"
|
88
89
|
def sanitize_sql_hash_for_conditions(attrs, default_table_name = self.table_name)
|
90
|
+
attrs = PredicateBuilder.resolve_column_aliases self, attrs
|
89
91
|
attrs = expand_hash_conditions_for_aggregates(attrs)
|
90
92
|
|
91
93
|
table = Arel::Table.new(table_name, arel_engine).alias(default_table_name)
|
@@ -121,8 +123,6 @@ module ActiveRecord
|
|
121
123
|
end
|
122
124
|
end
|
123
125
|
|
124
|
-
alias_method :sanitize_conditions, :sanitize_sql
|
125
|
-
|
126
126
|
def replace_bind_variables(statement, values) #:nodoc:
|
127
127
|
raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
|
128
128
|
bound = values.dup
|
@@ -17,9 +17,19 @@ module ActiveRecord
|
|
17
17
|
cattr_accessor :ignore_tables
|
18
18
|
@@ignore_tables = []
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
class << self
|
21
|
+
def dump(connection=ActiveRecord::Base.connection, stream=STDOUT, config = ActiveRecord::Base)
|
22
|
+
new(connection, generate_options(config)).dump(stream)
|
23
|
+
stream
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def generate_options(config)
|
28
|
+
{
|
29
|
+
table_name_prefix: config.table_name_prefix,
|
30
|
+
table_name_suffix: config.table_name_suffix
|
31
|
+
}
|
32
|
+
end
|
23
33
|
end
|
24
34
|
|
25
35
|
def dump(stream)
|
@@ -32,10 +42,11 @@ module ActiveRecord
|
|
32
42
|
|
33
43
|
private
|
34
44
|
|
35
|
-
def initialize(connection)
|
45
|
+
def initialize(connection, options = {})
|
36
46
|
@connection = connection
|
37
47
|
@types = @connection.native_database_types
|
38
48
|
@version = Migrator::current_version rescue nil
|
49
|
+
@options = options
|
39
50
|
end
|
40
51
|
|
41
52
|
def header(stream)
|
@@ -101,7 +112,8 @@ HEADER
|
|
101
112
|
# first dump primary key column
|
102
113
|
if @connection.respond_to?(:pk_and_sequence_for)
|
103
114
|
pk, _ = @connection.pk_and_sequence_for(table)
|
104
|
-
|
115
|
+
end
|
116
|
+
if !pk && @connection.respond_to?(:primary_key)
|
105
117
|
pk = @connection.primary_key(table)
|
106
118
|
end
|
107
119
|
|
@@ -202,7 +214,7 @@ HEADER
|
|
202
214
|
end
|
203
215
|
|
204
216
|
def remove_prefix_and_suffix(table)
|
205
|
-
table.gsub(/^(#{
|
217
|
+
table.gsub(/^(#{@options[:table_name_prefix]})(.+)(#{@options[:table_name_suffix]})$/, "\\2")
|
206
218
|
end
|
207
219
|
end
|
208
220
|
end
|
@@ -4,31 +4,44 @@ require 'active_record/base'
|
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
6
|
class SchemaMigration < ActiveRecord::Base
|
7
|
+
class << self
|
8
|
+
def primary_key
|
9
|
+
nil
|
10
|
+
end
|
7
11
|
|
8
|
-
|
9
|
-
|
10
|
-
|
12
|
+
def table_name
|
13
|
+
"#{table_name_prefix}#{ActiveRecord::Base.schema_migrations_table_name}#{table_name_suffix}"
|
14
|
+
end
|
11
15
|
|
12
|
-
|
13
|
-
|
14
|
-
|
16
|
+
def index_name
|
17
|
+
"#{table_name_prefix}unique_#{ActiveRecord::Base.schema_migrations_table_name}#{table_name_suffix}"
|
18
|
+
end
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
version_options[:limit] = limit if limit
|
20
|
+
def table_exists?
|
21
|
+
connection.table_exists?(table_name)
|
22
|
+
end
|
20
23
|
|
21
|
-
|
22
|
-
|
24
|
+
def create_table(limit=nil)
|
25
|
+
unless table_exists?
|
26
|
+
version_options = {null: false}
|
27
|
+
version_options[:limit] = limit if limit
|
28
|
+
|
29
|
+
connection.create_table(table_name, id: false) do |t|
|
30
|
+
t.column :version, :string, version_options
|
31
|
+
end
|
32
|
+
connection.add_index table_name, :version, unique: true, name: index_name
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def drop_table
|
37
|
+
if table_exists?
|
38
|
+
connection.remove_index table_name, name: index_name
|
39
|
+
connection.drop_table(table_name)
|
23
40
|
end
|
24
|
-
connection.add_index table_name, :version, unique: true, name: index_name
|
25
41
|
end
|
26
|
-
end
|
27
42
|
|
28
|
-
|
29
|
-
|
30
|
-
connection.remove_index table_name, name: index_name
|
31
|
-
connection.drop_table(table_name)
|
43
|
+
def normalize_migration_number(number)
|
44
|
+
"%.3d" % number.to_i
|
32
45
|
end
|
33
46
|
end
|
34
47
|
|
@@ -8,14 +8,6 @@ module ActiveRecord
|
|
8
8
|
class_attribute :default_scopes, instance_writer: false, instance_predicate: false
|
9
9
|
|
10
10
|
self.default_scopes = []
|
11
|
-
|
12
|
-
def self.default_scopes?
|
13
|
-
ActiveSupport::Deprecation.warn(
|
14
|
-
"#default_scopes? is deprecated. Do something like #default_scopes.empty? instead."
|
15
|
-
)
|
16
|
-
|
17
|
-
!!self.default_scopes
|
18
|
-
end
|
19
11
|
end
|
20
12
|
|
21
13
|
module ClassMethods
|
@@ -91,29 +83,24 @@ module ActiveRecord
|
|
91
83
|
scope = Proc.new if block_given?
|
92
84
|
|
93
85
|
if scope.is_a?(Relation) || !scope.respond_to?(:call)
|
94
|
-
|
95
|
-
"
|
86
|
+
raise ArgumentError,
|
87
|
+
"Support for calling #default_scope without a block is removed. For example instead " \
|
96
88
|
"of `default_scope where(color: 'red')`, please use " \
|
97
89
|
"`default_scope { where(color: 'red') }`. (Alternatively you can just redefine " \
|
98
90
|
"self.default_scope.)"
|
99
|
-
)
|
100
91
|
end
|
101
92
|
|
102
93
|
self.default_scopes += [scope]
|
103
94
|
end
|
104
95
|
|
105
|
-
def build_default_scope # :nodoc:
|
96
|
+
def build_default_scope(base_rel = relation) # :nodoc:
|
106
97
|
if !Base.is_a?(method(:default_scope).owner)
|
107
98
|
# The user has defined their own default scope method, so call that
|
108
99
|
evaluate_default_scope { default_scope }
|
109
100
|
elsif default_scopes.any?
|
110
101
|
evaluate_default_scope do
|
111
|
-
default_scopes.inject(
|
112
|
-
|
113
|
-
default_scope.merge(unscoped { scope.call })
|
114
|
-
else
|
115
|
-
default_scope.merge(scope)
|
116
|
-
end
|
102
|
+
default_scopes.inject(base_rel) do |default_scope, scope|
|
103
|
+
default_scope.merge(base_rel.scoping { scope.call })
|
117
104
|
end
|
118
105
|
end
|
119
106
|
end
|
@@ -25,22 +25,18 @@ module ActiveRecord
|
|
25
25
|
if current_scope
|
26
26
|
current_scope.clone
|
27
27
|
else
|
28
|
-
|
29
|
-
scope.default_scoped = true
|
30
|
-
scope
|
28
|
+
default_scoped
|
31
29
|
end
|
32
30
|
end
|
33
31
|
|
32
|
+
def default_scoped # :nodoc:
|
33
|
+
relation.merge(build_default_scope)
|
34
|
+
end
|
35
|
+
|
34
36
|
# Collects attributes from scopes that should be applied when creating
|
35
37
|
# an AR instance for the particular class this is called on.
|
36
38
|
def scope_attributes # :nodoc:
|
37
|
-
|
38
|
-
current_scope.scope_for_create
|
39
|
-
else
|
40
|
-
scope = relation
|
41
|
-
scope.default_scoped = true
|
42
|
-
scope.scope_for_create
|
43
|
-
end
|
39
|
+
all.scope_for_create
|
44
40
|
end
|
45
41
|
|
46
42
|
# Are there default attributes associated with this scope?
|
@@ -143,28 +139,17 @@ module ActiveRecord
|
|
143
139
|
# Article.published.featured.latest_article
|
144
140
|
# Article.featured.titles
|
145
141
|
def scope(name, body, &block)
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
if body.is_a?(Relation) || !body.respond_to?(:call)
|
151
|
-
ActiveSupport::Deprecation.warn(
|
152
|
-
"Using #scope without passing a callable object is deprecated. For " \
|
153
|
-
"example `scope :red, where(color: 'red')` should be changed to " \
|
154
|
-
"`scope :red, -> { where(color: 'red') }`. There are numerous gotchas " \
|
155
|
-
"in the former usage and it makes the implementation more complicated " \
|
156
|
-
"and buggy. (If you prefer, you can just define a class method named " \
|
157
|
-
"`self.red`.)"
|
158
|
-
)
|
142
|
+
if dangerous_class_method?(name)
|
143
|
+
raise ArgumentError, "You tried to define a scope named \"#{name}\" " \
|
144
|
+
"on the model \"#{self.name}\", but Active Record already defined " \
|
145
|
+
"a class method with the same name."
|
159
146
|
end
|
160
147
|
|
148
|
+
extension = Module.new(&block) if block
|
149
|
+
|
161
150
|
singleton_class.send(:define_method, name) do |*args|
|
162
|
-
|
163
|
-
|
164
|
-
scope = scope.extending(extension) if extension
|
165
|
-
else
|
166
|
-
scope = body
|
167
|
-
end
|
151
|
+
scope = all.scoping { body.call(*args) }
|
152
|
+
scope = scope.extending(extension) if extension
|
168
153
|
|
169
154
|
scope || all
|
170
155
|
end
|
@@ -27,6 +27,11 @@ module ActiveRecord
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
def initialize_internals_callback
|
31
|
+
super
|
32
|
+
populate_with_current_scope_attributes
|
33
|
+
end
|
34
|
+
|
30
35
|
# This class stores the +:current_scope+ and +:ignore_default_scope+ values
|
31
36
|
# for different classes. The registry is stored as a thread local, which is
|
32
37
|
# accessed through +ScopeRegistry.current+.
|