activerecord 4.2.9 → 6.1.4.1

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 (374) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +964 -1382
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +15 -14
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +266 -251
  8. data/lib/active_record/association_relation.rb +40 -15
  9. data/lib/active_record/associations/alias_tracker.rb +40 -43
  10. data/lib/active_record/associations/association.rb +162 -69
  11. data/lib/active_record/associations/association_scope.rb +105 -130
  12. data/lib/active_record/associations/belongs_to_association.rb +83 -65
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
  14. data/lib/active_record/associations/builder/association.rb +57 -43
  15. data/lib/active_record/associations/builder/belongs_to.rb +74 -57
  16. data/lib/active_record/associations/builder/collection_association.rb +15 -37
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +49 -66
  18. data/lib/active_record/associations/builder/has_many.rb +13 -5
  19. data/lib/active_record/associations/builder/has_one.rb +44 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  21. data/lib/active_record/associations/collection_association.rb +148 -287
  22. data/lib/active_record/associations/collection_proxy.rb +252 -150
  23. data/lib/active_record/associations/foreign_association.rb +23 -1
  24. data/lib/active_record/associations/has_many_association.rb +56 -98
  25. data/lib/active_record/associations/has_many_through_association.rb +68 -89
  26. data/lib/active_record/associations/has_one_association.rb +73 -47
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +54 -81
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  31. data/lib/active_record/associations/join_dependency.rb +174 -169
  32. data/lib/active_record/associations/preloader/association.rb +108 -115
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  34. data/lib/active_record/associations/preloader.rb +97 -94
  35. data/lib/active_record/associations/singular_association.rb +18 -39
  36. data/lib/active_record/associations/through_association.rb +39 -19
  37. data/lib/active_record/associations.rb +1845 -1598
  38. data/lib/active_record/attribute_assignment.rb +59 -185
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +18 -10
  40. data/lib/active_record/attribute_methods/dirty.rb +168 -148
  41. data/lib/active_record/attribute_methods/primary_key.rb +93 -83
  42. data/lib/active_record/attribute_methods/query.rb +8 -10
  43. data/lib/active_record/attribute_methods/read.rb +19 -79
  44. data/lib/active_record/attribute_methods/serialization.rb +49 -24
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +55 -36
  46. data/lib/active_record/attribute_methods/write.rb +24 -55
  47. data/lib/active_record/attribute_methods.rb +149 -154
  48. data/lib/active_record/attributes.rb +234 -78
  49. data/lib/active_record/autosave_association.rb +133 -60
  50. data/lib/active_record/base.rb +46 -46
  51. data/lib/active_record/callbacks.rb +234 -79
  52. data/lib/active_record/coders/json.rb +3 -1
  53. data/lib/active_record/coders/yaml_column.rb +34 -13
  54. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -323
  55. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
  56. data/lib/active_record/connection_adapters/abstract/database_statements.rb +292 -124
  57. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
  58. data/lib/active_record/connection_adapters/abstract/quoting.rb +177 -60
  59. data/lib/active_record/connection_adapters/abstract/savepoints.rb +8 -6
  60. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +473 -255
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +869 -286
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +257 -91
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +483 -230
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +557 -640
  67. data/lib/active_record/connection_adapters/column.rb +67 -40
  68. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  69. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +194 -0
  72. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +96 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +97 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +103 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +91 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
  78. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +80 -192
  80. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  81. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +75 -160
  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 +49 -58
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +8 -6
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -19
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  98. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  101. data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +70 -34
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  109. data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -25
  110. data/lib/active_record/connection_adapters/postgresql/quoting.rb +145 -48
  111. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  112. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
  114. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
  115. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +496 -298
  116. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
  117. data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
  118. data/lib/active_record/connection_adapters/postgresql_adapter.rb +588 -375
  119. data/lib/active_record/connection_adapters/schema_cache.rb +167 -29
  120. data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
  121. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
  122. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  123. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +21 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +322 -373
  129. data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
  130. data/lib/active_record/connection_adapters.rb +52 -0
  131. data/lib/active_record/connection_handling.rb +314 -41
  132. data/lib/active_record/core.rb +458 -241
  133. data/lib/active_record/counter_cache.rb +70 -49
  134. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  135. data/lib/active_record/database_configurations/database_config.rb +80 -0
  136. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  137. data/lib/active_record/database_configurations/url_config.rb +53 -0
  138. data/lib/active_record/database_configurations.rb +272 -0
  139. data/lib/active_record/delegated_type.rb +209 -0
  140. data/lib/active_record/destroy_association_async_job.rb +36 -0
  141. data/lib/active_record/dynamic_matchers.rb +87 -106
  142. data/lib/active_record/enum.rb +211 -92
  143. data/lib/active_record/errors.rb +224 -54
  144. data/lib/active_record/explain.rb +27 -11
  145. data/lib/active_record/explain_registry.rb +4 -2
  146. data/lib/active_record/explain_subscriber.rb +10 -5
  147. data/lib/active_record/fixture_set/file.rb +33 -14
  148. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  149. data/lib/active_record/fixture_set/render_context.rb +17 -0
  150. data/lib/active_record/fixture_set/table_row.rb +152 -0
  151. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  152. data/lib/active_record/fixtures.rb +275 -500
  153. data/lib/active_record/gem_version.rb +6 -4
  154. data/lib/active_record/inheritance.rb +175 -110
  155. data/lib/active_record/insert_all.rb +212 -0
  156. data/lib/active_record/integration.rb +121 -29
  157. data/lib/active_record/internal_metadata.rb +62 -0
  158. data/lib/active_record/legacy_yaml_adapter.rb +27 -5
  159. data/lib/active_record/locale/en.yml +3 -2
  160. data/lib/active_record/locking/optimistic.rb +98 -92
  161. data/lib/active_record/locking/pessimistic.rb +22 -6
  162. data/lib/active_record/log_subscriber.rb +93 -31
  163. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  164. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  165. data/lib/active_record/middleware/database_selector.rb +77 -0
  166. data/lib/active_record/migration/command_recorder.rb +185 -90
  167. data/lib/active_record/migration/compatibility.rb +295 -0
  168. data/lib/active_record/migration/join_table.rb +8 -7
  169. data/lib/active_record/migration.rb +673 -325
  170. data/lib/active_record/model_schema.rb +418 -113
  171. data/lib/active_record/nested_attributes.rb +263 -224
  172. data/lib/active_record/no_touching.rb +15 -2
  173. data/lib/active_record/null_relation.rb +24 -38
  174. data/lib/active_record/persistence.rb +572 -136
  175. data/lib/active_record/query_cache.rb +29 -23
  176. data/lib/active_record/querying.rb +50 -31
  177. data/lib/active_record/railtie.rb +170 -51
  178. data/lib/active_record/railties/console_sandbox.rb +3 -3
  179. data/lib/active_record/railties/controller_runtime.rb +34 -33
  180. data/lib/active_record/railties/databases.rake +523 -199
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +454 -291
  183. data/lib/active_record/relation/batches/batch_enumerator.rb +85 -0
  184. data/lib/active_record/relation/batches.rb +217 -59
  185. data/lib/active_record/relation/calculations.rb +324 -249
  186. data/lib/active_record/relation/delegation.rb +76 -84
  187. data/lib/active_record/relation/finder_methods.rb +316 -242
  188. data/lib/active_record/relation/from_clause.rb +30 -0
  189. data/lib/active_record/relation/merger.rb +95 -103
  190. data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -26
  191. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
  192. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  193. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +57 -0
  194. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  195. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  196. data/lib/active_record/relation/predicate_builder.rb +136 -122
  197. data/lib/active_record/relation/query_attribute.rb +50 -0
  198. data/lib/active_record/relation/query_methods.rb +757 -413
  199. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  200. data/lib/active_record/relation/spawn_methods.rb +18 -20
  201. data/lib/active_record/relation/where_clause.rb +239 -0
  202. data/lib/active_record/relation.rb +554 -343
  203. data/lib/active_record/result.rb +91 -47
  204. data/lib/active_record/runtime_registry.rb +6 -4
  205. data/lib/active_record/sanitization.rb +134 -122
  206. data/lib/active_record/schema.rb +21 -24
  207. data/lib/active_record/schema_dumper.rb +141 -92
  208. data/lib/active_record/schema_migration.rb +24 -23
  209. data/lib/active_record/scoping/default.rb +96 -83
  210. data/lib/active_record/scoping/named.rb +78 -36
  211. data/lib/active_record/scoping.rb +45 -27
  212. data/lib/active_record/secure_token.rb +48 -0
  213. data/lib/active_record/serialization.rb +8 -6
  214. data/lib/active_record/signed_id.rb +116 -0
  215. data/lib/active_record/statement_cache.rb +89 -36
  216. data/lib/active_record/store.rb +128 -43
  217. data/lib/active_record/suppressor.rb +61 -0
  218. data/lib/active_record/table_metadata.rb +81 -0
  219. data/lib/active_record/tasks/database_tasks.rb +364 -130
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +67 -113
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +86 -49
  222. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -19
  223. data/lib/active_record/test_databases.rb +24 -0
  224. data/lib/active_record/test_fixtures.rb +287 -0
  225. data/lib/active_record/timestamp.rb +86 -43
  226. data/lib/active_record/touch_later.rb +65 -0
  227. data/lib/active_record/transactions.rb +182 -163
  228. data/lib/active_record/translation.rb +3 -1
  229. data/lib/active_record/type/adapter_specific_registry.rb +126 -0
  230. data/lib/active_record/type/date.rb +4 -45
  231. data/lib/active_record/type/date_time.rb +4 -49
  232. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  233. data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
  234. data/lib/active_record/type/internal/timezone.rb +17 -0
  235. data/lib/active_record/type/json.rb +30 -0
  236. data/lib/active_record/type/serialized.rb +27 -15
  237. data/lib/active_record/type/text.rb +2 -2
  238. data/lib/active_record/type/time.rb +21 -16
  239. data/lib/active_record/type/type_map.rb +16 -19
  240. data/lib/active_record/type/unsigned_integer.rb +9 -8
  241. data/lib/active_record/type.rb +84 -23
  242. data/lib/active_record/type_caster/connection.rb +33 -0
  243. data/lib/active_record/type_caster/map.rb +23 -0
  244. data/lib/active_record/type_caster.rb +9 -0
  245. data/lib/active_record/validations/absence.rb +25 -0
  246. data/lib/active_record/validations/associated.rb +12 -4
  247. data/lib/active_record/validations/length.rb +26 -0
  248. data/lib/active_record/validations/numericality.rb +35 -0
  249. data/lib/active_record/validations/presence.rb +14 -13
  250. data/lib/active_record/validations/uniqueness.rb +63 -56
  251. data/lib/active_record/validations.rb +39 -35
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/active_record.rb +42 -29
  254. data/lib/arel/alias_predication.rb +9 -0
  255. data/lib/arel/attributes/attribute.rb +41 -0
  256. data/lib/arel/collectors/bind.rb +29 -0
  257. data/lib/arel/collectors/composite.rb +39 -0
  258. data/lib/arel/collectors/plain_string.rb +20 -0
  259. data/lib/arel/collectors/sql_string.rb +27 -0
  260. data/lib/arel/collectors/substitute_binds.rb +35 -0
  261. data/lib/arel/crud.rb +42 -0
  262. data/lib/arel/delete_manager.rb +18 -0
  263. data/lib/arel/errors.rb +9 -0
  264. data/lib/arel/expressions.rb +29 -0
  265. data/lib/arel/factory_methods.rb +49 -0
  266. data/lib/arel/insert_manager.rb +49 -0
  267. data/lib/arel/math.rb +45 -0
  268. data/lib/arel/nodes/and.rb +32 -0
  269. data/lib/arel/nodes/ascending.rb +23 -0
  270. data/lib/arel/nodes/binary.rb +126 -0
  271. data/lib/arel/nodes/bind_param.rb +44 -0
  272. data/lib/arel/nodes/case.rb +55 -0
  273. data/lib/arel/nodes/casted.rb +62 -0
  274. data/lib/arel/nodes/comment.rb +29 -0
  275. data/lib/arel/nodes/count.rb +12 -0
  276. data/lib/arel/nodes/delete_statement.rb +45 -0
  277. data/lib/arel/nodes/descending.rb +23 -0
  278. data/lib/arel/nodes/equality.rb +15 -0
  279. data/lib/arel/nodes/extract.rb +24 -0
  280. data/lib/arel/nodes/false.rb +16 -0
  281. data/lib/arel/nodes/full_outer_join.rb +8 -0
  282. data/lib/arel/nodes/function.rb +44 -0
  283. data/lib/arel/nodes/grouping.rb +11 -0
  284. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  285. data/lib/arel/nodes/in.rb +15 -0
  286. data/lib/arel/nodes/infix_operation.rb +92 -0
  287. data/lib/arel/nodes/inner_join.rb +8 -0
  288. data/lib/arel/nodes/insert_statement.rb +37 -0
  289. data/lib/arel/nodes/join_source.rb +20 -0
  290. data/lib/arel/nodes/matches.rb +18 -0
  291. data/lib/arel/nodes/named_function.rb +23 -0
  292. data/lib/arel/nodes/node.rb +51 -0
  293. data/lib/arel/nodes/node_expression.rb +13 -0
  294. data/lib/arel/nodes/ordering.rb +27 -0
  295. data/lib/arel/nodes/outer_join.rb +8 -0
  296. data/lib/arel/nodes/over.rb +15 -0
  297. data/lib/arel/nodes/regexp.rb +16 -0
  298. data/lib/arel/nodes/right_outer_join.rb +8 -0
  299. data/lib/arel/nodes/select_core.rb +67 -0
  300. data/lib/arel/nodes/select_statement.rb +41 -0
  301. data/lib/arel/nodes/sql_literal.rb +19 -0
  302. data/lib/arel/nodes/string_join.rb +11 -0
  303. data/lib/arel/nodes/table_alias.rb +31 -0
  304. data/lib/arel/nodes/terminal.rb +16 -0
  305. data/lib/arel/nodes/true.rb +16 -0
  306. data/lib/arel/nodes/unary.rb +44 -0
  307. data/lib/arel/nodes/unary_operation.rb +20 -0
  308. data/lib/arel/nodes/unqualified_column.rb +22 -0
  309. data/lib/arel/nodes/update_statement.rb +41 -0
  310. data/lib/arel/nodes/values_list.rb +9 -0
  311. data/lib/arel/nodes/window.rb +126 -0
  312. data/lib/arel/nodes/with.rb +11 -0
  313. data/lib/arel/nodes.rb +70 -0
  314. data/lib/arel/order_predications.rb +13 -0
  315. data/lib/arel/predications.rb +250 -0
  316. data/lib/arel/select_manager.rb +270 -0
  317. data/lib/arel/table.rb +118 -0
  318. data/lib/arel/tree_manager.rb +72 -0
  319. data/lib/arel/update_manager.rb +34 -0
  320. data/lib/arel/visitors/dot.rb +308 -0
  321. data/lib/arel/visitors/mysql.rb +93 -0
  322. data/lib/arel/visitors/postgresql.rb +120 -0
  323. data/lib/arel/visitors/sqlite.rb +38 -0
  324. data/lib/arel/visitors/to_sql.rb +899 -0
  325. data/lib/arel/visitors/visitor.rb +45 -0
  326. data/lib/arel/visitors.rb +13 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/arel.rb +54 -0
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  330. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  331. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -37
  332. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +26 -0
  333. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +13 -4
  334. data/lib/rails/generators/active_record/migration.rb +35 -1
  335. data/lib/rails/generators/active_record/model/model_generator.rb +55 -22
  336. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  337. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  338. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  339. data/lib/rails/generators/active_record.rb +7 -5
  340. metadata +172 -65
  341. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  342. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  343. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  344. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  345. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  346. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  347. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  348. data/lib/active_record/attribute.rb +0 -163
  349. data/lib/active_record/attribute_decorators.rb +0 -66
  350. data/lib/active_record/attribute_set/builder.rb +0 -106
  351. data/lib/active_record/attribute_set.rb +0 -81
  352. data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
  353. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  354. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  355. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  356. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  357. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  358. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  359. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  360. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  361. data/lib/active_record/type/big_integer.rb +0 -13
  362. data/lib/active_record/type/binary.rb +0 -50
  363. data/lib/active_record/type/boolean.rb +0 -31
  364. data/lib/active_record/type/decimal.rb +0 -64
  365. data/lib/active_record/type/decorator.rb +0 -14
  366. data/lib/active_record/type/float.rb +0 -19
  367. data/lib/active_record/type/integer.rb +0 -59
  368. data/lib/active_record/type/mutable.rb +0 -16
  369. data/lib/active_record/type/numeric.rb +0 -36
  370. data/lib/active_record/type/string.rb +0 -40
  371. data/lib/active_record/type/time_value.rb +0 -38
  372. data/lib/active_record/type/value.rb +0 -110
  373. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
  374. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  # Returns the version of the currently loaded Active Record as a <tt>Gem::Version</tt>
3
5
  def self.gem_version
@@ -5,10 +7,10 @@ module ActiveRecord
5
7
  end
6
8
 
7
9
  module VERSION
8
- MAJOR = 4
9
- MINOR = 2
10
- TINY = 9
11
- PRE = nil
10
+ MAJOR = 6
11
+ MINOR = 1
12
+ TINY = 4
13
+ PRE = "1"
12
14
 
13
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
14
16
  end
@@ -1,4 +1,6 @@
1
- require 'active_support/core_ext/hash/indifferent_access'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/hash/indifferent_access"
2
4
 
3
5
  module ActiveRecord
4
6
  # == Single table inheritance
@@ -19,7 +21,7 @@ module ActiveRecord
19
21
  # Be aware that because the type column is an attribute on the record every new
20
22
  # subclass will instantly be marked as dirty and the type column will be included
21
23
  # in the list of changed attributes on the record. This is different from non
22
- # STI classes:
24
+ # Single Table Inheritance(STI) classes:
23
25
  #
24
26
  # Company.new.changed? # => false
25
27
  # Firm.new.changed? # => true
@@ -30,33 +32,42 @@ module ActiveRecord
30
32
  # for differentiating between them or reloading the right type with find.
31
33
  #
32
34
  # Note, all the attributes for all the cases are kept in the same table. Read more:
33
- # http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
35
+ # https://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
34
36
  #
35
37
  module Inheritance
36
38
  extend ActiveSupport::Concern
37
39
 
38
40
  included do
41
+ class_attribute :store_full_class_name, instance_writer: false, default: true
42
+
39
43
  # Determines whether to store the full constant name including namespace when using STI.
40
- class_attribute :store_full_sti_class, instance_writer: false
41
- self.store_full_sti_class = true
44
+ # This is true, by default.
45
+ class_attribute :store_full_sti_class, instance_writer: false, default: true
42
46
  end
43
47
 
44
48
  module ClassMethods
45
49
  # Determines if one of the attributes passed in is the inheritance column,
46
50
  # and if the inheritance column is attr accessible, it initializes an
47
51
  # instance of the given subclass instead of the base class.
48
- def new(*args, &block)
52
+ def new(attributes = nil, &block)
49
53
  if abstract_class? || self == Base
50
54
  raise NotImplementedError, "#{self} is an abstract class and cannot be instantiated."
51
55
  end
52
56
 
53
- attrs = args.first
54
- if subclass_from_attributes?(attrs)
55
- subclass = subclass_from_attributes(attrs)
57
+ if _has_attribute?(inheritance_column)
58
+ subclass = subclass_from_attributes(attributes)
59
+
60
+ if subclass.nil? && scope_attributes = current_scope&.scope_for_create
61
+ subclass = subclass_from_attributes(scope_attributes)
62
+ end
63
+
64
+ if subclass.nil? && base_class?
65
+ subclass = subclass_from_attributes(column_defaults)
66
+ end
56
67
  end
57
68
 
58
- if subclass
59
- subclass.new(*args, &block)
69
+ if subclass && subclass != self
70
+ subclass.new(attributes, &block)
60
71
  else
61
72
  super
62
73
  end
@@ -79,20 +90,10 @@ module ActiveRecord
79
90
  :true == (@finder_needs_type_condition ||= descends_from_active_record? ? :false : :true)
80
91
  end
81
92
 
82
- def symbolized_base_class
83
- ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_base_class` is deprecated and will be removed without replacement.')
84
- @symbolized_base_class ||= base_class.to_s.to_sym
85
- end
86
-
87
- def symbolized_sti_name
88
- ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_sti_name` is deprecated and will be removed without replacement.')
89
- @symbolized_sti_name ||= sti_name.present? ? sti_name.to_sym : symbolized_base_class
90
- end
91
-
92
93
  # Returns the class descending directly from ActiveRecord::Base, or
93
94
  # an abstract class, if any, in the inheritance hierarchy.
94
95
  #
95
- # If A extends AR::Base, A.base_class will return A. If B descends from A
96
+ # If A extends ActiveRecord::Base, A.base_class will return A. If B descends from A
96
97
  # through some arbitrarily deep hierarchy, B.base_class will return A.
97
98
  #
98
99
  # If B < A and C < B and if A is an abstract_class then both B.base_class
@@ -109,21 +110,53 @@ module ActiveRecord
109
110
  end
110
111
  end
111
112
 
112
- # Set this to true if this is an abstract class (see <tt>abstract_class?</tt>).
113
- # If you are using inheritance with ActiveRecord and don't want child classes
114
- # to utilize the implied STI table name of the parent class, this will need to be true.
115
- # For example, given the following:
113
+ # Returns whether the class is a base class.
114
+ # See #base_class for more information.
115
+ def base_class?
116
+ base_class == self
117
+ end
118
+
119
+ # Set this to +true+ if this is an abstract class (see
120
+ # <tt>abstract_class?</tt>).
121
+ # If you are using inheritance with Active Record and don't want a class
122
+ # to be considered as part of the STI hierarchy, you must set this to
123
+ # true.
124
+ # +ApplicationRecord+, for example, is generated as an abstract class.
125
+ #
126
+ # Consider the following default behaviour:
127
+ #
128
+ # Shape = Class.new(ActiveRecord::Base)
129
+ # Polygon = Class.new(Shape)
130
+ # Square = Class.new(Polygon)
131
+ #
132
+ # Shape.table_name # => "shapes"
133
+ # Polygon.table_name # => "shapes"
134
+ # Square.table_name # => "shapes"
135
+ # Shape.create! # => #<Shape id: 1, type: nil>
136
+ # Polygon.create! # => #<Polygon id: 2, type: "Polygon">
137
+ # Square.create! # => #<Square id: 3, type: "Square">
138
+ #
139
+ # However, when using <tt>abstract_class</tt>, +Shape+ is omitted from
140
+ # the hierarchy:
116
141
  #
117
- # class SuperClass < ActiveRecord::Base
142
+ # class Shape < ActiveRecord::Base
118
143
  # self.abstract_class = true
119
144
  # end
120
- # class Child < SuperClass
121
- # self.table_name = 'the_table_i_really_want'
122
- # end
123
- #
145
+ # Polygon = Class.new(Shape)
146
+ # Square = Class.new(Polygon)
124
147
  #
125
- # <tt>self.abstract_class = true</tt> is required to make <tt>Child<.find,.create, or any Arel method></tt> use <tt>the_table_i_really_want</tt> instead of a table called <tt>super_classes</tt>
148
+ # Shape.table_name # => nil
149
+ # Polygon.table_name # => "polygons"
150
+ # Square.table_name # => "polygons"
151
+ # Shape.create! # => NotImplementedError: Shape is an abstract class and cannot be instantiated.
152
+ # Polygon.create! # => #<Polygon id: 1, type: nil>
153
+ # Square.create! # => #<Square id: 2, type: "Square">
126
154
  #
155
+ # Note that in the above example, to disallow the creation of a plain
156
+ # +Polygon+, you should use <tt>validates :type, presence: true</tt>,
157
+ # instead of setting it as an abstract class. This way, +Polygon+ will
158
+ # stay in the hierarchy, and Active Record will continue to correctly
159
+ # derive the table name.
127
160
  attr_accessor :abstract_class
128
161
 
129
162
  # Returns whether this class is an abstract class or not.
@@ -131,93 +164,126 @@ module ActiveRecord
131
164
  defined?(@abstract_class) && @abstract_class == true
132
165
  end
133
166
 
167
+ # Returns the value to be stored in the inheritance column for STI.
134
168
  def sti_name
135
- store_full_sti_class ? name : name.demodulize
169
+ store_full_sti_class && store_full_class_name ? name : name.demodulize
136
170
  end
137
171
 
138
- protected
139
-
140
- # Returns the class type of the record using the current module as a prefix. So descendants of
141
- # MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
142
- def compute_type(type_name)
143
- if type_name.match(/^::/)
144
- # If the type is prefixed with a scope operator then we assume that
145
- # the type_name is an absolute reference.
172
+ # Returns the class for the provided +type_name+.
173
+ #
174
+ # It is used to find the class correspondent to the value stored in the inheritance column.
175
+ def sti_class_for(type_name)
176
+ if store_full_sti_class && store_full_class_name
146
177
  ActiveSupport::Dependencies.constantize(type_name)
147
178
  else
148
- # Build a list of candidates to search for
149
- candidates = []
150
- name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" }
151
- candidates << type_name
152
-
153
- candidates.each do |candidate|
154
- constant = ActiveSupport::Dependencies.safe_constantize(candidate)
155
- return constant if candidate == constant.to_s
156
- end
157
-
158
- raise NameError.new("uninitialized constant #{candidates.first}", candidates.first)
179
+ compute_type(type_name)
159
180
  end
181
+ rescue NameError
182
+ raise SubclassNotFound,
183
+ "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
184
+ "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
185
+ "Please rename this column if you didn't intend it to be used for storing the inheritance class " \
186
+ "or overwrite #{name}.inheritance_column to use another column for that information."
160
187
  end
161
188
 
162
- private
189
+ # Returns the value to be stored in the polymorphic type column for Polymorphic Associations.
190
+ def polymorphic_name
191
+ store_full_class_name ? base_class.name : base_class.name.demodulize
192
+ end
163
193
 
164
- # Called by +instantiate+ to decide which class to use for a new
165
- # record instance. For single-table inheritance, we check the record
166
- # for a +type+ column and return the corresponding class.
167
- def discriminate_class_for_record(record)
168
- if using_single_table_inheritance?(record)
169
- find_sti_class(record[inheritance_column])
194
+ # Returns the class for the provided +name+.
195
+ #
196
+ # It is used to find the class correspondent to the value stored in the polymorphic type column.
197
+ def polymorphic_class_for(name)
198
+ if store_full_class_name
199
+ ActiveSupport::Dependencies.constantize(name)
170
200
  else
171
- super
201
+ compute_type(name)
172
202
  end
173
203
  end
174
204
 
175
- def using_single_table_inheritance?(record)
176
- record[inheritance_column].present? && columns_hash.include?(inheritance_column)
205
+ def inherited(subclass)
206
+ subclass.instance_variable_set(:@_type_candidates_cache, Concurrent::Map.new)
207
+ super
177
208
  end
178
209
 
179
- def find_sti_class(type_name)
180
- if store_full_sti_class
181
- ActiveSupport::Dependencies.constantize(type_name)
182
- else
183
- compute_type(type_name)
210
+ protected
211
+ # Returns the class type of the record using the current module as a prefix. So descendants of
212
+ # MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
213
+ def compute_type(type_name)
214
+ if type_name.start_with?("::")
215
+ # If the type is prefixed with a scope operator then we assume that
216
+ # the type_name is an absolute reference.
217
+ ActiveSupport::Dependencies.constantize(type_name)
218
+ else
219
+ type_candidate = @_type_candidates_cache[type_name]
220
+ if type_candidate && type_constant = ActiveSupport::Dependencies.safe_constantize(type_candidate)
221
+ return type_constant
222
+ end
223
+
224
+ # Build a list of candidates to search for
225
+ candidates = []
226
+ name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" }
227
+ candidates << type_name
228
+
229
+ candidates.each do |candidate|
230
+ constant = ActiveSupport::Dependencies.safe_constantize(candidate)
231
+ if candidate == constant.to_s
232
+ @_type_candidates_cache[type_name] = candidate
233
+ return constant
234
+ end
235
+ end
236
+
237
+ raise NameError.new("uninitialized constant #{candidates.first}", candidates.first)
238
+ end
184
239
  end
185
- rescue NameError
186
- raise SubclassNotFound,
187
- "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " +
188
- "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " +
189
- "Please rename this column if you didn't intend it to be used for storing the inheritance class " +
190
- "or overwrite #{name}.inheritance_column to use another column for that information."
191
- end
192
240
 
193
- def type_condition(table = arel_table)
194
- sti_column = table[inheritance_column]
195
- sti_names = ([self] + descendants).map { |model| model.sti_name }
196
-
197
- sti_column.in(sti_names)
198
- end
199
-
200
- # Detect the subclass from the inheritance column of attrs. If the inheritance column value
201
- # is not self or a valid subclass, raises ActiveRecord::SubclassNotFound
202
- # If this is a StrongParameters hash, and access to inheritance_column is not permitted,
203
- # this will ignore the inheritance column and return nil
204
- def subclass_from_attributes?(attrs)
205
- columns_hash.include?(inheritance_column) && attrs.is_a?(Hash)
206
- end
241
+ private
242
+ # Called by +instantiate+ to decide which class to use for a new
243
+ # record instance. For single-table inheritance, we check the record
244
+ # for a +type+ column and return the corresponding class.
245
+ def discriminate_class_for_record(record)
246
+ if using_single_table_inheritance?(record)
247
+ find_sti_class(record[inheritance_column])
248
+ else
249
+ super
250
+ end
251
+ end
207
252
 
208
- def subclass_from_attributes(attrs)
209
- subclass_name = attrs.with_indifferent_access[inheritance_column]
253
+ def using_single_table_inheritance?(record)
254
+ record[inheritance_column].present? && _has_attribute?(inheritance_column)
255
+ end
210
256
 
211
- if subclass_name.present? && subclass_name != self.name
212
- subclass = subclass_name.safe_constantize
257
+ def find_sti_class(type_name)
258
+ type_name = base_class.type_for_attribute(inheritance_column).cast(type_name)
259
+ subclass = sti_class_for(type_name)
213
260
 
214
- unless descendants.include?(subclass)
215
- raise ActiveRecord::SubclassNotFound.new("Invalid single-table inheritance type: #{subclass_name} is not a subclass of #{name}")
261
+ unless subclass == self || descendants.include?(subclass)
262
+ raise SubclassNotFound, "Invalid single-table inheritance type: #{subclass.name} is not a subclass of #{name}"
216
263
  end
217
264
 
218
265
  subclass
219
266
  end
220
- end
267
+
268
+ def type_condition(table = arel_table)
269
+ sti_column = table[inheritance_column]
270
+ sti_names = ([self] + descendants).map(&:sti_name)
271
+
272
+ predicate_builder.build(sti_column, sti_names)
273
+ end
274
+
275
+ # Detect the subclass from the inheritance column of attrs. If the inheritance column value
276
+ # is not self or a valid subclass, raises ActiveRecord::SubclassNotFound
277
+ def subclass_from_attributes(attrs)
278
+ attrs = attrs.to_h if attrs.respond_to?(:permitted?)
279
+ if attrs.is_a?(Hash)
280
+ subclass_name = attrs[inheritance_column] || attrs[inheritance_column.to_sym]
281
+
282
+ if subclass_name.present?
283
+ find_sti_class(subclass_name)
284
+ end
285
+ end
286
+ end
221
287
  end
222
288
 
223
289
  def initialize_dup(other)
@@ -226,22 +292,21 @@ module ActiveRecord
226
292
  end
227
293
 
228
294
  private
295
+ def initialize_internals_callback
296
+ super
297
+ ensure_proper_type
298
+ end
229
299
 
230
- def initialize_internals_callback
231
- super
232
- ensure_proper_type
233
- end
234
-
235
- # Sets the attribute used for single table inheritance to this class name if this is not the
236
- # ActiveRecord::Base descendant.
237
- # Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to
238
- # do Reply.new without having to set <tt>Reply[Reply.inheritance_column] = "Reply"</tt> yourself.
239
- # No such attribute would be set for objects of the Message class in that example.
240
- def ensure_proper_type
241
- klass = self.class
242
- if klass.finder_needs_type_condition?
243
- write_attribute(klass.inheritance_column, klass.sti_name)
300
+ # Sets the attribute used for single table inheritance to this class name if this is not the
301
+ # ActiveRecord::Base descendant.
302
+ # Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to
303
+ # do Reply.new without having to set <tt>Reply[Reply.inheritance_column] = "Reply"</tt> yourself.
304
+ # No such attribute would be set for objects of the Message class in that example.
305
+ def ensure_proper_type
306
+ klass = self.class
307
+ if klass.finder_needs_type_condition?
308
+ _write_attribute(klass.inheritance_column, klass.sti_name)
309
+ end
244
310
  end
245
- end
246
311
  end
247
312
  end
@@ -0,0 +1,212 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/enumerable"
4
+
5
+ module ActiveRecord
6
+ class InsertAll # :nodoc:
7
+ attr_reader :model, :connection, :inserts, :keys
8
+ attr_reader :on_duplicate, :returning, :unique_by
9
+
10
+ def initialize(model, inserts, on_duplicate:, returning: nil, unique_by: nil)
11
+ raise ArgumentError, "Empty list of attributes passed" if inserts.blank?
12
+
13
+ @model, @connection, @inserts, @keys = model, model.connection, inserts, inserts.first.keys.map(&:to_s)
14
+ @on_duplicate, @returning, @unique_by = on_duplicate, returning, unique_by
15
+
16
+ if model.scope_attributes?
17
+ @scope_attributes = model.scope_attributes
18
+ @keys |= @scope_attributes.keys
19
+ end
20
+ @keys = @keys.to_set
21
+
22
+ @returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
23
+ @returning = false if @returning == []
24
+
25
+ @unique_by = find_unique_index_for(unique_by)
26
+ @on_duplicate = :skip if @on_duplicate == :update && updatable_columns.empty?
27
+
28
+ ensure_valid_options_for_connection!
29
+ end
30
+
31
+ def execute
32
+ message = +"#{model} "
33
+ message << "Bulk " if inserts.many?
34
+ message << (on_duplicate == :update ? "Upsert" : "Insert")
35
+ connection.exec_insert_all to_sql, message
36
+ end
37
+
38
+ def updatable_columns
39
+ keys - readonly_columns - unique_by_columns
40
+ end
41
+
42
+ def primary_keys
43
+ Array(connection.schema_cache.primary_keys(model.table_name))
44
+ end
45
+
46
+
47
+ def skip_duplicates?
48
+ on_duplicate == :skip
49
+ end
50
+
51
+ def update_duplicates?
52
+ on_duplicate == :update
53
+ end
54
+
55
+ def map_key_with_value
56
+ inserts.map do |attributes|
57
+ attributes = attributes.stringify_keys
58
+ attributes.merge!(scope_attributes) if scope_attributes
59
+
60
+ verify_attributes(attributes)
61
+
62
+ keys.map do |key|
63
+ yield key, attributes[key]
64
+ end
65
+ end
66
+ end
67
+
68
+ private
69
+ attr_reader :scope_attributes
70
+
71
+ def find_unique_index_for(unique_by)
72
+ if !connection.supports_insert_conflict_target?
73
+ return if unique_by.nil?
74
+
75
+ raise ArgumentError, "#{connection.class} does not support :unique_by"
76
+ end
77
+
78
+ name_or_columns = unique_by || model.primary_key
79
+ match = Array(name_or_columns).map(&:to_s)
80
+
81
+ if index = unique_indexes.find { |i| match.include?(i.name) || i.columns == match }
82
+ index
83
+ elsif match == primary_keys
84
+ unique_by.nil? ? nil : ActiveRecord::ConnectionAdapters::IndexDefinition.new(model.table_name, "#{model.table_name}_primary_key", true, match)
85
+ else
86
+ raise ArgumentError, "No unique index found for #{name_or_columns}"
87
+ end
88
+ end
89
+
90
+ def unique_indexes
91
+ connection.schema_cache.indexes(model.table_name).select(&:unique)
92
+ end
93
+
94
+
95
+ def ensure_valid_options_for_connection!
96
+ if returning && !connection.supports_insert_returning?
97
+ raise ArgumentError, "#{connection.class} does not support :returning"
98
+ end
99
+
100
+ if skip_duplicates? && !connection.supports_insert_on_duplicate_skip?
101
+ raise ArgumentError, "#{connection.class} does not support skipping duplicates"
102
+ end
103
+
104
+ if update_duplicates? && !connection.supports_insert_on_duplicate_update?
105
+ raise ArgumentError, "#{connection.class} does not support upsert"
106
+ end
107
+
108
+ if unique_by && !connection.supports_insert_conflict_target?
109
+ raise ArgumentError, "#{connection.class} does not support :unique_by"
110
+ end
111
+ end
112
+
113
+
114
+ def to_sql
115
+ connection.build_insert_sql(ActiveRecord::InsertAll::Builder.new(self))
116
+ end
117
+
118
+
119
+ def readonly_columns
120
+ primary_keys + model.readonly_attributes.to_a
121
+ end
122
+
123
+ def unique_by_columns
124
+ Array(unique_by&.columns)
125
+ end
126
+
127
+
128
+ def verify_attributes(attributes)
129
+ if keys != attributes.keys.to_set
130
+ raise ArgumentError, "All objects being inserted must have the same keys"
131
+ end
132
+ end
133
+
134
+ class Builder # :nodoc:
135
+ attr_reader :model
136
+
137
+ delegate :skip_duplicates?, :update_duplicates?, :keys, to: :insert_all
138
+
139
+ def initialize(insert_all)
140
+ @insert_all, @model, @connection = insert_all, insert_all.model, insert_all.connection
141
+ end
142
+
143
+ def into
144
+ "INTO #{model.quoted_table_name} (#{columns_list})"
145
+ end
146
+
147
+ def values_list
148
+ types = extract_types_from_columns_on(model.table_name, keys: keys)
149
+
150
+ values_list = insert_all.map_key_with_value do |key, value|
151
+ connection.with_yaml_fallback(types[key].serialize(value))
152
+ end
153
+
154
+ connection.visitor.compile(Arel::Nodes::ValuesList.new(values_list))
155
+ end
156
+
157
+ def returning
158
+ format_columns(insert_all.returning) if insert_all.returning
159
+ end
160
+
161
+ def conflict_target
162
+ if index = insert_all.unique_by
163
+ sql = +"(#{format_columns(index.columns)})"
164
+ sql << " WHERE #{index.where}" if index.where
165
+ sql
166
+ elsif update_duplicates?
167
+ "(#{format_columns(insert_all.primary_keys)})"
168
+ end
169
+ end
170
+
171
+ def updatable_columns
172
+ quote_columns(insert_all.updatable_columns)
173
+ end
174
+
175
+ def touch_model_timestamps_unless(&block)
176
+ model.send(:timestamp_attributes_for_update_in_model).map do |column_name|
177
+ if touch_timestamp_attribute?(column_name)
178
+ "#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE CURRENT_TIMESTAMP END),"
179
+ end
180
+ end.compact.join
181
+ end
182
+
183
+ private
184
+ attr_reader :connection, :insert_all
185
+
186
+ def touch_timestamp_attribute?(column_name)
187
+ update_duplicates? && !insert_all.updatable_columns.include?(column_name)
188
+ end
189
+
190
+ def columns_list
191
+ format_columns(insert_all.keys)
192
+ end
193
+
194
+ def extract_types_from_columns_on(table_name, keys:)
195
+ columns = connection.schema_cache.columns_hash(table_name)
196
+
197
+ unknown_column = (keys - columns.keys).first
198
+ raise UnknownAttributeError.new(model.new, unknown_column) if unknown_column
199
+
200
+ keys.index_with { |key| model.type_for_attribute(key) }
201
+ end
202
+
203
+ def format_columns(columns)
204
+ columns.respond_to?(:map) ? quote_columns(columns).join(",") : columns
205
+ end
206
+
207
+ def quote_columns(columns)
208
+ columns.map(&connection.method(:quote_column_name))
209
+ end
210
+ end
211
+ end
212
+ end