activerecord 3.2.19 → 5.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 (264) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1715 -604
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +40 -45
  5. data/examples/performance.rb +33 -22
  6. data/examples/simple.rb +3 -4
  7. data/lib/active_record/aggregations.rb +76 -51
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +54 -40
  10. data/lib/active_record/associations/association.rb +76 -56
  11. data/lib/active_record/associations/association_scope.rb +125 -93
  12. data/lib/active_record/associations/belongs_to_association.rb +57 -28
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  14. data/lib/active_record/associations/builder/association.rb +120 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +115 -62
  16. data/lib/active_record/associations/builder/collection_association.rb +61 -53
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +117 -43
  18. data/lib/active_record/associations/builder/has_many.rb +9 -65
  19. data/lib/active_record/associations/builder/has_one.rb +18 -52
  20. data/lib/active_record/associations/builder/singular_association.rb +18 -19
  21. data/lib/active_record/associations/collection_association.rb +268 -186
  22. data/lib/active_record/associations/collection_proxy.rb +1003 -63
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +81 -41
  25. data/lib/active_record/associations/has_many_through_association.rb +76 -55
  26. data/lib/active_record/associations/has_one_association.rb +51 -21
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +83 -108
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +239 -155
  32. data/lib/active_record/associations/preloader/association.rb +97 -62
  33. data/lib/active_record/associations/preloader/collection_association.rb +2 -8
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +75 -33
  38. data/lib/active_record/associations/preloader.rb +111 -79
  39. data/lib/active_record/associations/singular_association.rb +35 -13
  40. data/lib/active_record/associations/through_association.rb +41 -19
  41. data/lib/active_record/associations.rb +727 -501
  42. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  43. data/lib/active_record/attribute.rb +213 -0
  44. data/lib/active_record/attribute_assignment.rb +32 -162
  45. data/lib/active_record/attribute_decorators.rb +67 -0
  46. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  47. data/lib/active_record/attribute_methods/dirty.rb +101 -61
  48. data/lib/active_record/attribute_methods/primary_key.rb +50 -36
  49. data/lib/active_record/attribute_methods/query.rb +7 -6
  50. data/lib/active_record/attribute_methods/read.rb +56 -117
  51. data/lib/active_record/attribute_methods/serialization.rb +43 -96
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +93 -42
  53. data/lib/active_record/attribute_methods/write.rb +34 -45
  54. data/lib/active_record/attribute_methods.rb +333 -144
  55. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  56. data/lib/active_record/attribute_set/builder.rb +108 -0
  57. data/lib/active_record/attribute_set.rb +108 -0
  58. data/lib/active_record/attributes.rb +265 -0
  59. data/lib/active_record/autosave_association.rb +285 -223
  60. data/lib/active_record/base.rb +95 -490
  61. data/lib/active_record/callbacks.rb +95 -61
  62. data/lib/active_record/coders/json.rb +13 -0
  63. data/lib/active_record/coders/yaml_column.rb +28 -19
  64. data/lib/active_record/collection_cache_key.rb +40 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +724 -277
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -192
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -26
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +140 -57
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +147 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +419 -276
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +105 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +963 -276
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +232 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +397 -106
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +643 -342
  78. data/lib/active_record/connection_adapters/column.rb +30 -259
  79. data/lib/active_record/connection_adapters/connection_specification.rb +263 -0
  80. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  81. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  82. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  83. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  84. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  86. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  87. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  88. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  89. data/lib/active_record/connection_adapters/mysql2_adapter.rb +47 -196
  90. data/lib/active_record/connection_adapters/postgresql/column.rb +15 -0
  91. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +170 -0
  92. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +70 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +48 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +21 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +10 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +39 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +93 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  112. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  113. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  114. data/lib/active_record/connection_adapters/postgresql/oid.rb +31 -0
  115. data/lib/active_record/connection_adapters/postgresql/quoting.rb +116 -0
  116. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +49 -0
  117. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +180 -0
  118. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  119. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +682 -0
  120. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  121. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  122. data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -1039
  123. data/lib/active_record/connection_adapters/schema_cache.rb +74 -36
  124. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  125. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +538 -24
  129. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  130. data/lib/active_record/connection_handling.rb +155 -0
  131. data/lib/active_record/core.rb +561 -0
  132. data/lib/active_record/counter_cache.rb +146 -105
  133. data/lib/active_record/dynamic_matchers.rb +101 -64
  134. data/lib/active_record/enum.rb +234 -0
  135. data/lib/active_record/errors.rb +153 -56
  136. data/lib/active_record/explain.rb +15 -63
  137. data/lib/active_record/explain_registry.rb +30 -0
  138. data/lib/active_record/explain_subscriber.rb +10 -6
  139. data/lib/active_record/fixture_set/file.rb +77 -0
  140. data/lib/active_record/fixtures.rb +355 -232
  141. data/lib/active_record/gem_version.rb +15 -0
  142. data/lib/active_record/inheritance.rb +144 -79
  143. data/lib/active_record/integration.rb +66 -13
  144. data/lib/active_record/internal_metadata.rb +56 -0
  145. data/lib/active_record/legacy_yaml_adapter.rb +46 -0
  146. data/lib/active_record/locale/en.yml +9 -1
  147. data/lib/active_record/locking/optimistic.rb +77 -56
  148. data/lib/active_record/locking/pessimistic.rb +6 -6
  149. data/lib/active_record/log_subscriber.rb +53 -28
  150. data/lib/active_record/migration/command_recorder.rb +166 -33
  151. data/lib/active_record/migration/compatibility.rb +126 -0
  152. data/lib/active_record/migration/join_table.rb +15 -0
  153. data/lib/active_record/migration.rb +792 -264
  154. data/lib/active_record/model_schema.rb +192 -130
  155. data/lib/active_record/nested_attributes.rb +238 -145
  156. data/lib/active_record/no_touching.rb +52 -0
  157. data/lib/active_record/null_relation.rb +89 -0
  158. data/lib/active_record/persistence.rb +357 -157
  159. data/lib/active_record/query_cache.rb +22 -43
  160. data/lib/active_record/querying.rb +34 -23
  161. data/lib/active_record/railtie.rb +88 -48
  162. data/lib/active_record/railties/console_sandbox.rb +3 -4
  163. data/lib/active_record/railties/controller_runtime.rb +5 -4
  164. data/lib/active_record/railties/databases.rake +170 -422
  165. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  166. data/lib/active_record/readonly_attributes.rb +2 -5
  167. data/lib/active_record/reflection.rb +715 -189
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  169. data/lib/active_record/relation/batches.rb +203 -50
  170. data/lib/active_record/relation/calculations.rb +203 -194
  171. data/lib/active_record/relation/delegation.rb +103 -25
  172. data/lib/active_record/relation/finder_methods.rb +457 -261
  173. data/lib/active_record/relation/from_clause.rb +32 -0
  174. data/lib/active_record/relation/merger.rb +167 -0
  175. data/lib/active_record/relation/predicate_builder/array_handler.rb +43 -0
  176. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  177. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  179. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  180. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  181. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  182. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  183. data/lib/active_record/relation/predicate_builder.rb +153 -48
  184. data/lib/active_record/relation/query_attribute.rb +19 -0
  185. data/lib/active_record/relation/query_methods.rb +1019 -194
  186. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  187. data/lib/active_record/relation/spawn_methods.rb +46 -150
  188. data/lib/active_record/relation/where_clause.rb +174 -0
  189. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  190. data/lib/active_record/relation.rb +450 -245
  191. data/lib/active_record/result.rb +104 -12
  192. data/lib/active_record/runtime_registry.rb +22 -0
  193. data/lib/active_record/sanitization.rb +120 -94
  194. data/lib/active_record/schema.rb +28 -18
  195. data/lib/active_record/schema_dumper.rb +141 -74
  196. data/lib/active_record/schema_migration.rb +50 -0
  197. data/lib/active_record/scoping/default.rb +64 -57
  198. data/lib/active_record/scoping/named.rb +93 -108
  199. data/lib/active_record/scoping.rb +73 -121
  200. data/lib/active_record/secure_token.rb +38 -0
  201. data/lib/active_record/serialization.rb +7 -5
  202. data/lib/active_record/statement_cache.rb +113 -0
  203. data/lib/active_record/store.rb +173 -15
  204. data/lib/active_record/suppressor.rb +58 -0
  205. data/lib/active_record/table_metadata.rb +68 -0
  206. data/lib/active_record/tasks/database_tasks.rb +313 -0
  207. data/lib/active_record/tasks/mysql_database_tasks.rb +151 -0
  208. data/lib/active_record/tasks/postgresql_database_tasks.rb +110 -0
  209. data/lib/active_record/tasks/sqlite_database_tasks.rb +59 -0
  210. data/lib/active_record/timestamp.rb +42 -24
  211. data/lib/active_record/touch_later.rb +58 -0
  212. data/lib/active_record/transactions.rb +233 -105
  213. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  214. data/lib/active_record/type/date.rb +7 -0
  215. data/lib/active_record/type/date_time.rb +7 -0
  216. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  217. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  218. data/lib/active_record/type/internal/timezone.rb +15 -0
  219. data/lib/active_record/type/serialized.rb +63 -0
  220. data/lib/active_record/type/time.rb +20 -0
  221. data/lib/active_record/type/type_map.rb +64 -0
  222. data/lib/active_record/type.rb +72 -0
  223. data/lib/active_record/type_caster/connection.rb +29 -0
  224. data/lib/active_record/type_caster/map.rb +19 -0
  225. data/lib/active_record/type_caster.rb +7 -0
  226. data/lib/active_record/validations/absence.rb +23 -0
  227. data/lib/active_record/validations/associated.rb +33 -18
  228. data/lib/active_record/validations/length.rb +24 -0
  229. data/lib/active_record/validations/presence.rb +66 -0
  230. data/lib/active_record/validations/uniqueness.rb +128 -68
  231. data/lib/active_record/validations.rb +48 -40
  232. data/lib/active_record/version.rb +5 -7
  233. data/lib/active_record.rb +71 -47
  234. data/lib/rails/generators/active_record/migration/migration_generator.rb +56 -8
  235. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +24 -0
  236. data/lib/rails/generators/active_record/migration/templates/migration.rb +28 -16
  237. data/lib/rails/generators/active_record/migration.rb +18 -8
  238. data/lib/rails/generators/active_record/model/model_generator.rb +38 -16
  239. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  240. data/lib/rails/generators/active_record/model/templates/model.rb +7 -6
  241. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  242. data/lib/rails/generators/active_record.rb +3 -11
  243. metadata +188 -134
  244. data/examples/associations.png +0 -0
  245. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  246. data/lib/active_record/associations/join_helper.rb +0 -55
  247. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  248. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  249. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  250. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
  251. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  252. data/lib/active_record/dynamic_finder_match.rb +0 -68
  253. data/lib/active_record/dynamic_scope_match.rb +0 -23
  254. data/lib/active_record/fixtures/file.rb +0 -65
  255. data/lib/active_record/identity_map.rb +0 -162
  256. data/lib/active_record/observer.rb +0 -121
  257. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  258. data/lib/active_record/session_store.rb +0 -360
  259. data/lib/active_record/test_case.rb +0 -73
  260. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  261. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  262. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  263. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  264. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -0,0 +1,32 @@
1
+ module ActiveRecord
2
+ class Relation
3
+ class FromClause # :nodoc:
4
+ attr_reader :value, :name
5
+
6
+ def initialize(value, name)
7
+ @value = value
8
+ @name = name
9
+ end
10
+
11
+ def binds
12
+ if value.is_a?(Relation)
13
+ value.bound_attributes
14
+ else
15
+ []
16
+ end
17
+ end
18
+
19
+ def merge(other)
20
+ self
21
+ end
22
+
23
+ def empty?
24
+ value.nil?
25
+ end
26
+
27
+ def self.empty
28
+ @empty ||= new(nil, nil)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,167 @@
1
+ require 'active_support/core_ext/hash/keys'
2
+
3
+ module ActiveRecord
4
+ class Relation
5
+ class HashMerger # :nodoc:
6
+ attr_reader :relation, :hash
7
+
8
+ def initialize(relation, hash)
9
+ hash.assert_valid_keys(*Relation::VALUE_METHODS)
10
+
11
+ @relation = relation
12
+ @hash = hash
13
+ end
14
+
15
+ def merge #:nodoc:
16
+ Merger.new(relation, other).merge
17
+ end
18
+
19
+ # Applying values to a relation has some side effects. E.g.
20
+ # interpolation might take place for where values. So we should
21
+ # build a relation to merge in rather than directly merging
22
+ # the values.
23
+ def other
24
+ other = Relation.create(relation.klass, relation.table, relation.predicate_builder)
25
+ hash.each { |k, v|
26
+ if k == :joins
27
+ if Hash === v
28
+ other.joins!(v)
29
+ else
30
+ other.joins!(*v)
31
+ end
32
+ elsif k == :select
33
+ other._select!(v)
34
+ else
35
+ other.send("#{k}!", v)
36
+ end
37
+ }
38
+ other
39
+ end
40
+ end
41
+
42
+ class Merger # :nodoc:
43
+ attr_reader :relation, :values, :other
44
+
45
+ def initialize(relation, other)
46
+ @relation = relation
47
+ @values = other.values
48
+ @other = other
49
+ end
50
+
51
+ NORMAL_VALUES = Relation::VALUE_METHODS -
52
+ Relation::CLAUSE_METHODS -
53
+ [:includes, :preload, :joins, :order, :reverse_order, :lock, :create_with, :reordering] # :nodoc:
54
+
55
+ def normal_values
56
+ NORMAL_VALUES
57
+ end
58
+
59
+ def merge
60
+ normal_values.each do |name|
61
+ value = values[name]
62
+ # The unless clause is here mostly for performance reasons (since the `send` call might be moderately
63
+ # expensive), most of the time the value is going to be `nil` or `.blank?`, the only catch is that
64
+ # `false.blank?` returns `true`, so there needs to be an extra check so that explicit `false` values
65
+ # don't fall through the cracks.
66
+ unless value.nil? || (value.blank? && false != value)
67
+ if name == :select
68
+ relation._select!(*value)
69
+ else
70
+ relation.send("#{name}!", *value)
71
+ end
72
+ end
73
+ end
74
+
75
+ merge_multi_values
76
+ merge_single_values
77
+ merge_clauses
78
+ merge_preloads
79
+ merge_joins
80
+
81
+ relation
82
+ end
83
+
84
+ private
85
+
86
+ def merge_preloads
87
+ return if other.preload_values.empty? && other.includes_values.empty?
88
+
89
+ if other.klass == relation.klass
90
+ relation.preload!(*other.preload_values) unless other.preload_values.empty?
91
+ relation.includes!(other.includes_values) unless other.includes_values.empty?
92
+ else
93
+ reflection = relation.klass.reflect_on_all_associations.find do |r|
94
+ r.class_name == other.klass.name
95
+ end || return
96
+
97
+ unless other.preload_values.empty?
98
+ relation.preload! reflection.name => other.preload_values
99
+ end
100
+
101
+ unless other.includes_values.empty?
102
+ relation.includes! reflection.name => other.includes_values
103
+ end
104
+ end
105
+ end
106
+
107
+ def merge_joins
108
+ return if other.joins_values.blank?
109
+
110
+ if other.klass == relation.klass
111
+ relation.joins!(*other.joins_values)
112
+ else
113
+ joins_dependency, rest = other.joins_values.partition do |join|
114
+ case join
115
+ when Hash, Symbol, Array
116
+ true
117
+ else
118
+ false
119
+ end
120
+ end
121
+
122
+ join_dependency = ActiveRecord::Associations::JoinDependency.new(other.klass,
123
+ joins_dependency,
124
+ [])
125
+ relation.joins! rest
126
+
127
+ @relation = relation.joins join_dependency
128
+ end
129
+ end
130
+
131
+ def merge_multi_values
132
+ if other.reordering_value
133
+ # override any order specified in the original relation
134
+ relation.reorder! other.order_values
135
+ elsif other.order_values
136
+ # merge in order_values from relation
137
+ relation.order! other.order_values
138
+ end
139
+
140
+ relation.extend(*other.extending_values) unless other.extending_values.blank?
141
+ end
142
+
143
+ def merge_single_values
144
+ if relation.from_clause.empty?
145
+ relation.from_clause = other.from_clause
146
+ end
147
+ relation.lock_value ||= other.lock_value
148
+
149
+ unless other.create_with_value.blank?
150
+ relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value)
151
+ end
152
+ end
153
+
154
+ CLAUSE_METHOD_NAMES = CLAUSE_METHODS.map do |name|
155
+ ["#{name}_clause", "#{name}_clause="]
156
+ end
157
+
158
+ def merge_clauses
159
+ CLAUSE_METHOD_NAMES.each do |(reader, writer)|
160
+ clause = relation.send(reader)
161
+ other_clause = other.send(reader)
162
+ relation.send(writer, clause.merge(other_clause))
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,43 @@
1
+ module ActiveRecord
2
+ class PredicateBuilder
3
+ class ArrayHandler # :nodoc:
4
+ def initialize(predicate_builder)
5
+ @predicate_builder = predicate_builder
6
+ end
7
+
8
+ def call(attribute, value)
9
+ values = value.map { |x| x.is_a?(Base) ? x.id : x }
10
+ nils, values = values.partition(&:nil?)
11
+
12
+ return attribute.in([]) if values.empty? && nils.empty?
13
+
14
+ ranges, values = values.partition { |v| v.is_a?(Range) }
15
+
16
+ values_predicate =
17
+ case values.length
18
+ when 0 then NullPredicate
19
+ when 1 then predicate_builder.build(attribute, values.first)
20
+ else attribute.in(values)
21
+ end
22
+
23
+ unless nils.empty?
24
+ values_predicate = values_predicate.or(predicate_builder.build(attribute, nil))
25
+ end
26
+
27
+ array_predicates = ranges.map { |range| predicate_builder.build(attribute, range) }
28
+ array_predicates.unshift(values_predicate)
29
+ array_predicates.inject { |composite, predicate| composite.or(predicate) }
30
+ end
31
+
32
+ protected
33
+
34
+ attr_reader :predicate_builder
35
+
36
+ module NullPredicate # :nodoc:
37
+ def self.or(other)
38
+ other
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,88 @@
1
+ module ActiveRecord
2
+ class PredicateBuilder
3
+ class AssociationQueryHandler # :nodoc:
4
+ def self.value_for(table, column, value)
5
+ klass = if table.associated_table(column).polymorphic_association? && ::Array === value && value.first.is_a?(Base)
6
+ PolymorphicArrayValue
7
+ else
8
+ AssociationQueryValue
9
+ end
10
+
11
+ klass.new(table.associated_table(column), value)
12
+ end
13
+
14
+ def initialize(predicate_builder)
15
+ @predicate_builder = predicate_builder
16
+ end
17
+
18
+ def call(attribute, value)
19
+ queries = {}
20
+
21
+ table = value.associated_table
22
+ if value.base_class
23
+ queries[table.association_foreign_type.to_s] = value.base_class.name
24
+ end
25
+
26
+ queries[table.association_foreign_key.to_s] = value.ids
27
+ predicate_builder.build_from_hash(queries)
28
+ end
29
+
30
+ protected
31
+
32
+ attr_reader :predicate_builder
33
+ end
34
+
35
+ class AssociationQueryValue # :nodoc:
36
+ attr_reader :associated_table, :value
37
+
38
+ def initialize(associated_table, value)
39
+ @associated_table = associated_table
40
+ @value = value
41
+ end
42
+
43
+ def ids
44
+ case value
45
+ when Relation
46
+ value.select(primary_key)
47
+ when Array
48
+ value.map { |v| convert_to_id(v) }
49
+ else
50
+ convert_to_id(value)
51
+ end
52
+ end
53
+
54
+ def base_class
55
+ if associated_table.polymorphic_association?
56
+ @base_class ||= polymorphic_base_class_from_value
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def primary_key
63
+ associated_table.association_primary_key(base_class)
64
+ end
65
+
66
+ def polymorphic_base_class_from_value
67
+ case value
68
+ when Relation
69
+ value.klass.base_class
70
+ when Array
71
+ val = value.compact.first
72
+ val.class.base_class if val.is_a?(Base)
73
+ when Base
74
+ value.class.base_class
75
+ end
76
+ end
77
+
78
+ def convert_to_id(value)
79
+ case value
80
+ when Base
81
+ value._read_attribute(primary_key)
82
+ else
83
+ value
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,17 @@
1
+ module ActiveRecord
2
+ class PredicateBuilder
3
+ class BaseHandler # :nodoc:
4
+ def initialize(predicate_builder)
5
+ @predicate_builder = predicate_builder
6
+ end
7
+
8
+ def call(attribute, value)
9
+ predicate_builder.build(attribute, value.id)
10
+ end
11
+
12
+ protected
13
+
14
+ attr_reader :predicate_builder
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module ActiveRecord
2
+ class PredicateBuilder
3
+ class BasicObjectHandler # :nodoc:
4
+ def initialize(predicate_builder)
5
+ @predicate_builder = predicate_builder
6
+ end
7
+
8
+ def call(attribute, value)
9
+ attribute.eq(value)
10
+ end
11
+
12
+ protected
13
+
14
+ attr_reader :predicate_builder
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,27 @@
1
+ module ActiveRecord
2
+ class PredicateBuilder
3
+ class ClassHandler # :nodoc:
4
+ def initialize(predicate_builder)
5
+ @predicate_builder = predicate_builder
6
+ end
7
+
8
+ def call(attribute, value)
9
+ print_deprecation_warning
10
+ predicate_builder.build(attribute, value.name)
11
+ end
12
+
13
+ protected
14
+
15
+ attr_reader :predicate_builder
16
+
17
+ private
18
+
19
+ def print_deprecation_warning
20
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
21
+ Passing a class as a value in an Active Record query is deprecated and
22
+ will be removed. Pass a string instead.
23
+ MSG
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,57 @@
1
+ module ActiveRecord
2
+ class PredicateBuilder
3
+ class PolymorphicArrayHandler # :nodoc:
4
+ def initialize(predicate_builder)
5
+ @predicate_builder = predicate_builder
6
+ end
7
+
8
+ def call(attribute, value)
9
+ table = value.associated_table
10
+ queries = value.type_to_ids_mapping.map do |type, ids|
11
+ { table.association_foreign_type.to_s => type, table.association_foreign_key.to_s => ids }
12
+ end
13
+
14
+ predicates = queries.map { |query| predicate_builder.build_from_hash(query) }
15
+
16
+ if predicates.size > 1
17
+ type_and_ids_predicates = predicates.map { |type_predicate, id_predicate| Arel::Nodes::Grouping.new(type_predicate.and(id_predicate)) }
18
+ type_and_ids_predicates.inject(&:or)
19
+ else
20
+ predicates.first
21
+ end
22
+ end
23
+
24
+ protected
25
+
26
+ attr_reader :predicate_builder
27
+ end
28
+
29
+ class PolymorphicArrayValue # :nodoc:
30
+ attr_reader :associated_table, :values
31
+
32
+ def initialize(associated_table, values)
33
+ @associated_table = associated_table
34
+ @values = values
35
+ end
36
+
37
+ def type_to_ids_mapping
38
+ default_hash = Hash.new { |hsh, key| hsh[key] = [] }
39
+ values.each_with_object(default_hash) { |value, hash| hash[base_class(value).name] << convert_to_id(value) }
40
+ end
41
+
42
+ private
43
+
44
+ def primary_key(value)
45
+ associated_table.association_primary_key(base_class(value))
46
+ end
47
+
48
+ def base_class(value)
49
+ value.class.base_class
50
+ end
51
+
52
+ def convert_to_id(value)
53
+ value._read_attribute(primary_key(value))
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,33 @@
1
+ module ActiveRecord
2
+ class PredicateBuilder
3
+ class RangeHandler # :nodoc:
4
+ RangeWithBinds = Struct.new(:begin, :end, :exclude_end?)
5
+
6
+ def initialize(predicate_builder)
7
+ @predicate_builder = predicate_builder
8
+ end
9
+
10
+ def call(attribute, value)
11
+ if value.begin.respond_to?(:infinite?) && value.begin.infinite?
12
+ if value.end.respond_to?(:infinite?) && value.end.infinite?
13
+ attribute.not_in([])
14
+ elsif value.exclude_end?
15
+ attribute.lt(value.end)
16
+ else
17
+ attribute.lteq(value.end)
18
+ end
19
+ elsif value.end.respond_to?(:infinite?) && value.end.infinite?
20
+ attribute.gteq(value.begin)
21
+ elsif value.exclude_end?
22
+ attribute.gteq(value.begin).and(attribute.lt(value.end))
23
+ else
24
+ attribute.between(value)
25
+ end
26
+ end
27
+
28
+ protected
29
+
30
+ attr_reader :predicate_builder
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ module ActiveRecord
2
+ class PredicateBuilder
3
+ class RelationHandler # :nodoc:
4
+ def call(attribute, value)
5
+ if value.select_values.empty?
6
+ value = value.select(value.arel_attribute(value.klass.primary_key))
7
+ end
8
+
9
+ attribute.in(value.arel)
10
+ end
11
+ end
12
+ end
13
+ end