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