activerecord 5.2.8 → 7.0.2

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 (364) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1393 -587
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +10 -9
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations/alias_tracker.rb +19 -16
  9. data/lib/active_record/associations/association.rb +122 -47
  10. data/lib/active_record/associations/association_scope.rb +24 -24
  11. data/lib/active_record/associations/belongs_to_association.rb +67 -49
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +16 -7
  13. data/lib/active_record/associations/builder/association.rb +52 -23
  14. data/lib/active_record/associations/builder/belongs_to.rb +44 -61
  15. data/lib/active_record/associations/builder/collection_association.rb +17 -19
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  17. data/lib/active_record/associations/builder/has_many.rb +10 -3
  18. data/lib/active_record/associations/builder/has_one.rb +35 -3
  19. data/lib/active_record/associations/builder/singular_association.rb +5 -3
  20. data/lib/active_record/associations/collection_association.rb +59 -50
  21. data/lib/active_record/associations/collection_proxy.rb +32 -23
  22. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  23. data/lib/active_record/associations/foreign_association.rb +20 -0
  24. data/lib/active_record/associations/has_many_association.rb +27 -14
  25. data/lib/active_record/associations/has_many_through_association.rb +26 -19
  26. data/lib/active_record/associations/has_one_association.rb +52 -37
  27. data/lib/active_record/associations/has_one_through_association.rb +6 -6
  28. data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
  29. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  30. data/lib/active_record/associations/join_dependency.rb +97 -62
  31. data/lib/active_record/associations/preloader/association.rb +220 -60
  32. data/lib/active_record/associations/preloader/batch.rb +48 -0
  33. data/lib/active_record/associations/preloader/branch.rb +147 -0
  34. data/lib/active_record/associations/preloader/through_association.rb +85 -40
  35. data/lib/active_record/associations/preloader.rb +44 -105
  36. data/lib/active_record/associations/singular_association.rb +9 -17
  37. data/lib/active_record/associations/through_association.rb +4 -4
  38. data/lib/active_record/associations.rb +207 -66
  39. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  40. data/lib/active_record/attribute_assignment.rb +17 -19
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +19 -8
  42. data/lib/active_record/attribute_methods/dirty.rb +141 -47
  43. data/lib/active_record/attribute_methods/primary_key.rb +22 -27
  44. data/lib/active_record/attribute_methods/query.rb +6 -10
  45. data/lib/active_record/attribute_methods/read.rb +15 -55
  46. data/lib/active_record/attribute_methods/serialization.rb +77 -18
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +16 -18
  48. data/lib/active_record/attribute_methods/write.rb +18 -37
  49. data/lib/active_record/attribute_methods.rb +90 -153
  50. data/lib/active_record/attributes.rb +38 -12
  51. data/lib/active_record/autosave_association.rb +50 -50
  52. data/lib/active_record/base.rb +23 -18
  53. data/lib/active_record/callbacks.rb +159 -44
  54. data/lib/active_record/coders/yaml_column.rb +12 -3
  55. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  58. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +92 -464
  59. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -51
  60. data/lib/active_record/connection_adapters/abstract/database_statements.rb +209 -164
  61. data/lib/active_record/connection_adapters/abstract/query_cache.rb +38 -22
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +103 -82
  63. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  64. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +140 -110
  65. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -94
  66. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +16 -5
  67. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +456 -159
  68. data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +367 -162
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +311 -327
  71. data/lib/active_record/connection_adapters/column.rb +33 -11
  72. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  73. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  74. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  75. data/lib/active_record/connection_adapters/mysql/database_statements.rb +113 -45
  76. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  77. data/lib/active_record/connection_adapters/mysql/quoting.rb +71 -5
  78. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  79. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  80. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +25 -8
  81. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +143 -19
  82. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  83. data/lib/active_record/connection_adapters/mysql2_adapter.rb +63 -22
  84. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  85. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  86. data/lib/active_record/connection_adapters/postgresql/column.rb +53 -28
  87. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +56 -63
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +54 -16
  95. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
  97. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  102. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +26 -12
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -52
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -2
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +39 -4
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +128 -91
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -1
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +149 -113
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +386 -182
  116. data/lib/active_record/connection_adapters/schema_cache.rb +161 -22
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
  118. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +152 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +65 -18
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  121. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +92 -26
  122. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +251 -204
  123. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  124. data/lib/active_record/connection_adapters.rb +53 -0
  125. data/lib/active_record/connection_handling.rb +292 -38
  126. data/lib/active_record/core.rb +385 -158
  127. data/lib/active_record/counter_cache.rb +8 -30
  128. data/lib/active_record/database_configurations/connection_url_resolver.rb +100 -0
  129. data/lib/active_record/database_configurations/database_config.rb +83 -0
  130. data/lib/active_record/database_configurations/hash_config.rb +154 -0
  131. data/lib/active_record/database_configurations/url_config.rb +53 -0
  132. data/lib/active_record/database_configurations.rb +256 -0
  133. data/lib/active_record/delegated_type.rb +250 -0
  134. data/lib/active_record/destroy_association_async_job.rb +36 -0
  135. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  136. data/lib/active_record/dynamic_matchers.rb +4 -5
  137. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  138. data/lib/active_record/encryption/cipher.rb +53 -0
  139. data/lib/active_record/encryption/config.rb +44 -0
  140. data/lib/active_record/encryption/configurable.rb +61 -0
  141. data/lib/active_record/encryption/context.rb +35 -0
  142. data/lib/active_record/encryption/contexts.rb +72 -0
  143. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  144. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  145. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  146. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  147. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  148. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  149. data/lib/active_record/encryption/encryptor.rb +155 -0
  150. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  151. data/lib/active_record/encryption/errors.rb +15 -0
  152. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  153. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  154. data/lib/active_record/encryption/key.rb +28 -0
  155. data/lib/active_record/encryption/key_generator.rb +42 -0
  156. data/lib/active_record/encryption/key_provider.rb +46 -0
  157. data/lib/active_record/encryption/message.rb +33 -0
  158. data/lib/active_record/encryption/message_serializer.rb +90 -0
  159. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  160. data/lib/active_record/encryption/properties.rb +76 -0
  161. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  162. data/lib/active_record/encryption/scheme.rb +99 -0
  163. data/lib/active_record/encryption.rb +55 -0
  164. data/lib/active_record/enum.rb +130 -51
  165. data/lib/active_record/errors.rb +129 -23
  166. data/lib/active_record/explain.rb +10 -6
  167. data/lib/active_record/explain_registry.rb +11 -6
  168. data/lib/active_record/explain_subscriber.rb +1 -1
  169. data/lib/active_record/fixture_set/file.rb +22 -15
  170. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  171. data/lib/active_record/fixture_set/render_context.rb +17 -0
  172. data/lib/active_record/fixture_set/table_row.rb +187 -0
  173. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  174. data/lib/active_record/fixtures.rb +206 -490
  175. data/lib/active_record/future_result.rb +139 -0
  176. data/lib/active_record/gem_version.rb +3 -3
  177. data/lib/active_record/inheritance.rb +104 -37
  178. data/lib/active_record/insert_all.rb +278 -0
  179. data/lib/active_record/integration.rb +69 -18
  180. data/lib/active_record/internal_metadata.rb +24 -9
  181. data/lib/active_record/legacy_yaml_adapter.rb +3 -36
  182. data/lib/active_record/locking/optimistic.rb +41 -26
  183. data/lib/active_record/locking/pessimistic.rb +18 -8
  184. data/lib/active_record/log_subscriber.rb +46 -35
  185. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  186. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  187. data/lib/active_record/middleware/database_selector.rb +82 -0
  188. data/lib/active_record/middleware/shard_selector.rb +60 -0
  189. data/lib/active_record/migration/command_recorder.rb +96 -44
  190. data/lib/active_record/migration/compatibility.rb +246 -64
  191. data/lib/active_record/migration/join_table.rb +1 -2
  192. data/lib/active_record/migration.rb +266 -187
  193. data/lib/active_record/model_schema.rb +165 -52
  194. data/lib/active_record/nested_attributes.rb +17 -19
  195. data/lib/active_record/no_touching.rb +11 -4
  196. data/lib/active_record/null_relation.rb +2 -7
  197. data/lib/active_record/persistence.rb +467 -92
  198. data/lib/active_record/query_cache.rb +21 -4
  199. data/lib/active_record/query_logs.rb +138 -0
  200. data/lib/active_record/querying.rb +51 -24
  201. data/lib/active_record/railtie.rb +224 -57
  202. data/lib/active_record/railties/console_sandbox.rb +2 -4
  203. data/lib/active_record/railties/controller_runtime.rb +31 -36
  204. data/lib/active_record/railties/databases.rake +369 -101
  205. data/lib/active_record/readonly_attributes.rb +15 -0
  206. data/lib/active_record/reflection.rb +170 -137
  207. data/lib/active_record/relation/batches/batch_enumerator.rb +44 -14
  208. data/lib/active_record/relation/batches.rb +46 -37
  209. data/lib/active_record/relation/calculations.rb +168 -96
  210. data/lib/active_record/relation/delegation.rb +37 -52
  211. data/lib/active_record/relation/finder_methods.rb +79 -58
  212. data/lib/active_record/relation/from_clause.rb +5 -1
  213. data/lib/active_record/relation/merger.rb +50 -51
  214. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  215. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  216. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  217. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
  218. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  219. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  220. data/lib/active_record/relation/predicate_builder.rb +58 -46
  221. data/lib/active_record/relation/query_attribute.rb +9 -10
  222. data/lib/active_record/relation/query_methods.rb +685 -208
  223. data/lib/active_record/relation/record_fetch_warning.rb +9 -11
  224. data/lib/active_record/relation/spawn_methods.rb +10 -10
  225. data/lib/active_record/relation/where_clause.rb +108 -64
  226. data/lib/active_record/relation.rb +515 -151
  227. data/lib/active_record/result.rb +78 -42
  228. data/lib/active_record/runtime_registry.rb +9 -13
  229. data/lib/active_record/sanitization.rb +29 -44
  230. data/lib/active_record/schema.rb +37 -31
  231. data/lib/active_record/schema_dumper.rb +74 -23
  232. data/lib/active_record/schema_migration.rb +7 -9
  233. data/lib/active_record/scoping/default.rb +62 -17
  234. data/lib/active_record/scoping/named.rb +17 -32
  235. data/lib/active_record/scoping.rb +70 -41
  236. data/lib/active_record/secure_token.rb +16 -8
  237. data/lib/active_record/serialization.rb +6 -4
  238. data/lib/active_record/signed_id.rb +116 -0
  239. data/lib/active_record/statement_cache.rb +49 -6
  240. data/lib/active_record/store.rb +88 -9
  241. data/lib/active_record/suppressor.rb +13 -17
  242. data/lib/active_record/table_metadata.rb +42 -43
  243. data/lib/active_record/tasks/database_tasks.rb +352 -94
  244. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  245. data/lib/active_record/tasks/postgresql_database_tasks.rb +41 -39
  246. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  247. data/lib/active_record/test_databases.rb +24 -0
  248. data/lib/active_record/test_fixtures.rb +287 -0
  249. data/lib/active_record/timestamp.rb +44 -34
  250. data/lib/active_record/touch_later.rb +23 -22
  251. data/lib/active_record/transactions.rb +67 -128
  252. data/lib/active_record/translation.rb +3 -3
  253. data/lib/active_record/type/adapter_specific_registry.rb +34 -19
  254. data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
  255. data/lib/active_record/type/internal/timezone.rb +2 -2
  256. data/lib/active_record/type/serialized.rb +7 -4
  257. data/lib/active_record/type/time.rb +10 -0
  258. data/lib/active_record/type/type_map.rb +17 -21
  259. data/lib/active_record/type/unsigned_integer.rb +0 -1
  260. data/lib/active_record/type.rb +9 -5
  261. data/lib/active_record/type_caster/connection.rb +15 -15
  262. data/lib/active_record/type_caster/map.rb +8 -8
  263. data/lib/active_record/validations/associated.rb +2 -3
  264. data/lib/active_record/validations/numericality.rb +35 -0
  265. data/lib/active_record/validations/uniqueness.rb +39 -31
  266. data/lib/active_record/validations.rb +4 -3
  267. data/lib/active_record.rb +209 -32
  268. data/lib/arel/alias_predication.rb +9 -0
  269. data/lib/arel/attributes/attribute.rb +33 -0
  270. data/lib/arel/collectors/bind.rb +29 -0
  271. data/lib/arel/collectors/composite.rb +39 -0
  272. data/lib/arel/collectors/plain_string.rb +20 -0
  273. data/lib/arel/collectors/sql_string.rb +27 -0
  274. data/lib/arel/collectors/substitute_binds.rb +35 -0
  275. data/lib/arel/crud.rb +48 -0
  276. data/lib/arel/delete_manager.rb +32 -0
  277. data/lib/arel/errors.rb +9 -0
  278. data/lib/arel/expressions.rb +29 -0
  279. data/lib/arel/factory_methods.rb +49 -0
  280. data/lib/arel/filter_predications.rb +9 -0
  281. data/lib/arel/insert_manager.rb +48 -0
  282. data/lib/arel/math.rb +45 -0
  283. data/lib/arel/nodes/and.rb +32 -0
  284. data/lib/arel/nodes/ascending.rb +23 -0
  285. data/lib/arel/nodes/binary.rb +126 -0
  286. data/lib/arel/nodes/bind_param.rb +44 -0
  287. data/lib/arel/nodes/case.rb +55 -0
  288. data/lib/arel/nodes/casted.rb +62 -0
  289. data/lib/arel/nodes/comment.rb +29 -0
  290. data/lib/arel/nodes/count.rb +12 -0
  291. data/lib/arel/nodes/delete_statement.rb +44 -0
  292. data/lib/arel/nodes/descending.rb +23 -0
  293. data/lib/arel/nodes/equality.rb +15 -0
  294. data/lib/arel/nodes/extract.rb +24 -0
  295. data/lib/arel/nodes/false.rb +16 -0
  296. data/lib/arel/nodes/filter.rb +10 -0
  297. data/lib/arel/nodes/full_outer_join.rb +8 -0
  298. data/lib/arel/nodes/function.rb +45 -0
  299. data/lib/arel/nodes/grouping.rb +11 -0
  300. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  301. data/lib/arel/nodes/in.rb +15 -0
  302. data/lib/arel/nodes/infix_operation.rb +92 -0
  303. data/lib/arel/nodes/inner_join.rb +8 -0
  304. data/lib/arel/nodes/insert_statement.rb +37 -0
  305. data/lib/arel/nodes/join_source.rb +20 -0
  306. data/lib/arel/nodes/matches.rb +18 -0
  307. data/lib/arel/nodes/named_function.rb +23 -0
  308. data/lib/arel/nodes/node.rb +51 -0
  309. data/lib/arel/nodes/node_expression.rb +13 -0
  310. data/lib/arel/nodes/ordering.rb +27 -0
  311. data/lib/arel/nodes/outer_join.rb +8 -0
  312. data/lib/arel/nodes/over.rb +15 -0
  313. data/lib/arel/nodes/regexp.rb +16 -0
  314. data/lib/arel/nodes/right_outer_join.rb +8 -0
  315. data/lib/arel/nodes/select_core.rb +67 -0
  316. data/lib/arel/nodes/select_statement.rb +41 -0
  317. data/lib/arel/nodes/sql_literal.rb +19 -0
  318. data/lib/arel/nodes/string_join.rb +11 -0
  319. data/lib/arel/nodes/table_alias.rb +31 -0
  320. data/lib/arel/nodes/terminal.rb +16 -0
  321. data/lib/arel/nodes/true.rb +16 -0
  322. data/lib/arel/nodes/unary.rb +44 -0
  323. data/lib/arel/nodes/unary_operation.rb +20 -0
  324. data/lib/arel/nodes/unqualified_column.rb +22 -0
  325. data/lib/arel/nodes/update_statement.rb +46 -0
  326. data/lib/arel/nodes/values_list.rb +9 -0
  327. data/lib/arel/nodes/window.rb +126 -0
  328. data/lib/arel/nodes/with.rb +11 -0
  329. data/lib/arel/nodes.rb +71 -0
  330. data/lib/arel/order_predications.rb +13 -0
  331. data/lib/arel/predications.rb +258 -0
  332. data/lib/arel/select_manager.rb +276 -0
  333. data/lib/arel/table.rb +117 -0
  334. data/lib/arel/tree_manager.rb +60 -0
  335. data/lib/arel/update_manager.rb +48 -0
  336. data/lib/arel/visitors/dot.rb +298 -0
  337. data/lib/arel/visitors/mysql.rb +99 -0
  338. data/lib/arel/visitors/postgresql.rb +110 -0
  339. data/lib/arel/visitors/sqlite.rb +38 -0
  340. data/lib/arel/visitors/to_sql.rb +955 -0
  341. data/lib/arel/visitors/visitor.rb +45 -0
  342. data/lib/arel/visitors.rb +13 -0
  343. data/lib/arel/window_predications.rb +9 -0
  344. data/lib/arel.rb +55 -0
  345. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  346. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  347. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  348. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  349. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  350. data/lib/rails/generators/active_record/migration.rb +19 -2
  351. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  352. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  353. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  354. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  355. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  356. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  357. metadata +162 -32
  358. data/lib/active_record/attribute_decorators.rb +0 -90
  359. data/lib/active_record/collection_cache_key.rb +0 -53
  360. data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
  361. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
  362. data/lib/active_record/define_callbacks.rb +0 -22
  363. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
  364. data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class FutureResult # :nodoc:
5
+ class EventBuffer
6
+ def initialize(future_result, instrumenter)
7
+ @future_result = future_result
8
+ @instrumenter = instrumenter
9
+ @events = []
10
+ end
11
+
12
+ def instrument(name, payload = {}, &block)
13
+ event = @instrumenter.new_event(name, payload)
14
+ @events << event
15
+ event.record(&block)
16
+ end
17
+
18
+ def flush
19
+ events, @events = @events, []
20
+ events.each do |event|
21
+ event.payload[:lock_wait] = @future_result.lock_wait
22
+ ActiveSupport::Notifications.publish_event(event)
23
+ end
24
+ end
25
+ end
26
+
27
+ Canceled = Class.new(ActiveRecordError)
28
+
29
+ delegate :empty?, :to_a, to: :result
30
+
31
+ attr_reader :lock_wait
32
+
33
+ def initialize(pool, *args, **kwargs)
34
+ @mutex = Mutex.new
35
+
36
+ @session = nil
37
+ @pool = pool
38
+ @args = args
39
+ @kwargs = kwargs
40
+
41
+ @pending = true
42
+ @error = nil
43
+ @result = nil
44
+ @instrumenter = ActiveSupport::Notifications.instrumenter
45
+ @event_buffer = nil
46
+ end
47
+
48
+ def schedule!(session)
49
+ @session = session
50
+ @pool.schedule_query(self)
51
+ end
52
+
53
+ def execute!(connection)
54
+ execute_query(connection)
55
+ end
56
+
57
+ def cancel
58
+ @pending = false
59
+ @error = Canceled
60
+ self
61
+ end
62
+
63
+ def execute_or_skip
64
+ return unless pending?
65
+
66
+ @pool.with_connection do |connection|
67
+ return unless @mutex.try_lock
68
+ begin
69
+ if pending?
70
+ @event_buffer = EventBuffer.new(self, @instrumenter)
71
+ connection.with_instrumenter(@event_buffer) do
72
+ execute_query(connection, async: true)
73
+ end
74
+ end
75
+ ensure
76
+ @mutex.unlock
77
+ end
78
+ end
79
+ end
80
+
81
+ def result
82
+ execute_or_wait
83
+ @event_buffer&.flush
84
+
85
+ if canceled?
86
+ raise Canceled
87
+ elsif @error
88
+ raise @error
89
+ else
90
+ @result
91
+ end
92
+ end
93
+
94
+ def pending?
95
+ @pending && (!@session || @session.active?)
96
+ end
97
+
98
+ private
99
+ def canceled?
100
+ @session && !@session.active?
101
+ end
102
+
103
+ def execute_or_wait
104
+ if pending?
105
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
106
+ @mutex.synchronize do
107
+ if pending?
108
+ execute_query(@pool.connection)
109
+ else
110
+ @lock_wait = (Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - start)
111
+ end
112
+ end
113
+ else
114
+ @lock_wait = 0.0
115
+ end
116
+ end
117
+
118
+ def execute_query(connection, async: false)
119
+ @result = exec_query(connection, *@args, **@kwargs, async: async)
120
+ rescue => error
121
+ @error = error
122
+ ensure
123
+ @pending = false
124
+ end
125
+
126
+ def exec_query(connection, *args, **kwargs)
127
+ connection.exec_query(*args, **kwargs)
128
+ end
129
+
130
+ class SelectAll < FutureResult # :nodoc:
131
+ private
132
+ def exec_query(*, **)
133
+ super
134
+ rescue ::RangeError
135
+ ActiveRecord::Result.empty
136
+ end
137
+ end
138
+ end
139
+ end
@@ -7,9 +7,9 @@ module ActiveRecord
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 5
11
- MINOR = 2
12
- TINY = 8
10
+ MAJOR = 7
11
+ MINOR = 0
12
+ TINY = 2
13
13
  PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/inflector"
3
4
  require "active_support/core_ext/hash/indifferent_access"
4
5
 
5
6
  module ActiveRecord
@@ -38,9 +39,13 @@ module ActiveRecord
38
39
  extend ActiveSupport::Concern
39
40
 
40
41
  included do
42
+ class_attribute :store_full_class_name, instance_writer: false, default: true
43
+
41
44
  # Determines whether to store the full constant name including namespace when using STI.
42
45
  # This is true, by default.
43
46
  class_attribute :store_full_sti_class, instance_writer: false, default: true
47
+
48
+ set_base_class
44
49
  end
45
50
 
46
51
  module ClassMethods
@@ -52,10 +57,14 @@ module ActiveRecord
52
57
  raise NotImplementedError, "#{self} is an abstract class and cannot be instantiated."
53
58
  end
54
59
 
55
- if has_attribute?(inheritance_column)
60
+ if _has_attribute?(inheritance_column)
56
61
  subclass = subclass_from_attributes(attributes)
57
62
 
58
- if subclass.nil? && base_class == self
63
+ if subclass.nil? && scope_attributes = current_scope&.scope_for_create
64
+ subclass = subclass_from_attributes(scope_attributes)
65
+ end
66
+
67
+ if subclass.nil? && base_class?
59
68
  subclass = subclass_from_attributes(column_defaults)
60
69
  end
61
70
  end
@@ -79,7 +88,7 @@ module ActiveRecord
79
88
  end
80
89
  end
81
90
 
82
- def finder_needs_type_condition? #:nodoc:
91
+ def finder_needs_type_condition? # :nodoc:
83
92
  # This is like this because benchmarking justifies the strange :false stuff
84
93
  :true == (@finder_needs_type_condition ||= descends_from_active_record? ? :false : :true)
85
94
  end
@@ -92,16 +101,12 @@ module ActiveRecord
92
101
  #
93
102
  # If B < A and C < B and if A is an abstract_class then both B.base_class
94
103
  # and C.base_class would return B as the answer since A is an abstract_class.
95
- def base_class
96
- unless self < Base
97
- raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
98
- end
104
+ attr_reader :base_class
99
105
 
100
- if superclass == Base || superclass.abstract_class?
101
- self
102
- else
103
- superclass.base_class
104
- end
106
+ # Returns whether the class is a base class.
107
+ # See #base_class for more information.
108
+ def base_class?
109
+ base_class == self
105
110
  end
106
111
 
107
112
  # Set this to +true+ if this is an abstract class (see
@@ -152,31 +157,89 @@ module ActiveRecord
152
157
  defined?(@abstract_class) && @abstract_class == true
153
158
  end
154
159
 
160
+ # Sets the application record class for Active Record
161
+ #
162
+ # This is useful if your application uses a different class than
163
+ # ApplicationRecord for your primary abstract class. This class
164
+ # will share a database connection with Active Record. It is the class
165
+ # that connects to your primary database.
166
+ def primary_abstract_class
167
+ if ActiveRecord.application_record_class && ActiveRecord.application_record_class.name != name
168
+ raise ArgumentError, "The `primary_abstract_class` is already set to #{ActiveRecord.application_record_class.inspect}. There can only be one `primary_abstract_class` in an application."
169
+ end
170
+
171
+ self.abstract_class = true
172
+ ActiveRecord.application_record_class = self
173
+ end
174
+
175
+ # Returns the value to be stored in the inheritance column for STI.
155
176
  def sti_name
156
- store_full_sti_class ? name : name.demodulize
177
+ store_full_sti_class && store_full_class_name ? name : name.demodulize
178
+ end
179
+
180
+ # Returns the class for the provided +type_name+.
181
+ #
182
+ # It is used to find the class correspondent to the value stored in the inheritance column.
183
+ def sti_class_for(type_name)
184
+ if store_full_sti_class && store_full_class_name
185
+ type_name.constantize
186
+ else
187
+ compute_type(type_name)
188
+ end
189
+ rescue NameError
190
+ raise SubclassNotFound,
191
+ "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
192
+ "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
193
+ "Please rename this column if you didn't intend it to be used for storing the inheritance class " \
194
+ "or overwrite #{name}.inheritance_column to use another column for that information."
157
195
  end
158
196
 
197
+ # Returns the value to be stored in the polymorphic type column for Polymorphic Associations.
159
198
  def polymorphic_name
160
- base_class.name
199
+ store_full_class_name ? base_class.name : base_class.name.demodulize
200
+ end
201
+
202
+ # Returns the class for the provided +name+.
203
+ #
204
+ # It is used to find the class correspondent to the value stored in the polymorphic type column.
205
+ def polymorphic_class_for(name)
206
+ if store_full_class_name
207
+ name.constantize
208
+ else
209
+ compute_type(name)
210
+ end
161
211
  end
162
212
 
163
213
  def inherited(subclass)
214
+ subclass.set_base_class
164
215
  subclass.instance_variable_set(:@_type_candidates_cache, Concurrent::Map.new)
165
216
  super
166
217
  end
167
218
 
168
- protected
219
+ def dup # :nodoc:
220
+ # `initialize_dup` / `initialize_copy` don't work when defined
221
+ # in the `singleton_class`.
222
+ other = super
223
+ other.set_base_class
224
+ other
225
+ end
226
+
227
+ def initialize_clone(other) # :nodoc:
228
+ super
229
+ set_base_class
230
+ end
169
231
 
232
+ protected
170
233
  # Returns the class type of the record using the current module as a prefix. So descendants of
171
234
  # MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
172
235
  def compute_type(type_name)
173
- if type_name.start_with?("::".freeze)
236
+ if type_name.start_with?("::")
174
237
  # If the type is prefixed with a scope operator then we assume that
175
238
  # the type_name is an absolute reference.
176
- ActiveSupport::Dependencies.constantize(type_name)
239
+ type_name.constantize
177
240
  else
178
241
  type_candidate = @_type_candidates_cache[type_name]
179
- if type_candidate && type_constant = ActiveSupport::Dependencies.safe_constantize(type_candidate)
242
+ if type_candidate && type_constant = type_candidate.safe_constantize
180
243
  return type_constant
181
244
  end
182
245
 
@@ -186,7 +249,7 @@ module ActiveRecord
186
249
  candidates << type_name
187
250
 
188
251
  candidates.each do |candidate|
189
- constant = ActiveSupport::Dependencies.safe_constantize(candidate)
252
+ constant = candidate.safe_constantize
190
253
  if candidate == constant.to_s
191
254
  @_type_candidates_cache[type_name] = candidate
192
255
  return constant
@@ -197,8 +260,23 @@ module ActiveRecord
197
260
  end
198
261
  end
199
262
 
200
- private
263
+ def set_base_class # :nodoc:
264
+ @base_class = if self == Base
265
+ self
266
+ else
267
+ unless self < Base
268
+ raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
269
+ end
201
270
 
271
+ if superclass == Base || superclass.abstract_class?
272
+ self
273
+ else
274
+ superclass.base_class
275
+ end
276
+ end
277
+ end
278
+
279
+ private
202
280
  # Called by +instantiate+ to decide which class to use for a new
203
281
  # record instance. For single-table inheritance, we check the record
204
282
  # for a +type+ column and return the corresponding class.
@@ -211,35 +289,25 @@ module ActiveRecord
211
289
  end
212
290
 
213
291
  def using_single_table_inheritance?(record)
214
- record[inheritance_column].present? && has_attribute?(inheritance_column)
292
+ record[inheritance_column].present? && _has_attribute?(inheritance_column)
215
293
  end
216
294
 
217
295
  def find_sti_class(type_name)
218
296
  type_name = base_class.type_for_attribute(inheritance_column).cast(type_name)
219
- subclass = begin
220
- if store_full_sti_class
221
- ActiveSupport::Dependencies.constantize(type_name)
222
- else
223
- compute_type(type_name)
224
- end
225
- rescue NameError
226
- raise SubclassNotFound,
227
- "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
228
- "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
229
- "Please rename this column if you didn't intend it to be used for storing the inheritance class " \
230
- "or overwrite #{name}.inheritance_column to use another column for that information."
231
- end
297
+ subclass = sti_class_for(type_name)
298
+
232
299
  unless subclass == self || descendants.include?(subclass)
233
300
  raise SubclassNotFound, "Invalid single-table inheritance type: #{subclass.name} is not a subclass of #{name}"
234
301
  end
302
+
235
303
  subclass
236
304
  end
237
305
 
238
306
  def type_condition(table = arel_table)
239
- sti_column = arel_attribute(inheritance_column, table)
307
+ sti_column = table[inheritance_column]
240
308
  sti_names = ([self] + descendants).map(&:sti_name)
241
309
 
242
- sti_column.in(sti_names)
310
+ predicate_builder.build(sti_column, sti_names)
243
311
  end
244
312
 
245
313
  # Detect the subclass from the inheritance column of attrs. If the inheritance column value
@@ -262,7 +330,6 @@ module ActiveRecord
262
330
  end
263
331
 
264
332
  private
265
-
266
333
  def initialize_internals_callback
267
334
  super
268
335
  ensure_proper_type
@@ -0,0 +1,278 @@
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, :update_only, :returning, :unique_by, :update_sql
9
+
10
+ def initialize(model, inserts, on_duplicate:, update_only: nil, returning: nil, unique_by: nil, record_timestamps: 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, @update_only, @returning, @unique_by = on_duplicate, update_only, returning, unique_by
15
+ @record_timestamps = record_timestamps.nil? ? model.record_timestamps : record_timestamps
16
+
17
+ disallow_raw_sql!(on_duplicate)
18
+ disallow_raw_sql!(returning)
19
+
20
+ configure_on_duplicate_update_logic
21
+
22
+ if model.scope_attributes?
23
+ @scope_attributes = model.scope_attributes
24
+ @keys |= @scope_attributes.keys
25
+ end
26
+ @keys = @keys.to_set
27
+
28
+ @returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
29
+ @returning = false if @returning == []
30
+
31
+ @unique_by = find_unique_index_for(unique_by)
32
+ @on_duplicate = :skip if @on_duplicate == :update && updatable_columns.empty?
33
+
34
+ ensure_valid_options_for_connection!
35
+ end
36
+
37
+ def execute
38
+ message = +"#{model} "
39
+ message << "Bulk " if inserts.many?
40
+ message << (on_duplicate == :update ? "Upsert" : "Insert")
41
+ connection.exec_insert_all to_sql, message
42
+ end
43
+
44
+ def updatable_columns
45
+ @updatable_columns ||= keys - readonly_columns - unique_by_columns
46
+ end
47
+
48
+ def primary_keys
49
+ Array(connection.schema_cache.primary_keys(model.table_name))
50
+ end
51
+
52
+
53
+ def skip_duplicates?
54
+ on_duplicate == :skip
55
+ end
56
+
57
+ def update_duplicates?
58
+ on_duplicate == :update
59
+ end
60
+
61
+ def map_key_with_value
62
+ inserts.map do |attributes|
63
+ attributes = attributes.stringify_keys
64
+ attributes.merge!(scope_attributes) if scope_attributes
65
+ attributes.reverse_merge!(timestamps_for_create) if record_timestamps?
66
+
67
+ verify_attributes(attributes)
68
+
69
+ keys_including_timestamps.map do |key|
70
+ yield key, attributes[key]
71
+ end
72
+ end
73
+ end
74
+
75
+ def record_timestamps?
76
+ @record_timestamps
77
+ end
78
+
79
+ # TODO: Consider remaining this method, as it only conditionally extends keys, not always
80
+ def keys_including_timestamps
81
+ @keys_including_timestamps ||= if record_timestamps?
82
+ keys + model.all_timestamp_attributes_in_model
83
+ else
84
+ keys
85
+ end
86
+ end
87
+
88
+ private
89
+ attr_reader :scope_attributes
90
+
91
+ def configure_on_duplicate_update_logic
92
+ if custom_update_sql_provided? && update_only.present?
93
+ raise ArgumentError, "You can't set :update_only and provide custom update SQL via :on_duplicate at the same time"
94
+ end
95
+
96
+ if update_only.present?
97
+ @updatable_columns = Array(update_only)
98
+ @on_duplicate = :update
99
+ elsif custom_update_sql_provided?
100
+ @update_sql = on_duplicate
101
+ @on_duplicate = :update
102
+ end
103
+ end
104
+
105
+ def custom_update_sql_provided?
106
+ @custom_update_sql_provided ||= Arel.arel_node?(on_duplicate)
107
+ end
108
+
109
+ def find_unique_index_for(unique_by)
110
+ if !connection.supports_insert_conflict_target?
111
+ return if unique_by.nil?
112
+
113
+ raise ArgumentError, "#{connection.class} does not support :unique_by"
114
+ end
115
+
116
+ name_or_columns = unique_by || model.primary_key
117
+ match = Array(name_or_columns).map(&:to_s)
118
+
119
+ if index = unique_indexes.find { |i| match.include?(i.name) || i.columns == match }
120
+ index
121
+ elsif match == primary_keys
122
+ unique_by.nil? ? nil : ActiveRecord::ConnectionAdapters::IndexDefinition.new(model.table_name, "#{model.table_name}_primary_key", true, match)
123
+ else
124
+ raise ArgumentError, "No unique index found for #{name_or_columns}"
125
+ end
126
+ end
127
+
128
+ def unique_indexes
129
+ connection.schema_cache.indexes(model.table_name).select(&:unique)
130
+ end
131
+
132
+
133
+ def ensure_valid_options_for_connection!
134
+ if returning && !connection.supports_insert_returning?
135
+ raise ArgumentError, "#{connection.class} does not support :returning"
136
+ end
137
+
138
+ if skip_duplicates? && !connection.supports_insert_on_duplicate_skip?
139
+ raise ArgumentError, "#{connection.class} does not support skipping duplicates"
140
+ end
141
+
142
+ if update_duplicates? && !connection.supports_insert_on_duplicate_update?
143
+ raise ArgumentError, "#{connection.class} does not support upsert"
144
+ end
145
+
146
+ if unique_by && !connection.supports_insert_conflict_target?
147
+ raise ArgumentError, "#{connection.class} does not support :unique_by"
148
+ end
149
+ end
150
+
151
+
152
+ def to_sql
153
+ connection.build_insert_sql(ActiveRecord::InsertAll::Builder.new(self))
154
+ end
155
+
156
+
157
+ def readonly_columns
158
+ primary_keys + model.readonly_attributes.to_a
159
+ end
160
+
161
+ def unique_by_columns
162
+ Array(unique_by&.columns)
163
+ end
164
+
165
+
166
+ def verify_attributes(attributes)
167
+ if keys_including_timestamps != attributes.keys.to_set
168
+ raise ArgumentError, "All objects being inserted must have the same keys"
169
+ end
170
+ end
171
+
172
+ def disallow_raw_sql!(value)
173
+ return if !value.is_a?(String) || Arel.arel_node?(value)
174
+
175
+ raise ArgumentError, "Dangerous query method (method whose arguments are used as raw " \
176
+ "SQL) called: #{value}. " \
177
+ "Known-safe values can be passed " \
178
+ "by wrapping them in Arel.sql()."
179
+ end
180
+
181
+ def timestamps_for_create
182
+ model.all_timestamp_attributes_in_model.index_with(connection.high_precision_current_timestamp)
183
+ end
184
+
185
+ class Builder # :nodoc:
186
+ attr_reader :model
187
+
188
+ delegate :skip_duplicates?, :update_duplicates?, :keys, :keys_including_timestamps, :record_timestamps?, to: :insert_all
189
+
190
+ def initialize(insert_all)
191
+ @insert_all, @model, @connection = insert_all, insert_all.model, insert_all.connection
192
+ end
193
+
194
+ def into
195
+ "INTO #{model.quoted_table_name} (#{columns_list})"
196
+ end
197
+
198
+ def values_list
199
+ types = extract_types_from_columns_on(model.table_name, keys: keys_including_timestamps)
200
+
201
+ values_list = insert_all.map_key_with_value do |key, value|
202
+ next value if Arel::Nodes::SqlLiteral === value
203
+ connection.with_yaml_fallback(types[key].serialize(value))
204
+ end
205
+
206
+ connection.visitor.compile(Arel::Nodes::ValuesList.new(values_list))
207
+ end
208
+
209
+ def returning
210
+ return unless insert_all.returning
211
+
212
+ if insert_all.returning.is_a?(String)
213
+ insert_all.returning
214
+ else
215
+ format_columns(insert_all.returning)
216
+ end
217
+ end
218
+
219
+ def conflict_target
220
+ if index = insert_all.unique_by
221
+ sql = +"(#{format_columns(index.columns)})"
222
+ sql << " WHERE #{index.where}" if index.where
223
+ sql
224
+ elsif update_duplicates?
225
+ "(#{format_columns(insert_all.primary_keys)})"
226
+ end
227
+ end
228
+
229
+ def updatable_columns
230
+ quote_columns(insert_all.updatable_columns)
231
+ end
232
+
233
+ def touch_model_timestamps_unless(&block)
234
+ return "" unless update_duplicates? && record_timestamps?
235
+
236
+ model.timestamp_attributes_for_update_in_model.filter_map do |column_name|
237
+ if touch_timestamp_attribute?(column_name)
238
+ "#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE #{connection.high_precision_current_timestamp} END),"
239
+ end
240
+ end.join
241
+ end
242
+
243
+ def raw_update_sql
244
+ insert_all.update_sql
245
+ end
246
+
247
+ alias raw_update_sql? raw_update_sql
248
+
249
+ private
250
+ attr_reader :connection, :insert_all
251
+
252
+ def touch_timestamp_attribute?(column_name)
253
+ insert_all.updatable_columns.exclude?(column_name)
254
+ end
255
+
256
+ def columns_list
257
+ format_columns(insert_all.keys_including_timestamps)
258
+ end
259
+
260
+ def extract_types_from_columns_on(table_name, keys:)
261
+ columns = connection.schema_cache.columns_hash(table_name)
262
+
263
+ unknown_column = (keys - columns.keys).first
264
+ raise UnknownAttributeError.new(model.new, unknown_column) if unknown_column
265
+
266
+ keys.index_with { |key| model.type_for_attribute(key) }
267
+ end
268
+
269
+ def format_columns(columns)
270
+ columns.respond_to?(:map) ? quote_columns(columns).join(",") : columns
271
+ end
272
+
273
+ def quote_columns(columns)
274
+ columns.map(&connection.method(:quote_column_name))
275
+ end
276
+ end
277
+ end
278
+ end