activerecord 3.0.0 → 4.0.0

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.

Files changed (181) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +2102 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +35 -44
  5. data/examples/performance.rb +110 -100
  6. data/lib/active_record/aggregations.rb +59 -75
  7. data/lib/active_record/associations/alias_tracker.rb +76 -0
  8. data/lib/active_record/associations/association.rb +248 -0
  9. data/lib/active_record/associations/association_scope.rb +135 -0
  10. data/lib/active_record/associations/belongs_to_association.rb +60 -59
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +16 -59
  12. data/lib/active_record/associations/builder/association.rb +108 -0
  13. data/lib/active_record/associations/builder/belongs_to.rb +98 -0
  14. data/lib/active_record/associations/builder/collection_association.rb +89 -0
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +39 -0
  16. data/lib/active_record/associations/builder/has_many.rb +15 -0
  17. data/lib/active_record/associations/builder/has_one.rb +25 -0
  18. data/lib/active_record/associations/builder/singular_association.rb +32 -0
  19. data/lib/active_record/associations/collection_association.rb +608 -0
  20. data/lib/active_record/associations/collection_proxy.rb +986 -0
  21. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +40 -112
  22. data/lib/active_record/associations/has_many_association.rb +83 -76
  23. data/lib/active_record/associations/has_many_through_association.rb +147 -66
  24. data/lib/active_record/associations/has_one_association.rb +67 -108
  25. data/lib/active_record/associations/has_one_through_association.rb +21 -25
  26. data/lib/active_record/associations/join_dependency/join_association.rb +174 -0
  27. data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
  28. data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
  29. data/lib/active_record/associations/join_dependency.rb +235 -0
  30. data/lib/active_record/associations/join_helper.rb +45 -0
  31. data/lib/active_record/associations/preloader/association.rb +121 -0
  32. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  33. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  34. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
  35. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  36. data/lib/active_record/associations/preloader/has_many_through.rb +19 -0
  37. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  38. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  39. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  40. data/lib/active_record/associations/preloader/through_association.rb +63 -0
  41. data/lib/active_record/associations/preloader.rb +178 -0
  42. data/lib/active_record/associations/singular_association.rb +64 -0
  43. data/lib/active_record/associations/through_association.rb +87 -0
  44. data/lib/active_record/associations.rb +512 -1224
  45. data/lib/active_record/attribute_assignment.rb +201 -0
  46. data/lib/active_record/attribute_methods/before_type_cast.rb +49 -12
  47. data/lib/active_record/attribute_methods/dirty.rb +51 -28
  48. data/lib/active_record/attribute_methods/primary_key.rb +94 -22
  49. data/lib/active_record/attribute_methods/query.rb +5 -4
  50. data/lib/active_record/attribute_methods/read.rb +63 -72
  51. data/lib/active_record/attribute_methods/serialization.rb +162 -0
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -41
  53. data/lib/active_record/attribute_methods/write.rb +39 -13
  54. data/lib/active_record/attribute_methods.rb +362 -29
  55. data/lib/active_record/autosave_association.rb +132 -75
  56. data/lib/active_record/base.rb +83 -1627
  57. data/lib/active_record/callbacks.rb +69 -47
  58. data/lib/active_record/coders/yaml_column.rb +38 -0
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +411 -138
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +21 -11
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +234 -173
  62. data/lib/active_record/connection_adapters/abstract/query_cache.rb +36 -22
  63. data/lib/active_record/connection_adapters/abstract/quoting.rb +82 -25
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +176 -414
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +562 -232
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +281 -53
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +782 -0
  70. data/lib/active_record/connection_adapters/column.rb +318 -0
  71. data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
  72. data/lib/active_record/connection_adapters/mysql2_adapter.rb +273 -0
  73. data/lib/active_record/connection_adapters/mysql_adapter.rb +365 -450
  74. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
  75. data/lib/active_record/connection_adapters/postgresql/cast.rb +152 -0
  76. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid.rb +366 -0
  78. data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -0
  79. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  80. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +489 -0
  81. data/lib/active_record/connection_adapters/postgresql_adapter.rb +672 -752
  82. data/lib/active_record/connection_adapters/schema_cache.rb +129 -0
  83. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +588 -17
  84. data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
  85. data/lib/active_record/connection_handling.rb +98 -0
  86. data/lib/active_record/core.rb +463 -0
  87. data/lib/active_record/counter_cache.rb +108 -101
  88. data/lib/active_record/dynamic_matchers.rb +131 -0
  89. data/lib/active_record/errors.rb +54 -13
  90. data/lib/active_record/explain.rb +38 -0
  91. data/lib/active_record/explain_registry.rb +30 -0
  92. data/lib/active_record/explain_subscriber.rb +29 -0
  93. data/lib/active_record/fixture_set/file.rb +55 -0
  94. data/lib/active_record/fixtures.rb +703 -785
  95. data/lib/active_record/inheritance.rb +200 -0
  96. data/lib/active_record/integration.rb +60 -0
  97. data/lib/active_record/locale/en.yml +8 -1
  98. data/lib/active_record/locking/optimistic.rb +69 -60
  99. data/lib/active_record/locking/pessimistic.rb +34 -12
  100. data/lib/active_record/log_subscriber.rb +40 -6
  101. data/lib/active_record/migration/command_recorder.rb +164 -0
  102. data/lib/active_record/migration/join_table.rb +15 -0
  103. data/lib/active_record/migration.rb +614 -216
  104. data/lib/active_record/model_schema.rb +345 -0
  105. data/lib/active_record/nested_attributes.rb +248 -119
  106. data/lib/active_record/null_relation.rb +65 -0
  107. data/lib/active_record/persistence.rb +275 -57
  108. data/lib/active_record/query_cache.rb +29 -9
  109. data/lib/active_record/querying.rb +62 -0
  110. data/lib/active_record/railtie.rb +135 -21
  111. data/lib/active_record/railties/console_sandbox.rb +5 -0
  112. data/lib/active_record/railties/controller_runtime.rb +17 -5
  113. data/lib/active_record/railties/databases.rake +249 -359
  114. data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
  115. data/lib/active_record/readonly_attributes.rb +30 -0
  116. data/lib/active_record/reflection.rb +283 -103
  117. data/lib/active_record/relation/batches.rb +38 -34
  118. data/lib/active_record/relation/calculations.rb +252 -139
  119. data/lib/active_record/relation/delegation.rb +125 -0
  120. data/lib/active_record/relation/finder_methods.rb +182 -188
  121. data/lib/active_record/relation/merger.rb +161 -0
  122. data/lib/active_record/relation/predicate_builder.rb +86 -21
  123. data/lib/active_record/relation/query_methods.rb +917 -134
  124. data/lib/active_record/relation/spawn_methods.rb +53 -92
  125. data/lib/active_record/relation.rb +405 -143
  126. data/lib/active_record/result.rb +67 -0
  127. data/lib/active_record/runtime_registry.rb +17 -0
  128. data/lib/active_record/sanitization.rb +168 -0
  129. data/lib/active_record/schema.rb +20 -14
  130. data/lib/active_record/schema_dumper.rb +55 -46
  131. data/lib/active_record/schema_migration.rb +39 -0
  132. data/lib/active_record/scoping/default.rb +146 -0
  133. data/lib/active_record/scoping/named.rb +175 -0
  134. data/lib/active_record/scoping.rb +82 -0
  135. data/lib/active_record/serialization.rb +8 -46
  136. data/lib/active_record/serializers/xml_serializer.rb +21 -68
  137. data/lib/active_record/statement_cache.rb +26 -0
  138. data/lib/active_record/store.rb +156 -0
  139. data/lib/active_record/tasks/database_tasks.rb +203 -0
  140. data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
  141. data/lib/active_record/tasks/mysql_database_tasks.rb +143 -0
  142. data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
  143. data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
  144. data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
  145. data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
  146. data/lib/active_record/test_case.rb +57 -28
  147. data/lib/active_record/timestamp.rb +49 -18
  148. data/lib/active_record/transactions.rb +106 -63
  149. data/lib/active_record/translation.rb +22 -0
  150. data/lib/active_record/validations/associated.rb +25 -24
  151. data/lib/active_record/validations/presence.rb +65 -0
  152. data/lib/active_record/validations/uniqueness.rb +123 -83
  153. data/lib/active_record/validations.rb +29 -29
  154. data/lib/active_record/version.rb +7 -5
  155. data/lib/active_record.rb +83 -34
  156. data/lib/rails/generators/active_record/migration/migration_generator.rb +46 -9
  157. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
  158. data/lib/rails/generators/active_record/migration/templates/migration.rb +30 -8
  159. data/lib/rails/generators/active_record/model/model_generator.rb +15 -5
  160. data/lib/rails/generators/active_record/model/templates/model.rb +7 -2
  161. data/lib/rails/generators/active_record/model/templates/module.rb +3 -1
  162. data/lib/rails/generators/active_record.rb +4 -8
  163. metadata +163 -121
  164. data/CHANGELOG +0 -6023
  165. data/examples/associations.png +0 -0
  166. data/lib/active_record/association_preload.rb +0 -403
  167. data/lib/active_record/associations/association_collection.rb +0 -562
  168. data/lib/active_record/associations/association_proxy.rb +0 -295
  169. data/lib/active_record/associations/through_association_scope.rb +0 -154
  170. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -113
  171. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -401
  172. data/lib/active_record/dynamic_finder_match.rb +0 -53
  173. data/lib/active_record/dynamic_scope_match.rb +0 -32
  174. data/lib/active_record/named_scope.rb +0 -138
  175. data/lib/active_record/observer.rb +0 -140
  176. data/lib/active_record/session_store.rb +0 -340
  177. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -16
  178. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  179. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -2
  180. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -24
  181. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -16
@@ -0,0 +1,161 @@
1
+ require 'active_support/core_ext/hash/keys'
2
+ require "set"
3
+
4
+ module ActiveRecord
5
+ class Relation
6
+ class HashMerger # :nodoc:
7
+ attr_reader :relation, :hash
8
+
9
+ def initialize(relation, hash)
10
+ hash.assert_valid_keys(*Relation::VALUE_METHODS)
11
+
12
+ @relation = relation
13
+ @hash = hash
14
+ end
15
+
16
+ def merge
17
+ Merger.new(relation, other).merge
18
+ end
19
+
20
+ # Applying values to a relation has some side effects. E.g.
21
+ # interpolation might take place for where values. So we should
22
+ # build a relation to merge in rather than directly merging
23
+ # the values.
24
+ def other
25
+ other = Relation.new(relation.klass, relation.table)
26
+ hash.each { |k, v|
27
+ if k == :joins
28
+ if Hash === v
29
+ other.joins!(v)
30
+ else
31
+ other.joins!(*v)
32
+ end
33
+ else
34
+ other.send("#{k}!", v)
35
+ end
36
+ }
37
+ other
38
+ end
39
+ end
40
+
41
+ class Merger # :nodoc:
42
+ attr_reader :relation, :values, :other
43
+
44
+ def initialize(relation, other)
45
+ if other.default_scoped? && other.klass != relation.klass
46
+ other = other.with_default_scope
47
+ end
48
+
49
+ @relation = relation
50
+ @values = other.values
51
+ @other = other
52
+ end
53
+
54
+ NORMAL_VALUES = Relation::SINGLE_VALUE_METHODS +
55
+ Relation::MULTI_VALUE_METHODS -
56
+ [:joins, :where, :order, :bind, :reverse_order, :lock, :create_with, :reordering, :from] # :nodoc:
57
+
58
+ def normal_values
59
+ NORMAL_VALUES
60
+ end
61
+
62
+ def merge
63
+ normal_values.each do |name|
64
+ value = values[name]
65
+ relation.send("#{name}!", *value) unless value.blank?
66
+ end
67
+
68
+ merge_multi_values
69
+ merge_single_values
70
+ merge_joins
71
+
72
+ relation
73
+ end
74
+
75
+ private
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
+
103
+ def merge_multi_values
104
+ relation.where_values = merged_wheres
105
+ relation.bind_values = merged_binds
106
+
107
+ if values[:reordering]
108
+ # override any order specified in the original relation
109
+ relation.reorder! values[:order]
110
+ elsif values[:order]
111
+ # merge in order_values from r
112
+ relation.order! values[:order]
113
+ end
114
+
115
+ relation.extend(*values[:extending]) unless values[:extending].blank?
116
+ end
117
+
118
+ def merge_single_values
119
+ relation.from_value = values[:from] unless relation.from_value
120
+ relation.lock_value = values[:lock] unless relation.lock_value
121
+ relation.reverse_order_value = values[:reverse_order]
122
+
123
+ unless values[:create_with].blank?
124
+ relation.create_with_value = (relation.create_with_value || {}).merge(values[:create_with])
125
+ end
126
+ end
127
+
128
+ def merged_binds
129
+ if values[:bind]
130
+ (relation.bind_values + values[:bind]).uniq(&:first)
131
+ else
132
+ relation.bind_values
133
+ end
134
+ end
135
+
136
+ def merged_wheres
137
+ values[:where] ||= []
138
+
139
+ if values[:where].empty? || relation.where_values.empty?
140
+ relation.where_values + values[:where]
141
+ else
142
+ # Remove equalities from the existing relation with a LHS which is
143
+ # present in the relation being merged in.
144
+
145
+ seen = Set.new
146
+ values[:where].each { |w|
147
+ if w.respond_to?(:operator) && w.operator == :==
148
+ seen << w.left
149
+ end
150
+ }
151
+
152
+ relation.where_values.reject { |w|
153
+ w.respond_to?(:operator) &&
154
+ w.operator == :== &&
155
+ seen.include?(w.left)
156
+ } + values[:where]
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
@@ -1,41 +1,106 @@
1
1
  module ActiveRecord
2
- class PredicateBuilder
2
+ class PredicateBuilder # :nodoc:
3
+ def self.build_from_hash(klass, attributes, default_table)
4
+ queries = []
3
5
 
4
- def initialize(engine)
5
- @engine = engine
6
- end
7
-
8
- def build_from_hash(attributes, default_table)
9
- predicates = attributes.map do |column, value|
6
+ attributes.each do |column, value|
10
7
  table = default_table
11
8
 
12
9
  if value.is_a?(Hash)
13
- table = Arel::Table.new(column, :engine => @engine)
14
- build_from_hash(value, table)
10
+ if value.empty?
11
+ queries << '1=0'
12
+ else
13
+ table = Arel::Table.new(column, default_table.engine)
14
+ association = klass.reflect_on_association(column.to_sym)
15
+
16
+ value.each do |k, v|
17
+ queries.concat expand(association && association.klass, table, k, v)
18
+ end
19
+ end
15
20
  else
16
21
  column = column.to_s
17
22
 
18
23
  if column.include?('.')
19
24
  table_name, column = column.split('.', 2)
20
- table = Arel::Table.new(table_name, :engine => @engine)
25
+ table = Arel::Table.new(table_name, default_table.engine)
21
26
  end
22
27
 
23
- attribute = table[column] || Arel::Attribute.new(table, column)
28
+ queries.concat expand(klass, table, column, value)
29
+ end
30
+ end
31
+
32
+ queries
33
+ end
24
34
 
25
- case value
26
- when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::Relation
27
- values = value.to_a
28
- attribute.in(values)
29
- when Range, Arel::Relation
30
- attribute.in(value)
31
- else
32
- attribute.eq(value)
33
- end
35
+ def self.expand(klass, table, column, value)
36
+ queries = []
37
+
38
+ # Find the foreign key when using queries such as:
39
+ # Post.where(author: author)
40
+ #
41
+ # For polymorphic relationships, find the foreign key and type:
42
+ # PriceEstimate.where(estimate_of: treasure)
43
+ if klass && value.class < Base && reflection = klass.reflect_on_association(column.to_sym)
44
+ if reflection.polymorphic?
45
+ queries << build(table[reflection.foreign_type], value.class.base_class)
34
46
  end
47
+
48
+ column = reflection.foreign_key
35
49
  end
36
50
 
37
- predicates.flatten
51
+ queries << build(table[column], value)
52
+ queries
38
53
  end
39
54
 
55
+ def self.references(attributes)
56
+ attributes.map do |key, value|
57
+ if value.is_a?(Hash)
58
+ key
59
+ else
60
+ key = key.to_s
61
+ key.split('.').first if key.include?('.')
62
+ end
63
+ end.compact
64
+ end
65
+
66
+ private
67
+ def self.build(attribute, value)
68
+ case value
69
+ when Array
70
+ values = value.to_a.map {|x| x.is_a?(Base) ? x.id : x}
71
+ ranges, values = values.partition {|v| v.is_a?(Range)}
72
+
73
+ values_predicate = if values.include?(nil)
74
+ values = values.compact
75
+
76
+ case values.length
77
+ when 0
78
+ attribute.eq(nil)
79
+ when 1
80
+ attribute.eq(values.first).or(attribute.eq(nil))
81
+ else
82
+ attribute.in(values).or(attribute.eq(nil))
83
+ end
84
+ else
85
+ attribute.in(values)
86
+ end
87
+
88
+ array_predicates = ranges.map { |range| attribute.in(range) }
89
+ array_predicates << values_predicate
90
+ array_predicates.inject { |composite, predicate| composite.or(predicate) }
91
+ when ActiveRecord::Relation
92
+ value = value.select(value.klass.arel_table[value.klass.primary_key]) if value.select_values.empty?
93
+ attribute.in(value.arel.ast)
94
+ when Range
95
+ attribute.in(value)
96
+ when ActiveRecord::Base
97
+ attribute.eq(value.id)
98
+ when Class
99
+ # FIXME: I think we need to deprecate this behavior
100
+ attribute.eq(value.name)
101
+ else
102
+ attribute.eq(value)
103
+ end
104
+ end
40
105
  end
41
106
  end