activerecord 3.2.22.5 → 5.2.8

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 (275) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +657 -621
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +41 -46
  5. data/examples/performance.rb +55 -42
  6. data/examples/simple.rb +6 -5
  7. data/lib/active_record/aggregations.rb +264 -236
  8. data/lib/active_record/association_relation.rb +40 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -42
  10. data/lib/active_record/associations/association.rb +127 -75
  11. data/lib/active_record/associations/association_scope.rb +126 -92
  12. data/lib/active_record/associations/belongs_to_association.rb +78 -27
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +9 -4
  14. data/lib/active_record/associations/builder/association.rb +117 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +135 -60
  16. data/lib/active_record/associations/builder/collection_association.rb +61 -54
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +120 -42
  18. data/lib/active_record/associations/builder/has_many.rb +10 -64
  19. data/lib/active_record/associations/builder/has_one.rb +19 -51
  20. data/lib/active_record/associations/builder/singular_association.rb +28 -18
  21. data/lib/active_record/associations/collection_association.rb +226 -293
  22. data/lib/active_record/associations/collection_proxy.rb +1067 -69
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +83 -47
  25. data/lib/active_record/associations/has_many_through_association.rb +98 -65
  26. data/lib/active_record/associations/has_one_association.rb +57 -20
  27. data/lib/active_record/associations/has_one_through_association.rb +18 -9
  28. data/lib/active_record/associations/join_dependency/join_association.rb +48 -126
  29. data/lib/active_record/associations/join_dependency/join_base.rb +11 -12
  30. data/lib/active_record/associations/join_dependency/join_part.rb +35 -42
  31. data/lib/active_record/associations/join_dependency.rb +212 -164
  32. data/lib/active_record/associations/preloader/association.rb +95 -89
  33. data/lib/active_record/associations/preloader/through_association.rb +84 -44
  34. data/lib/active_record/associations/preloader.rb +123 -111
  35. data/lib/active_record/associations/singular_association.rb +33 -24
  36. data/lib/active_record/associations/through_association.rb +60 -26
  37. data/lib/active_record/associations.rb +1759 -1506
  38. data/lib/active_record/attribute_assignment.rb +60 -193
  39. data/lib/active_record/attribute_decorators.rb +90 -0
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +55 -8
  41. data/lib/active_record/attribute_methods/dirty.rb +113 -74
  42. data/lib/active_record/attribute_methods/primary_key.rb +106 -77
  43. data/lib/active_record/attribute_methods/query.rb +8 -5
  44. data/lib/active_record/attribute_methods/read.rb +63 -114
  45. data/lib/active_record/attribute_methods/serialization.rb +60 -90
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +69 -43
  47. data/lib/active_record/attribute_methods/write.rb +43 -45
  48. data/lib/active_record/attribute_methods.rb +366 -149
  49. data/lib/active_record/attributes.rb +266 -0
  50. data/lib/active_record/autosave_association.rb +312 -225
  51. data/lib/active_record/base.rb +114 -505
  52. data/lib/active_record/callbacks.rb +145 -67
  53. data/lib/active_record/coders/json.rb +15 -0
  54. data/lib/active_record/coders/yaml_column.rb +32 -23
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +883 -284
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +16 -2
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +350 -200
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -27
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +150 -65
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +146 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +477 -284
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +95 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1100 -310
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +283 -0
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +450 -118
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +657 -446
  69. data/lib/active_record/connection_adapters/column.rb +50 -255
  70. data/lib/active_record/connection_adapters/connection_specification.rb +287 -0
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +59 -210
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +163 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +56 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +111 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +168 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +206 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +774 -0
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +620 -1080
  117. data/lib/active_record/connection_adapters/schema_cache.rb +85 -36
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +545 -27
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +145 -0
  128. data/lib/active_record/core.rb +559 -0
  129. data/lib/active_record/counter_cache.rb +200 -105
  130. data/lib/active_record/define_callbacks.rb +22 -0
  131. data/lib/active_record/dynamic_matchers.rb +107 -69
  132. data/lib/active_record/enum.rb +244 -0
  133. data/lib/active_record/errors.rb +245 -60
  134. data/lib/active_record/explain.rb +35 -71
  135. data/lib/active_record/explain_registry.rb +32 -0
  136. data/lib/active_record/explain_subscriber.rb +18 -9
  137. data/lib/active_record/fixture_set/file.rb +82 -0
  138. data/lib/active_record/fixtures.rb +418 -275
  139. data/lib/active_record/gem_version.rb +17 -0
  140. data/lib/active_record/inheritance.rb +209 -100
  141. data/lib/active_record/integration.rb +116 -21
  142. data/lib/active_record/internal_metadata.rb +45 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  144. data/lib/active_record/locale/en.yml +9 -1
  145. data/lib/active_record/locking/optimistic.rb +107 -94
  146. data/lib/active_record/locking/pessimistic.rb +20 -8
  147. data/lib/active_record/log_subscriber.rb +99 -34
  148. data/lib/active_record/migration/command_recorder.rb +199 -64
  149. data/lib/active_record/migration/compatibility.rb +217 -0
  150. data/lib/active_record/migration/join_table.rb +17 -0
  151. data/lib/active_record/migration.rb +893 -296
  152. data/lib/active_record/model_schema.rb +328 -175
  153. data/lib/active_record/nested_attributes.rb +338 -242
  154. data/lib/active_record/no_touching.rb +58 -0
  155. data/lib/active_record/null_relation.rb +68 -0
  156. data/lib/active_record/persistence.rb +557 -170
  157. data/lib/active_record/query_cache.rb +14 -43
  158. data/lib/active_record/querying.rb +36 -24
  159. data/lib/active_record/railtie.rb +147 -52
  160. data/lib/active_record/railties/console_sandbox.rb +5 -4
  161. data/lib/active_record/railties/controller_runtime.rb +13 -6
  162. data/lib/active_record/railties/databases.rake +206 -488
  163. data/lib/active_record/readonly_attributes.rb +4 -6
  164. data/lib/active_record/reflection.rb +734 -228
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  166. data/lib/active_record/relation/batches.rb +249 -52
  167. data/lib/active_record/relation/calculations.rb +330 -284
  168. data/lib/active_record/relation/delegation.rb +135 -37
  169. data/lib/active_record/relation/finder_methods.rb +450 -287
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +193 -0
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  173. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  174. data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  179. data/lib/active_record/relation/predicate_builder.rb +132 -43
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +1037 -221
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +48 -151
  184. data/lib/active_record/relation/where_clause.rb +186 -0
  185. data/lib/active_record/relation/where_clause_factory.rb +34 -0
  186. data/lib/active_record/relation.rb +451 -359
  187. data/lib/active_record/result.rb +129 -20
  188. data/lib/active_record/runtime_registry.rb +24 -0
  189. data/lib/active_record/sanitization.rb +164 -136
  190. data/lib/active_record/schema.rb +31 -19
  191. data/lib/active_record/schema_dumper.rb +154 -107
  192. data/lib/active_record/schema_migration.rb +56 -0
  193. data/lib/active_record/scoping/default.rb +108 -98
  194. data/lib/active_record/scoping/named.rb +125 -112
  195. data/lib/active_record/scoping.rb +77 -123
  196. data/lib/active_record/secure_token.rb +40 -0
  197. data/lib/active_record/serialization.rb +10 -6
  198. data/lib/active_record/statement_cache.rb +121 -0
  199. data/lib/active_record/store.rb +175 -16
  200. data/lib/active_record/suppressor.rb +61 -0
  201. data/lib/active_record/table_metadata.rb +82 -0
  202. data/lib/active_record/tasks/database_tasks.rb +337 -0
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +143 -0
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +83 -0
  206. data/lib/active_record/timestamp.rb +80 -41
  207. data/lib/active_record/touch_later.rb +64 -0
  208. data/lib/active_record/transactions.rb +240 -119
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type/adapter_specific_registry.rb +136 -0
  211. data/lib/active_record/type/date.rb +9 -0
  212. data/lib/active_record/type/date_time.rb +9 -0
  213. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  214. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  215. data/lib/active_record/type/internal/timezone.rb +17 -0
  216. data/lib/active_record/type/json.rb +30 -0
  217. data/lib/active_record/type/serialized.rb +71 -0
  218. data/lib/active_record/type/text.rb +11 -0
  219. data/lib/active_record/type/time.rb +21 -0
  220. data/lib/active_record/type/type_map.rb +62 -0
  221. data/lib/active_record/type/unsigned_integer.rb +17 -0
  222. data/lib/active_record/type.rb +79 -0
  223. data/lib/active_record/type_caster/connection.rb +33 -0
  224. data/lib/active_record/type_caster/map.rb +23 -0
  225. data/lib/active_record/type_caster.rb +9 -0
  226. data/lib/active_record/validations/absence.rb +25 -0
  227. data/lib/active_record/validations/associated.rb +35 -18
  228. data/lib/active_record/validations/length.rb +26 -0
  229. data/lib/active_record/validations/presence.rb +68 -0
  230. data/lib/active_record/validations/uniqueness.rb +133 -75
  231. data/lib/active_record/validations.rb +53 -43
  232. data/lib/active_record/version.rb +7 -7
  233. data/lib/active_record.rb +89 -57
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  236. data/lib/rails/generators/active_record/migration/migration_generator.rb +61 -8
  237. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  238. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +46 -0
  239. data/lib/rails/generators/active_record/migration.rb +28 -8
  240. data/lib/rails/generators/active_record/model/model_generator.rb +23 -22
  241. data/lib/rails/generators/active_record/model/templates/model.rb.tt +13 -0
  242. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +1 -1
  243. data/lib/rails/generators/active_record.rb +10 -16
  244. metadata +141 -62
  245. data/examples/associations.png +0 -0
  246. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  247. data/lib/active_record/associations/join_helper.rb +0 -55
  248. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  249. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  250. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  251. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  252. data/lib/active_record/associations/preloader/has_many_through.rb +0 -15
  253. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  254. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  255. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  256. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  257. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  258. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
  259. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  260. data/lib/active_record/dynamic_finder_match.rb +0 -68
  261. data/lib/active_record/dynamic_scope_match.rb +0 -23
  262. data/lib/active_record/fixtures/file.rb +0 -65
  263. data/lib/active_record/identity_map.rb +0 -162
  264. data/lib/active_record/observer.rb +0 -121
  265. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  266. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  267. data/lib/active_record/session_store.rb +0 -360
  268. data/lib/active_record/test_case.rb +0 -73
  269. data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -34
  270. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  271. data/lib/rails/generators/active_record/model/templates/model.rb +0 -12
  272. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  273. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  274. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  275. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,158 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/associations/join_dependency/join_part"
4
+
1
5
  module ActiveRecord
2
6
  module Associations
3
7
  class JoinDependency # :nodoc:
4
8
  class JoinAssociation < JoinPart # :nodoc:
5
- include JoinHelper
6
-
7
- # The reflection of the association represented
8
- attr_reader :reflection
9
-
10
- # The JoinDependency object which this JoinAssociation exists within. This is mainly
11
- # relevant for generating aliases which do not conflict with other joins which are
12
- # part of the query.
13
- attr_reader :join_dependency
14
-
15
- # A JoinBase instance representing the active record we are joining onto.
16
- # (So in Author.has_many :posts, the Author would be that base record.)
17
- attr_reader :parent
18
-
19
- # What type of join will be generated, either Arel::InnerJoin (default) or Arel::OuterJoin
20
- attr_accessor :join_type
21
-
22
- # These implement abstract methods from the superclass
23
- attr_reader :aliased_prefix
24
-
25
- attr_reader :tables
26
-
27
- delegate :options, :through_reflection, :source_reflection, :chain, :to => :reflection
28
- delegate :table, :table_name, :to => :parent, :prefix => :parent
29
- delegate :alias_tracker, :to => :join_dependency
30
-
31
- alias :alias_suffix :parent_table_name
9
+ attr_reader :reflection, :tables
10
+ attr_accessor :table
32
11
 
33
- def initialize(reflection, join_dependency, parent = nil)
34
- reflection.check_validity!
12
+ def initialize(reflection, children)
13
+ super(reflection.klass, children)
35
14
 
36
- if reflection.options[:polymorphic]
37
- raise EagerLoadPolymorphicError.new(reflection)
38
- end
39
-
40
- super(reflection.klass)
41
-
42
- @reflection = reflection
43
- @join_dependency = join_dependency
44
- @parent = parent
45
- @join_type = Arel::InnerJoin
46
- @aliased_prefix = "t#{ join_dependency.join_parts.size }"
47
- @tables = construct_tables.reverse
48
- end
49
-
50
- def ==(other)
51
- other.class == self.class &&
52
- other.reflection == reflection &&
53
- other.parent == parent
15
+ @reflection = reflection
16
+ @tables = nil
54
17
  end
55
18
 
56
- def find_parent_in(other_join_dependency)
57
- other_join_dependency.join_parts.detect do |join_part|
58
- case parent
59
- when JoinBase
60
- parent.active_record == join_part.active_record
61
- else
62
- parent == join_part
63
- end
64
- end
19
+ def match?(other)
20
+ return true if self == other
21
+ super && reflection == other.reflection
65
22
  end
66
23
 
67
- def join_to(relation)
68
- tables = @tables.dup
69
- foreign_table = parent_table
70
- foreign_klass = parent.active_record
24
+ def join_constraints(foreign_table, foreign_klass, join_type, alias_tracker)
25
+ joins = []
71
26
 
72
27
  # The chain starts with the target table, but we want to end with it here (makes
73
28
  # more sense in this context), so we reverse
74
- chain.reverse.each_with_index do |reflection, i|
75
- table = tables.shift
76
-
77
- case reflection.source_macro
78
- when :belongs_to
79
- key = reflection.association_primary_key
80
- foreign_key = reflection.foreign_key
81
- when :has_and_belongs_to_many
82
- # Join the join table first...
83
- relation.from(join(
84
- table,
85
- table[reflection.foreign_key].
86
- eq(foreign_table[reflection.active_record_primary_key])
87
- ))
88
-
89
- foreign_table, table = table, tables.shift
90
-
91
- key = reflection.association_primary_key
92
- foreign_key = reflection.association_foreign_key
93
- else
94
- key = reflection.foreign_key
95
- foreign_key = reflection.active_record_primary_key
96
- end
29
+ reflection.chain.reverse_each.with_index(1) do |reflection, i|
30
+ table = tables[-i]
31
+ klass = reflection.klass
97
32
 
98
- constraint = build_constraint(reflection, table, key, foreign_table, foreign_key)
33
+ join_scope = reflection.join_scope(table, foreign_table, foreign_klass)
99
34
 
100
- conditions = self.conditions[i].dup
101
- conditions << { reflection.type => foreign_klass.base_class.name } if reflection.type
35
+ arel = join_scope.arel(alias_tracker.aliases)
36
+ nodes = arel.constraints.first
102
37
 
103
- unless conditions.empty?
104
- constraint = constraint.and(sanitize(conditions, table))
38
+ others, children = nodes.children.partition do |node|
39
+ !fetch_arel_attribute(node) { |attr| attr.relation.name == table.name }
105
40
  end
41
+ nodes = table.create_and(children)
106
42
 
107
- relation.from(join(table, constraint))
43
+ joins << table.create_join(table, table.create_on(nodes), join_type)
108
44
 
109
- # The current table in this iteration becomes the foreign table in the next
110
- foreign_table, foreign_klass = table, reflection.klass
111
- end
112
-
113
- relation
114
- end
115
-
116
- def build_constraint(reflection, table, key, foreign_table, foreign_key)
117
- constraint = table[key].eq(foreign_table[foreign_key])
45
+ unless others.empty?
46
+ joins.concat arel.join_sources
47
+ append_constraints(joins.last, others)
48
+ end
118
49
 
119
- if reflection.klass.finder_needs_type_condition?
120
- constraint = table.create_and([
121
- constraint,
122
- reflection.klass.send(:type_condition, table)
123
- ])
50
+ # The current table in this iteration becomes the foreign table in the next
51
+ foreign_table, foreign_klass = table, klass
124
52
  end
125
53
 
126
- constraint
54
+ joins
127
55
  end
128
56
 
129
- def join_relation(joining_relation)
130
- self.join_type = Arel::OuterJoin
131
- joining_relation.joins(self)
132
- end
133
-
134
- def table
135
- tables.last
136
- end
137
-
138
- def aliased_table_name
139
- table.table_alias || table.name
140
- end
141
-
142
- def conditions
143
- @conditions ||= reflection.conditions.reverse
57
+ def tables=(tables)
58
+ @tables = tables
59
+ @table = tables.first
144
60
  end
145
61
 
146
62
  private
147
-
148
- def interpolate(conditions)
149
- if conditions.respond_to?(:to_proc) && !conditions.is_a?(Hash)
150
- instance_eval(&conditions)
151
- else
152
- conditions
63
+ def fetch_arel_attribute(value)
64
+ case value
65
+ when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
66
+ yield value.left.is_a?(Arel::Attributes::Attribute) ? value.left : value.right
67
+ end
153
68
  end
154
- end
155
69
 
70
+ def append_constraints(join, constraints)
71
+ if join.is_a?(Arel::Nodes::StringJoin)
72
+ join_string = table.create_and(constraints.unshift(join.left))
73
+ join.left = Arel.sql(base_klass.connection.visitor.compile(join_string))
74
+ else
75
+ join.right.expr.children.concat(constraints)
76
+ end
77
+ end
156
78
  end
157
79
  end
158
80
  end
@@ -1,22 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/associations/join_dependency/join_part"
4
+
1
5
  module ActiveRecord
2
6
  module Associations
3
7
  class JoinDependency # :nodoc:
4
8
  class JoinBase < JoinPart # :nodoc:
5
- def ==(other)
6
- other.class == self.class &&
7
- other.active_record == active_record
8
- end
9
-
10
- def aliased_prefix
11
- "t0"
12
- end
9
+ attr_reader :table
13
10
 
14
- def table
15
- Arel::Table.new(table_name, arel_engine)
11
+ def initialize(base_klass, table, children)
12
+ super(base_klass, children)
13
+ @table = table
16
14
  end
17
15
 
18
- def aliased_table_name
19
- active_record.table_name
16
+ def match?(other)
17
+ return true if self == other
18
+ super && base_klass == other.base_klass
20
19
  end
21
20
  end
22
21
  end
@@ -1,76 +1,69 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  class JoinDependency # :nodoc:
4
- # A JoinPart represents a part of a JoinDependency. It is an abstract class, inherited
6
+ # A JoinPart represents a part of a JoinDependency. It is inherited
5
7
  # by JoinBase and JoinAssociation. A JoinBase represents the Active Record which
6
8
  # everything else is being joined onto. A JoinAssociation represents an association which
7
9
  # is joining to the base. A JoinAssociation may result in more than one actual join
8
10
  # operations (for example a has_and_belongs_to_many JoinAssociation would result in
9
11
  # two; one for the join table and one for the target table).
10
12
  class JoinPart # :nodoc:
13
+ include Enumerable
14
+
11
15
  # The Active Record class which this join part is associated 'about'; for a JoinBase
12
16
  # this is the actual base model, for a JoinAssociation this is the target model of the
13
17
  # association.
14
- attr_reader :active_record
18
+ attr_reader :base_klass, :children
15
19
 
16
- delegate :table_name, :column_names, :primary_key, :reflections, :arel_engine, :to => :active_record
17
-
18
- def initialize(active_record)
19
- @active_record = active_record
20
- @cached_record = {}
21
- @column_names_with_alias = nil
22
- end
20
+ delegate :table_name, :column_names, :primary_key, to: :base_klass
23
21
 
24
- def aliased_table
25
- Arel::Nodes::TableAlias.new table, aliased_table_name
22
+ def initialize(base_klass, children)
23
+ @base_klass = base_klass
24
+ @children = children
26
25
  end
27
26
 
28
- def ==(other)
29
- raise NotImplementedError
27
+ def match?(other)
28
+ self.class == other.class
30
29
  end
31
30
 
32
- # An Arel::Table for the active_record
33
- def table
34
- raise NotImplementedError
31
+ def each(&block)
32
+ yield self
33
+ children.each { |child| child.each(&block) }
35
34
  end
36
35
 
37
- # The prefix to be used when aliasing columns in the active_record's table
38
- def aliased_prefix
39
- raise NotImplementedError
36
+ def each_children(&block)
37
+ children.each do |child|
38
+ yield self, child
39
+ child.each_children(&block)
40
+ end
40
41
  end
41
42
 
42
- # The alias for the active_record's table
43
- def aliased_table_name
43
+ # An Arel::Table for the active_record
44
+ def table
44
45
  raise NotImplementedError
45
46
  end
46
47
 
47
- # The alias for the primary key of the active_record's table
48
- def aliased_primary_key
49
- "#{aliased_prefix}_r0"
50
- end
48
+ def extract_record(row, column_names_with_alias)
49
+ # This code is performance critical as it is called per row.
50
+ # see: https://github.com/rails/rails/pull/12185
51
+ hash = {}
51
52
 
52
- # An array of [column_name, alias] pairs for the table
53
- def column_names_with_alias
54
- unless @column_names_with_alias
55
- @column_names_with_alias = []
53
+ index = 0
54
+ length = column_names_with_alias.length
56
55
 
57
- ([primary_key] + (column_names - [primary_key])).each_with_index do |column_name, i|
58
- @column_names_with_alias << [column_name, "#{aliased_prefix}_r#{i}"]
59
- end
56
+ while index < length
57
+ column_name, alias_name = column_names_with_alias[index]
58
+ hash[column_name] = row[alias_name]
59
+ index += 1
60
60
  end
61
- @column_names_with_alias
62
- end
63
-
64
- def extract_record(row)
65
- Hash[column_names_with_alias.map{|cn, an| [cn, row[an]]}]
66
- end
67
61
 
68
- def record_id(row)
69
- row[aliased_primary_key]
62
+ hash
70
63
  end
71
64
 
72
- def instantiate(row)
73
- @cached_record[record_id(row)] ||= active_record.send(:instantiate, extract_record(row))
65
+ def instantiate(row, aliases, &block)
66
+ base_klass.instantiate(extract_record(row, aliases), &block)
74
67
  end
75
68
  end
76
69
  end