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
@@ -4,17 +4,20 @@ require "active_record/connection_adapters/abstract_adapter"
4
4
  require "active_record/connection_adapters/statement_pool"
5
5
  require "active_record/connection_adapters/sqlite3/explain_pretty_printer"
6
6
  require "active_record/connection_adapters/sqlite3/quoting"
7
+ require "active_record/connection_adapters/sqlite3/database_statements"
7
8
  require "active_record/connection_adapters/sqlite3/schema_creation"
8
9
  require "active_record/connection_adapters/sqlite3/schema_definitions"
9
10
  require "active_record/connection_adapters/sqlite3/schema_dumper"
10
11
  require "active_record/connection_adapters/sqlite3/schema_statements"
11
12
 
12
- gem "sqlite3", "~> 1.3", ">= 1.3.6"
13
+ gem "sqlite3", "~> 1.4"
13
14
  require "sqlite3"
14
15
 
15
16
  module ActiveRecord
16
17
  module ConnectionHandling # :nodoc:
17
18
  def sqlite3_connection(config)
19
+ config = config.symbolize_keys
20
+
18
21
  # Require database.
19
22
  unless config[:database]
20
23
  raise ArgumentError, "No database file specified. Missing argument: database"
@@ -23,7 +26,7 @@ module ActiveRecord
23
26
  # Allow database path relative to Rails.root, but only if the database
24
27
  # path is not the special path that tells sqlite to build a database only
25
28
  # in memory.
26
- if ":memory:" != config[:database]
29
+ if ":memory:" != config[:database] && !config[:database].to_s.start_with?("file:")
27
30
  config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root)
28
31
  dirname = File.dirname(config[:database])
29
32
  Dir.mkdir(dirname) unless File.directory?(dirname)
@@ -31,11 +34,9 @@ module ActiveRecord
31
34
 
32
35
  db = SQLite3::Database.new(
33
36
  config[:database].to_s,
34
- results_as_hash: true
37
+ config.merge(results_as_hash: true)
35
38
  )
36
39
 
37
- db.busy_timeout(ConnectionAdapters::SQLite3Adapter.type_cast_config_to_integer(config[:timeout])) if config[:timeout]
38
-
39
40
  ConnectionAdapters::SQLite3Adapter.new(db, logger, nil, config)
40
41
  rescue Errno::ENOENT => error
41
42
  if error.message.include?("No such file or directory")
@@ -46,18 +47,19 @@ module ActiveRecord
46
47
  end
47
48
  end
48
49
 
49
- module ConnectionAdapters #:nodoc:
50
- # The SQLite3 adapter works SQLite 3.6.16 or newer
51
- # with the sqlite3-ruby drivers (available as gem from https://rubygems.org/gems/sqlite3).
50
+ module ConnectionAdapters # :nodoc:
51
+ # The SQLite3 adapter works with the sqlite3-ruby drivers
52
+ # (available as gem from https://rubygems.org/gems/sqlite3).
52
53
  #
53
54
  # Options:
54
55
  #
55
56
  # * <tt>:database</tt> - Path to the database file.
56
57
  class SQLite3Adapter < AbstractAdapter
57
- ADAPTER_NAME = "SQLite".freeze
58
+ ADAPTER_NAME = "SQLite"
58
59
 
59
60
  include SQLite3::Quoting
60
61
  include SQLite3::SchemaStatements
62
+ include SQLite3::DatabaseStatements
61
63
 
62
64
  NATIVE_DATABASE_TYPES = {
63
65
  primary_key: "integer PRIMARY KEY AUTOINCREMENT NOT NULL",
@@ -74,39 +76,29 @@ module ActiveRecord
74
76
  json: { name: "json" },
75
77
  }
76
78
 
77
- ##
78
- # :singleton-method:
79
- # Indicates whether boolean values are stored in sqlite3 databases as 1
80
- # and 0 or 't' and 'f'. Leaving <tt>ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer</tt>
81
- # set to false is deprecated. SQLite databases have used 't' and 'f' to
82
- # serialize boolean values and must have old data converted to 1 and 0
83
- # (its native boolean serialization) before setting this flag to true.
84
- # Conversion can be accomplished by setting up a rake task which runs
85
- #
86
- # ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1)
87
- # ExampleModel.where("boolean_column = 'f'").update_all(boolean_column: 0)
88
- # for all models and all boolean columns, after which the flag must be set
89
- # to true by adding the following to your <tt>application.rb</tt> file:
90
- #
91
- # Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
92
- class_attribute :represent_boolean_as_integer, default: false
93
-
94
79
  class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
95
80
  private
96
81
  def dealloc(stmt)
97
- stmt[:stmt].close unless stmt[:stmt].closed?
82
+ stmt.close unless stmt.closed?
98
83
  end
99
84
  end
100
85
 
101
86
  def initialize(connection, logger, connection_options, config)
87
+ @memory_database = config[:database] == ":memory:"
102
88
  super(connection, logger, config)
103
-
104
- @active = true
105
- @statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
106
-
107
89
  configure_connection
108
90
  end
109
91
 
92
+ def self.database_exists?(config)
93
+ config = config.symbolize_keys
94
+ if config[:database] == ":memory:"
95
+ true
96
+ else
97
+ database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database]
98
+ File.exist?(database_file)
99
+ end
100
+ end
101
+
110
102
  def supports_ddl_transactions?
111
103
  true
112
104
  end
@@ -115,16 +107,28 @@ module ActiveRecord
115
107
  true
116
108
  end
117
109
 
110
+ def supports_transaction_isolation?
111
+ true
112
+ end
113
+
118
114
  def supports_partial_index?
119
- sqlite_version >= "3.8.0"
115
+ true
116
+ end
117
+
118
+ def supports_expression_index?
119
+ database_version >= "3.9.0"
120
120
  end
121
121
 
122
122
  def requires_reloading?
123
123
  true
124
124
  end
125
125
 
126
- def supports_foreign_keys_in_create?
127
- sqlite_version >= "3.6.19"
126
+ def supports_foreign_keys?
127
+ true
128
+ end
129
+
130
+ def supports_check_constraints?
131
+ true
128
132
  end
129
133
 
130
134
  def supports_views?
@@ -139,43 +143,46 @@ module ActiveRecord
139
143
  true
140
144
  end
141
145
 
142
- def supports_multi_insert?
143
- sqlite_version >= "3.7.11"
146
+ def supports_common_table_expressions?
147
+ database_version >= "3.8.3"
148
+ end
149
+
150
+ def supports_insert_on_conflict?
151
+ database_version >= "3.24.0"
152
+ end
153
+ alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
154
+ alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
155
+ alias supports_insert_conflict_target? supports_insert_on_conflict?
156
+
157
+ def supports_concurrent_connections?
158
+ !@memory_database
144
159
  end
145
160
 
146
161
  def active?
147
- @active
162
+ !@connection.closed?
163
+ end
164
+
165
+ def reconnect!
166
+ super
167
+ connect if @connection.closed?
148
168
  end
149
169
 
150
170
  # Disconnects from the database if already connected. Otherwise, this
151
171
  # method does nothing.
152
172
  def disconnect!
153
173
  super
154
- @active = false
155
174
  @connection.close rescue nil
156
175
  end
157
176
 
158
- # Clears the prepared statements cache.
159
- def clear_cache!
160
- @statements.clear
161
- end
162
-
163
177
  def supports_index_sort_order?
164
178
  true
165
179
  end
166
180
 
167
- # Returns 62. SQLite supports index names up to 64
168
- # characters. The rest is used by Rails internally to perform
169
- # temporary rename operations
170
- def allowed_index_name_length
171
- index_name_length - 2
172
- end
173
-
174
- def native_database_types #:nodoc:
181
+ def native_database_types # :nodoc:
175
182
  NATIVE_DATABASE_TYPES
176
183
  end
177
184
 
178
- # Returns the current database encoding format as a string, eg: 'UTF-8'
185
+ # Returns the current database encoding format as a string, e.g. 'UTF-8'
179
186
  def encoding
180
187
  @connection.encoding.to_s
181
188
  end
@@ -184,89 +191,28 @@ module ActiveRecord
184
191
  true
185
192
  end
186
193
 
194
+ def supports_lazy_transactions?
195
+ true
196
+ end
197
+
187
198
  # REFERENTIAL INTEGRITY ====================================
188
199
 
189
200
  def disable_referential_integrity # :nodoc:
190
- old = query_value("PRAGMA foreign_keys")
201
+ old_foreign_keys = query_value("PRAGMA foreign_keys")
202
+ old_defer_foreign_keys = query_value("PRAGMA defer_foreign_keys")
191
203
 
192
204
  begin
205
+ execute("PRAGMA defer_foreign_keys = ON")
193
206
  execute("PRAGMA foreign_keys = OFF")
194
207
  yield
195
208
  ensure
196
- execute("PRAGMA foreign_keys = #{old}")
197
- end
198
- end
199
-
200
- #--
201
- # DATABASE STATEMENTS ======================================
202
- #++
203
-
204
- def explain(arel, binds = [])
205
- sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
206
- SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
207
- end
208
-
209
- def exec_query(sql, name = nil, binds = [], prepare: false)
210
- type_casted_binds = type_casted_binds(binds)
211
-
212
- log(sql, name, binds, type_casted_binds) do
213
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
214
- # Don't cache statements if they are not prepared
215
- unless prepare
216
- stmt = @connection.prepare(sql)
217
- begin
218
- cols = stmt.columns
219
- unless without_prepared_statement?(binds)
220
- stmt.bind_params(type_casted_binds)
221
- end
222
- records = stmt.to_a
223
- ensure
224
- stmt.close
225
- end
226
- else
227
- cache = @statements[sql] ||= {
228
- stmt: @connection.prepare(sql)
229
- }
230
- stmt = cache[:stmt]
231
- cols = cache[:cols] ||= stmt.columns
232
- stmt.reset!
233
- stmt.bind_params(type_casted_binds)
234
- records = stmt.to_a
235
- end
236
-
237
- ActiveRecord::Result.new(cols, records)
238
- end
209
+ execute("PRAGMA defer_foreign_keys = #{old_defer_foreign_keys}")
210
+ execute("PRAGMA foreign_keys = #{old_foreign_keys}")
239
211
  end
240
212
  end
241
213
 
242
- def exec_delete(sql, name = "SQL", binds = [])
243
- exec_query(sql, name, binds)
244
- @connection.changes
245
- end
246
- alias :exec_update :exec_delete
247
-
248
- def last_inserted_id(result)
249
- @connection.last_insert_row_id
250
- end
251
-
252
- def execute(sql, name = nil) #:nodoc:
253
- log(sql, name) do
254
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
255
- @connection.execute(sql)
256
- end
257
- end
258
- end
259
-
260
- def begin_db_transaction #:nodoc:
261
- log("begin transaction", nil) { @connection.transaction }
262
- end
263
-
264
- def commit_db_transaction #:nodoc:
265
- log("commit transaction", nil) { @connection.commit }
266
- end
267
-
268
- def exec_rollback_db_transaction #:nodoc:
269
- log("rollback transaction", nil) { @connection.rollback }
214
+ def all_foreign_keys_valid? # :nodoc:
215
+ execute("PRAGMA foreign_key_check").blank?
270
216
  end
271
217
 
272
218
  # SCHEMA STATEMENTS ========================================
@@ -276,8 +222,11 @@ module ActiveRecord
276
222
  pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
277
223
  end
278
224
 
279
- def remove_index(table_name, options = {}) #:nodoc:
280
- index_name = index_name_for_remove(table_name, options)
225
+ def remove_index(table_name, column_name = nil, **options) # :nodoc:
226
+ return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
227
+
228
+ index_name = index_name_for_remove(table_name, column_name, options)
229
+
281
230
  exec_query "DROP INDEX #{quote_column_name(index_name)}"
282
231
  end
283
232
 
@@ -286,32 +235,40 @@ module ActiveRecord
286
235
  # Example:
287
236
  # rename_table('octopuses', 'octopi')
288
237
  def rename_table(table_name, new_name)
238
+ schema_cache.clear_data_source_cache!(table_name.to_s)
239
+ schema_cache.clear_data_source_cache!(new_name.to_s)
289
240
  exec_query "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
290
241
  rename_table_indexes(table_name, new_name)
291
242
  end
292
243
 
293
- def valid_alter_table_type?(type, options = {})
294
- !invalid_alter_table_type?(type, options)
295
- end
296
- deprecate :valid_alter_table_type?
297
-
298
- def add_column(table_name, column_name, type, options = {}) #:nodoc:
244
+ def add_column(table_name, column_name, type, **options) # :nodoc:
299
245
  if invalid_alter_table_type?(type, options)
300
246
  alter_table(table_name) do |definition|
301
- definition.column(column_name, type, options)
247
+ definition.column(column_name, type, **options)
302
248
  end
303
249
  else
304
250
  super
305
251
  end
306
252
  end
307
253
 
308
- def remove_column(table_name, column_name, type = nil, options = {}) #:nodoc:
254
+ def remove_column(table_name, column_name, type = nil, **options) # :nodoc:
309
255
  alter_table(table_name) do |definition|
310
256
  definition.remove_column column_name
257
+ definition.foreign_keys.delete_if { |fk| fk.column == column_name.to_s }
258
+ end
259
+ end
260
+
261
+ def remove_columns(table_name, *column_names, type: nil, **options) # :nodoc:
262
+ alter_table(table_name) do |definition|
263
+ column_names.each do |column_name|
264
+ definition.remove_column column_name
265
+ end
266
+ column_names = column_names.map(&:to_s)
267
+ definition.foreign_keys.delete_if { |fk| column_names.include?(fk.column) }
311
268
  end
312
269
  end
313
270
 
314
- def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
271
+ def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
315
272
  default = extract_new_default_value(default_or_changes)
316
273
 
317
274
  alter_table(table_name) do |definition|
@@ -319,7 +276,7 @@ module ActiveRecord
319
276
  end
320
277
  end
321
278
 
322
- def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
279
+ def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
323
280
  unless null || default.nil?
324
281
  exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
325
282
  end
@@ -328,21 +285,16 @@ module ActiveRecord
328
285
  end
329
286
  end
330
287
 
331
- def change_column(table_name, column_name, type, options = {}) #:nodoc:
288
+ def change_column(table_name, column_name, type, **options) # :nodoc:
332
289
  alter_table(table_name) do |definition|
333
290
  definition[column_name].instance_eval do
334
- self.type = type
335
- self.limit = options[:limit] if options.include?(:limit)
336
- self.default = options[:default] if options.include?(:default)
337
- self.null = options[:null] if options.include?(:null)
338
- self.precision = options[:precision] if options.include?(:precision)
339
- self.scale = options[:scale] if options.include?(:scale)
340
- self.collation = options[:collation] if options.include?(:collation)
291
+ self.type = aliased_types(type.to_s, type)
292
+ self.options.merge!(options)
341
293
  end
342
294
  end
343
295
  end
344
296
 
345
- def rename_column(table_name, column_name, new_column_name) #:nodoc:
297
+ def rename_column(table_name, column_name, new_column_name) # :nodoc:
346
298
  column = column_for(table_name, column_name)
347
299
  alter_table(table_name, rename: { column.name => new_column_name.to_s })
348
300
  rename_column_indexes(table_name, column.name, new_column_name)
@@ -366,30 +318,68 @@ module ActiveRecord
366
318
  end
367
319
  end
368
320
 
369
- def insert_fixtures(rows, table_name)
370
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
371
- `insert_fixtures` is deprecated and will be removed in the next version of Rails.
372
- Consider using `insert_fixtures_set` for performance improvement.
373
- MSG
374
- insert_fixtures_set(table_name => rows)
321
+ def build_insert_sql(insert) # :nodoc:
322
+ sql = +"INSERT #{insert.into} #{insert.values_list}"
323
+
324
+ if insert.skip_duplicates?
325
+ sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
326
+ elsif insert.update_duplicates?
327
+ sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
328
+ if insert.raw_update_sql?
329
+ sql << insert.raw_update_sql
330
+ else
331
+ sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
332
+ sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
333
+ end
334
+ end
335
+
336
+ sql
375
337
  end
376
338
 
377
- def insert_fixtures_set(fixture_set, tables_to_delete = [])
378
- disable_referential_integrity do
379
- transaction(requires_new: true) do
380
- tables_to_delete.each { |table| delete "DELETE FROM #{quote_table_name(table)}", "Fixture Delete" }
339
+ def shared_cache? # :nodoc:
340
+ @config.fetch(:flags, 0).anybits?(::SQLite3::Constants::Open::SHAREDCACHE)
341
+ end
381
342
 
382
- fixture_set.each do |table_name, rows|
383
- rows.each { |row| insert_fixture(row, table_name) }
384
- end
385
- end
343
+ def get_database_version # :nodoc:
344
+ SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
345
+ end
346
+
347
+ def check_version # :nodoc:
348
+ if database_version < "3.8.0"
349
+ raise "Your version of SQLite (#{database_version}) is too old. Active Record supports SQLite >= 3.8."
386
350
  end
387
351
  end
388
352
 
353
+ class SQLite3Integer < Type::Integer # :nodoc:
354
+ private
355
+ def _limit
356
+ # INTEGER storage class can be stored 8 bytes value.
357
+ # See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
358
+ limit || 8
359
+ end
360
+ end
361
+
362
+ ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
363
+
364
+ class << self
365
+ private
366
+ def initialize_type_map(m)
367
+ super
368
+ register_class_with_limit m, %r(int)i, SQLite3Integer
369
+ end
370
+ end
371
+
372
+ TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
373
+
389
374
  private
390
- def initialize_type_map(m = type_map)
391
- super
392
- register_class_with_limit m, %r(int)i, SQLite3Integer
375
+ def type_map
376
+ TYPE_MAP
377
+ end
378
+
379
+ # See https://www.sqlite.org/limits.html,
380
+ # the default value is 999 when not configured.
381
+ def bind_params_length
382
+ 999
393
383
  end
394
384
 
395
385
  def table_structure(table_name)
@@ -399,20 +389,71 @@ module ActiveRecord
399
389
  end
400
390
  alias column_definitions table_structure
401
391
 
392
+ def extract_value_from_default(default)
393
+ case default
394
+ when /^null$/i
395
+ nil
396
+ # Quoted types
397
+ when /^'(.*)'$/m
398
+ $1.gsub("''", "'")
399
+ # Quoted types
400
+ when /^"(.*)"$/m
401
+ $1.gsub('""', '"')
402
+ # Numeric types
403
+ when /\A-?\d+(\.\d*)?\z/
404
+ $&
405
+ else
406
+ # Anything else is blank or some function
407
+ # and we can't know the value of that, so return nil.
408
+ nil
409
+ end
410
+ end
411
+
412
+ def extract_default_function(default_value, default)
413
+ default if has_default_function?(default_value, default)
414
+ end
415
+
416
+ def has_default_function?(default_value, default)
417
+ !default_value && %r{\w+\(.*\)|CURRENT_TIME|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
418
+ end
419
+
402
420
  # See: https://www.sqlite.org/lang_altertable.html
403
421
  # SQLite has an additional restriction on the ALTER TABLE statement
404
422
  def invalid_alter_table_type?(type, options)
405
- type.to_sym == :primary_key || options[:primary_key]
423
+ type.to_sym == :primary_key || options[:primary_key] ||
424
+ options[:null] == false && options[:default].nil?
406
425
  end
407
426
 
408
- def alter_table(table_name, options = {})
427
+ def alter_table(
428
+ table_name,
429
+ foreign_keys = foreign_keys(table_name),
430
+ check_constraints = check_constraints(table_name),
431
+ **options
432
+ )
409
433
  altered_table_name = "a#{table_name}"
410
- caller = lambda { |definition| yield definition if block_given? }
434
+
435
+ caller = lambda do |definition|
436
+ rename = options[:rename] || {}
437
+ foreign_keys.each do |fk|
438
+ if column = rename[fk.options[:column]]
439
+ fk.options[:column] = column
440
+ end
441
+ to_table = strip_table_name_prefix_and_suffix(fk.to_table)
442
+ definition.foreign_key(to_table, **fk.options)
443
+ end
444
+
445
+ check_constraints.each do |chk|
446
+ definition.check_constraint(chk.expression, **chk.options)
447
+ end
448
+
449
+ yield definition if block_given?
450
+ end
411
451
 
412
452
  transaction do
413
- move_table(table_name, altered_table_name,
414
- options.merge(temporary: true))
415
- move_table(altered_table_name, table_name, &caller)
453
+ disable_referential_integrity do
454
+ move_table(table_name, altered_table_name, options.merge(temporary: true))
455
+ move_table(altered_table_name, table_name, &caller)
456
+ end
416
457
  end
417
458
  end
418
459
 
@@ -424,11 +465,12 @@ module ActiveRecord
424
465
  def copy_table(from, to, options = {})
425
466
  from_primary_key = primary_key(from)
426
467
  options[:id] = false
427
- create_table(to, options) do |definition|
468
+ create_table(to, **options) do |definition|
428
469
  @definition = definition
429
470
  if from_primary_key.is_a?(Array)
430
471
  @definition.primary_keys from_primary_key
431
472
  end
473
+
432
474
  columns(from).each do |column|
433
475
  column_name = options[:rename] ?
434
476
  (options[:rename][column.name] ||
@@ -442,6 +484,7 @@ module ActiveRecord
442
484
  primary_key: column_name == from_primary_key
443
485
  )
444
486
  end
487
+
445
488
  yield @definition if block_given?
446
489
  end
447
490
  copy_table_indexes(from, to, options[:rename] || {})
@@ -459,17 +502,21 @@ module ActiveRecord
459
502
  name = name[1..-1]
460
503
  end
461
504
 
462
- to_column_names = columns(to).map(&:name)
463
- columns = index.columns.map { |c| rename[c] || c }.select do |column|
464
- to_column_names.include?(column)
505
+ columns = index.columns
506
+ if columns.is_a?(Array)
507
+ to_column_names = columns(to).map(&:name)
508
+ columns = columns.map { |c| rename[c] || c }.select do |column|
509
+ to_column_names.include?(column)
510
+ end
465
511
  end
466
512
 
467
513
  unless columns.empty?
468
514
  # index name can't be the same
469
- opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
470
- opts[:unique] = true if index.unique
471
- opts[:where] = index.where if index.where
472
- add_index(to, columns, opts)
515
+ options = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
516
+ options[:unique] = true if index.unique
517
+ options[:where] = index.where if index.where
518
+ options[:order] = index.orders if index.orders
519
+ add_index(to, columns, **options)
473
520
  end
474
521
  end
475
522
  end
@@ -487,32 +534,29 @@ module ActiveRecord
487
534
  SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
488
535
  end
489
536
 
490
- def sqlite_version
491
- @sqlite_version ||= SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
492
- end
493
-
494
- def translate_exception(exception, message)
495
- case exception.message
537
+ def translate_exception(exception, message:, sql:, binds:)
496
538
  # SQLite 3.8.2 returns a newly formatted error message:
497
539
  # UNIQUE constraint failed: *table_name*.*column_name*
498
540
  # Older versions of SQLite return:
499
541
  # column *column_name* is not unique
500
- when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
501
- RecordNotUnique.new(message)
502
- when /.* may not be NULL/, /NOT NULL constraint failed: .*/
503
- NotNullViolation.new(message)
504
- when /FOREIGN KEY constraint failed/i
505
- InvalidForeignKey.new(message)
542
+ if exception.message.match?(/(column(s)? .* (is|are) not unique|UNIQUE constraint failed: .*)/i)
543
+ RecordNotUnique.new(message, sql: sql, binds: binds)
544
+ elsif exception.message.match?(/(.* may not be NULL|NOT NULL constraint failed: .*)/i)
545
+ NotNullViolation.new(message, sql: sql, binds: binds)
546
+ elsif exception.message.match?(/FOREIGN KEY constraint failed/i)
547
+ InvalidForeignKey.new(message, sql: sql, binds: binds)
548
+ elsif exception.message.match?(/called on a closed database/i)
549
+ ConnectionNotEstablished.new(exception)
506
550
  else
507
551
  super
508
552
  end
509
553
  end
510
554
 
511
- COLLATE_REGEX = /.*\"(\w+)\".*collate\s+\"(\w+)\".*/i.freeze
555
+ COLLATE_REGEX = /.*"(\w+)".*collate\s+"(\w+)".*/i.freeze
512
556
 
513
557
  def table_structure_with_collation(table_name, basic_structure)
514
558
  collation_hash = {}
515
- sql = <<-SQL
559
+ sql = <<~SQL
516
560
  SELECT sql FROM
517
561
  (SELECT * FROM sqlite_master UNION ALL
518
562
  SELECT * FROM sqlite_temp_master)
@@ -522,12 +566,12 @@ module ActiveRecord
522
566
  # Result will have following sample string
523
567
  # CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
524
568
  # "password_digest" varchar COLLATE "NOCASE");
525
- result = exec_query(sql, "SCHEMA").first
569
+ result = query_value(sql, "SCHEMA")
526
570
 
527
571
  if result
528
572
  # Splitting with left parentheses and discarding the first part will return all
529
573
  # columns separated with comma(,).
530
- columns_string = result["sql"].split("(", 2).last
574
+ columns_string = result.split("(", 2).last
531
575
 
532
576
  columns_string.split(",").each do |column_string|
533
577
  # This regex will match the column name and collation type and will save
@@ -535,7 +579,7 @@ module ActiveRecord
535
579
  collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string
536
580
  end
537
581
 
538
- basic_structure.map! do |column|
582
+ basic_structure.map do |column|
539
583
  column_name = column["name"]
540
584
 
541
585
  if collation_hash.has_key? column_name
@@ -545,7 +589,7 @@ module ActiveRecord
545
589
  column
546
590
  end
547
591
  else
548
- basic_structure.to_hash
592
+ basic_structure.to_a
549
593
  end
550
594
  end
551
595
 
@@ -553,20 +597,23 @@ module ActiveRecord
553
597
  Arel::Visitors::SQLite.new(self)
554
598
  end
555
599
 
556
- def configure_connection
557
- execute("PRAGMA foreign_keys = ON", "SCHEMA")
600
+ def build_statement_pool
601
+ StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
558
602
  end
559
603
 
560
- class SQLite3Integer < Type::Integer # :nodoc:
561
- private
562
- def _limit
563
- # INTEGER storage class can be stored 8 bytes value.
564
- # See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
565
- limit || 8
566
- end
604
+ def connect
605
+ @connection = ::SQLite3::Database.new(
606
+ @config[:database].to_s,
607
+ @config.merge(results_as_hash: true)
608
+ )
609
+ configure_connection
567
610
  end
568
611
 
569
- ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
612
+ def configure_connection
613
+ @connection.busy_timeout(self.class.type_cast_config_to_integer(@config[:timeout])) if @config[:timeout]
614
+
615
+ execute("PRAGMA foreign_keys = ON", "SCHEMA")
616
+ end
570
617
  end
571
618
  ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
572
619
  end