activerecord 5.0.6 → 6.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (358) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +638 -2023
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +8 -6
  5. data/examples/performance.rb +31 -29
  6. data/examples/simple.rb +5 -3
  7. data/lib/active_record/aggregations.rb +249 -246
  8. data/lib/active_record/association_relation.rb +24 -13
  9. data/lib/active_record/associations/alias_tracker.rb +24 -33
  10. data/lib/active_record/associations/association.rb +119 -56
  11. data/lib/active_record/associations/association_scope.rb +94 -94
  12. data/lib/active_record/associations/belongs_to_association.rb +58 -42
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  14. data/lib/active_record/associations/builder/association.rb +18 -25
  15. data/lib/active_record/associations/builder/belongs_to.rb +43 -54
  16. data/lib/active_record/associations/builder/collection_association.rb +7 -18
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +42 -61
  18. data/lib/active_record/associations/builder/has_many.rb +4 -0
  19. data/lib/active_record/associations/builder/has_one.rb +37 -1
  20. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  21. data/lib/active_record/associations/collection_association.rb +80 -252
  22. data/lib/active_record/associations/collection_proxy.rb +158 -121
  23. data/lib/active_record/associations/foreign_association.rb +9 -0
  24. data/lib/active_record/associations/has_many_association.rb +23 -29
  25. data/lib/active_record/associations/has_many_through_association.rb +58 -44
  26. data/lib/active_record/associations/has_one_association.rb +59 -54
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +38 -90
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  31. data/lib/active_record/associations/join_dependency.rb +134 -176
  32. data/lib/active_record/associations/preloader/association.rb +84 -125
  33. data/lib/active_record/associations/preloader/through_association.rb +82 -75
  34. data/lib/active_record/associations/preloader.rb +90 -102
  35. data/lib/active_record/associations/singular_association.rb +12 -45
  36. data/lib/active_record/associations/through_association.rb +26 -14
  37. data/lib/active_record/associations.rb +1603 -1592
  38. data/lib/active_record/attribute_assignment.rb +54 -60
  39. data/lib/active_record/attribute_decorators.rb +38 -15
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +12 -7
  41. data/lib/active_record/attribute_methods/dirty.rb +179 -109
  42. data/lib/active_record/attribute_methods/primary_key.rb +86 -91
  43. data/lib/active_record/attribute_methods/query.rb +4 -3
  44. data/lib/active_record/attribute_methods/read.rb +21 -49
  45. data/lib/active_record/attribute_methods/serialization.rb +30 -7
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -64
  47. data/lib/active_record/attribute_methods/write.rb +35 -33
  48. data/lib/active_record/attribute_methods.rb +66 -106
  49. data/lib/active_record/attributes.rb +38 -24
  50. data/lib/active_record/autosave_association.rb +53 -32
  51. data/lib/active_record/base.rb +27 -24
  52. data/lib/active_record/callbacks.rb +63 -33
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +11 -11
  55. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +553 -321
  56. data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
  57. data/lib/active_record/connection_adapters/abstract/database_statements.rb +213 -94
  58. data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -28
  59. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -75
  60. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  61. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -27
  62. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -126
  63. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
  64. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +369 -199
  65. data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
  66. data/lib/active_record/connection_adapters/abstract_adapter.rb +363 -202
  67. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +405 -551
  68. data/lib/active_record/connection_adapters/column.rb +41 -13
  69. data/lib/active_record/connection_adapters/connection_specification.rb +172 -138
  70. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -4
  71. data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +143 -49
  73. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -22
  74. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
  75. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +50 -45
  76. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +58 -56
  77. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
  78. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  79. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
  80. data/lib/active_record/connection_adapters/mysql2_adapter.rb +49 -30
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +22 -7
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +60 -54
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -10
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +4 -2
  91. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -17
  94. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  96. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
  98. data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +31 -9
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +34 -30
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  102. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +9 -4
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +24 -21
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +95 -35
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +35 -32
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +380 -300
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +10 -6
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +382 -275
  116. data/lib/active_record/connection_adapters/schema_cache.rb +46 -12
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +13 -8
  118. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +74 -19
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +3 -8
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +254 -262
  126. data/lib/active_record/connection_adapters/statement_pool.rb +9 -7
  127. data/lib/active_record/connection_handling.rb +159 -40
  128. data/lib/active_record/core.rb +202 -162
  129. data/lib/active_record/counter_cache.rb +57 -28
  130. data/lib/active_record/database_configurations/database_config.rb +37 -0
  131. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  132. data/lib/active_record/database_configurations/url_config.rb +79 -0
  133. data/lib/active_record/database_configurations.rb +233 -0
  134. data/lib/active_record/define_callbacks.rb +22 -0
  135. data/lib/active_record/dynamic_matchers.rb +87 -86
  136. data/lib/active_record/enum.rb +60 -23
  137. data/lib/active_record/errors.rb +114 -18
  138. data/lib/active_record/explain.rb +4 -3
  139. data/lib/active_record/explain_registry.rb +3 -1
  140. data/lib/active_record/explain_subscriber.rb +9 -4
  141. data/lib/active_record/fixture_set/file.rb +13 -8
  142. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  143. data/lib/active_record/fixture_set/render_context.rb +17 -0
  144. data/lib/active_record/fixture_set/table_row.rb +153 -0
  145. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  146. data/lib/active_record/fixtures.rb +195 -502
  147. data/lib/active_record/gem_version.rb +4 -2
  148. data/lib/active_record/inheritance.rb +151 -97
  149. data/lib/active_record/insert_all.rb +179 -0
  150. data/lib/active_record/integration.rb +116 -25
  151. data/lib/active_record/internal_metadata.rb +15 -18
  152. data/lib/active_record/legacy_yaml_adapter.rb +4 -2
  153. data/lib/active_record/locking/optimistic.rb +78 -87
  154. data/lib/active_record/locking/pessimistic.rb +18 -6
  155. data/lib/active_record/log_subscriber.rb +48 -29
  156. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  157. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  158. data/lib/active_record/middleware/database_selector.rb +75 -0
  159. data/lib/active_record/migration/command_recorder.rb +143 -97
  160. data/lib/active_record/migration/compatibility.rb +174 -56
  161. data/lib/active_record/migration/join_table.rb +8 -6
  162. data/lib/active_record/migration.rb +367 -300
  163. data/lib/active_record/model_schema.rb +145 -139
  164. data/lib/active_record/nested_attributes.rb +214 -201
  165. data/lib/active_record/no_touching.rb +10 -1
  166. data/lib/active_record/null_relation.rb +13 -34
  167. data/lib/active_record/persistence.rb +442 -72
  168. data/lib/active_record/query_cache.rb +15 -14
  169. data/lib/active_record/querying.rb +36 -23
  170. data/lib/active_record/railtie.rb +128 -36
  171. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  172. data/lib/active_record/railties/console_sandbox.rb +2 -0
  173. data/lib/active_record/railties/controller_runtime.rb +34 -33
  174. data/lib/active_record/railties/databases.rake +309 -177
  175. data/lib/active_record/readonly_attributes.rb +5 -4
  176. data/lib/active_record/reflection.rb +211 -249
  177. data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
  178. data/lib/active_record/relation/batches.rb +99 -52
  179. data/lib/active_record/relation/calculations.rb +211 -172
  180. data/lib/active_record/relation/delegation.rb +67 -65
  181. data/lib/active_record/relation/finder_methods.rb +208 -247
  182. data/lib/active_record/relation/from_clause.rb +2 -8
  183. data/lib/active_record/relation/merger.rb +78 -61
  184. data/lib/active_record/relation/predicate_builder/array_handler.rb +20 -14
  185. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  186. data/lib/active_record/relation/predicate_builder/base_handler.rb +4 -3
  187. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
  188. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  189. data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
  190. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  191. data/lib/active_record/relation/predicate_builder.rb +86 -104
  192. data/lib/active_record/relation/query_attribute.rb +33 -2
  193. data/lib/active_record/relation/query_methods.rb +458 -329
  194. data/lib/active_record/relation/record_fetch_warning.rb +5 -3
  195. data/lib/active_record/relation/spawn_methods.rb +8 -7
  196. data/lib/active_record/relation/where_clause.rb +111 -95
  197. data/lib/active_record/relation/where_clause_factory.rb +6 -11
  198. data/lib/active_record/relation.rb +429 -318
  199. data/lib/active_record/result.rb +69 -39
  200. data/lib/active_record/runtime_registry.rb +5 -3
  201. data/lib/active_record/sanitization.rb +83 -99
  202. data/lib/active_record/schema.rb +7 -14
  203. data/lib/active_record/schema_dumper.rb +71 -69
  204. data/lib/active_record/schema_migration.rb +15 -5
  205. data/lib/active_record/scoping/default.rb +93 -95
  206. data/lib/active_record/scoping/named.rb +45 -25
  207. data/lib/active_record/scoping.rb +20 -19
  208. data/lib/active_record/secure_token.rb +4 -2
  209. data/lib/active_record/serialization.rb +2 -0
  210. data/lib/active_record/statement_cache.rb +63 -28
  211. data/lib/active_record/store.rb +121 -41
  212. data/lib/active_record/suppressor.rb +4 -1
  213. data/lib/active_record/table_metadata.rb +26 -20
  214. data/lib/active_record/tasks/database_tasks.rb +276 -85
  215. data/lib/active_record/tasks/mysql_database_tasks.rb +54 -90
  216. data/lib/active_record/tasks/postgresql_database_tasks.rb +78 -47
  217. data/lib/active_record/tasks/sqlite_database_tasks.rb +34 -16
  218. data/lib/active_record/test_databases.rb +23 -0
  219. data/lib/active_record/test_fixtures.rb +224 -0
  220. data/lib/active_record/timestamp.rb +70 -35
  221. data/lib/active_record/touch_later.rb +7 -4
  222. data/lib/active_record/transactions.rb +133 -149
  223. data/lib/active_record/translation.rb +3 -1
  224. data/lib/active_record/type/adapter_specific_registry.rb +44 -45
  225. data/lib/active_record/type/date.rb +2 -0
  226. data/lib/active_record/type/date_time.rb +2 -0
  227. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  228. data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
  229. data/lib/active_record/type/internal/timezone.rb +2 -0
  230. data/lib/active_record/type/json.rb +30 -0
  231. data/lib/active_record/type/serialized.rb +16 -8
  232. data/lib/active_record/type/text.rb +11 -0
  233. data/lib/active_record/type/time.rb +2 -1
  234. data/lib/active_record/type/type_map.rb +13 -15
  235. data/lib/active_record/type/unsigned_integer.rb +17 -0
  236. data/lib/active_record/type.rb +23 -17
  237. data/lib/active_record/type_caster/connection.rb +17 -12
  238. data/lib/active_record/type_caster/map.rb +5 -4
  239. data/lib/active_record/type_caster.rb +4 -2
  240. data/lib/active_record/validations/absence.rb +2 -0
  241. data/lib/active_record/validations/associated.rb +3 -1
  242. data/lib/active_record/validations/length.rb +2 -0
  243. data/lib/active_record/validations/presence.rb +4 -2
  244. data/lib/active_record/validations/uniqueness.rb +29 -42
  245. data/lib/active_record/validations.rb +7 -4
  246. data/lib/active_record/version.rb +3 -1
  247. data/lib/active_record.rb +36 -22
  248. data/lib/arel/alias_predication.rb +9 -0
  249. data/lib/arel/attributes/attribute.rb +37 -0
  250. data/lib/arel/attributes.rb +22 -0
  251. data/lib/arel/collectors/bind.rb +24 -0
  252. data/lib/arel/collectors/composite.rb +31 -0
  253. data/lib/arel/collectors/plain_string.rb +20 -0
  254. data/lib/arel/collectors/sql_string.rb +20 -0
  255. data/lib/arel/collectors/substitute_binds.rb +28 -0
  256. data/lib/arel/crud.rb +42 -0
  257. data/lib/arel/delete_manager.rb +18 -0
  258. data/lib/arel/errors.rb +9 -0
  259. data/lib/arel/expressions.rb +29 -0
  260. data/lib/arel/factory_methods.rb +49 -0
  261. data/lib/arel/insert_manager.rb +49 -0
  262. data/lib/arel/math.rb +45 -0
  263. data/lib/arel/nodes/and.rb +32 -0
  264. data/lib/arel/nodes/ascending.rb +23 -0
  265. data/lib/arel/nodes/binary.rb +52 -0
  266. data/lib/arel/nodes/bind_param.rb +36 -0
  267. data/lib/arel/nodes/case.rb +55 -0
  268. data/lib/arel/nodes/casted.rb +50 -0
  269. data/lib/arel/nodes/comment.rb +29 -0
  270. data/lib/arel/nodes/count.rb +12 -0
  271. data/lib/arel/nodes/delete_statement.rb +45 -0
  272. data/lib/arel/nodes/descending.rb +23 -0
  273. data/lib/arel/nodes/equality.rb +18 -0
  274. data/lib/arel/nodes/extract.rb +24 -0
  275. data/lib/arel/nodes/false.rb +16 -0
  276. data/lib/arel/nodes/full_outer_join.rb +8 -0
  277. data/lib/arel/nodes/function.rb +44 -0
  278. data/lib/arel/nodes/grouping.rb +8 -0
  279. data/lib/arel/nodes/in.rb +8 -0
  280. data/lib/arel/nodes/infix_operation.rb +80 -0
  281. data/lib/arel/nodes/inner_join.rb +8 -0
  282. data/lib/arel/nodes/insert_statement.rb +37 -0
  283. data/lib/arel/nodes/join_source.rb +20 -0
  284. data/lib/arel/nodes/matches.rb +18 -0
  285. data/lib/arel/nodes/named_function.rb +23 -0
  286. data/lib/arel/nodes/node.rb +50 -0
  287. data/lib/arel/nodes/node_expression.rb +13 -0
  288. data/lib/arel/nodes/outer_join.rb +8 -0
  289. data/lib/arel/nodes/over.rb +15 -0
  290. data/lib/arel/nodes/regexp.rb +16 -0
  291. data/lib/arel/nodes/right_outer_join.rb +8 -0
  292. data/lib/arel/nodes/select_core.rb +67 -0
  293. data/lib/arel/nodes/select_statement.rb +41 -0
  294. data/lib/arel/nodes/sql_literal.rb +16 -0
  295. data/lib/arel/nodes/string_join.rb +11 -0
  296. data/lib/arel/nodes/table_alias.rb +27 -0
  297. data/lib/arel/nodes/terminal.rb +16 -0
  298. data/lib/arel/nodes/true.rb +16 -0
  299. data/lib/arel/nodes/unary.rb +45 -0
  300. data/lib/arel/nodes/unary_operation.rb +20 -0
  301. data/lib/arel/nodes/unqualified_column.rb +22 -0
  302. data/lib/arel/nodes/update_statement.rb +41 -0
  303. data/lib/arel/nodes/values_list.rb +9 -0
  304. data/lib/arel/nodes/window.rb +126 -0
  305. data/lib/arel/nodes/with.rb +11 -0
  306. data/lib/arel/nodes.rb +68 -0
  307. data/lib/arel/order_predications.rb +13 -0
  308. data/lib/arel/predications.rb +257 -0
  309. data/lib/arel/select_manager.rb +271 -0
  310. data/lib/arel/table.rb +110 -0
  311. data/lib/arel/tree_manager.rb +72 -0
  312. data/lib/arel/update_manager.rb +34 -0
  313. data/lib/arel/visitors/depth_first.rb +204 -0
  314. data/lib/arel/visitors/dot.rb +297 -0
  315. data/lib/arel/visitors/ibm_db.rb +34 -0
  316. data/lib/arel/visitors/informix.rb +62 -0
  317. data/lib/arel/visitors/mssql.rb +157 -0
  318. data/lib/arel/visitors/mysql.rb +83 -0
  319. data/lib/arel/visitors/oracle.rb +159 -0
  320. data/lib/arel/visitors/oracle12.rb +66 -0
  321. data/lib/arel/visitors/postgresql.rb +110 -0
  322. data/lib/arel/visitors/sqlite.rb +39 -0
  323. data/lib/arel/visitors/to_sql.rb +889 -0
  324. data/lib/arel/visitors/visitor.rb +46 -0
  325. data/lib/arel/visitors/where_sql.rb +23 -0
  326. data/lib/arel/visitors.rb +20 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/arel.rb +58 -0
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  330. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  331. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -35
  332. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +1 -1
  333. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +4 -2
  334. data/lib/rails/generators/active_record/migration.rb +17 -2
  335. data/lib/rails/generators/active_record/model/model_generator.rb +9 -29
  336. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
  337. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  338. data/lib/rails/generators/active_record.rb +7 -5
  339. metadata +133 -50
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  342. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  343. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  344. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -20
  347. data/lib/active_record/attribute/user_provided_default.rb +0 -28
  348. data/lib/active_record/attribute.rb +0 -213
  349. data/lib/active_record/attribute_mutation_tracker.rb +0 -70
  350. data/lib/active_record/attribute_set/builder.rb +0 -130
  351. data/lib/active_record/attribute_set.rb +0 -110
  352. data/lib/active_record/collection_cache_key.rb +0 -50
  353. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
  354. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  355. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  356. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
  357. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
  358. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,15 +1,23 @@
1
- require 'active_record/connection_adapters/abstract_adapter'
2
- require 'active_record/connection_adapters/statement_pool'
3
- require 'active_record/connection_adapters/sqlite3/explain_pretty_printer'
4
- require 'active_record/connection_adapters/sqlite3/quoting'
5
- require 'active_record/connection_adapters/sqlite3/schema_creation'
1
+ # frozen_string_literal: true
6
2
 
7
- gem 'sqlite3', '~> 1.3.6'
8
- require 'sqlite3'
3
+ require "active_record/connection_adapters/abstract_adapter"
4
+ require "active_record/connection_adapters/statement_pool"
5
+ require "active_record/connection_adapters/sqlite3/explain_pretty_printer"
6
+ require "active_record/connection_adapters/sqlite3/quoting"
7
+ require "active_record/connection_adapters/sqlite3/database_statements"
8
+ require "active_record/connection_adapters/sqlite3/schema_creation"
9
+ require "active_record/connection_adapters/sqlite3/schema_definitions"
10
+ require "active_record/connection_adapters/sqlite3/schema_dumper"
11
+ require "active_record/connection_adapters/sqlite3/schema_statements"
12
+
13
+ gem "sqlite3", "~> 1.4"
14
+ require "sqlite3"
9
15
 
10
16
  module ActiveRecord
11
17
  module ConnectionHandling # :nodoc:
12
18
  def sqlite3_connection(config)
19
+ config = config.symbolize_keys
20
+
13
21
  # Require database.
14
22
  unless config[:database]
15
23
  raise ArgumentError, "No database file specified. Missing argument: database"
@@ -18,7 +26,7 @@ module ActiveRecord
18
26
  # Allow database path relative to Rails.root, but only if the database
19
27
  # path is not the special path that tells sqlite to build a database only
20
28
  # in memory.
21
- if ':memory:' != config[:database]
29
+ if ":memory:" != config[:database]
22
30
  config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root)
23
31
  dirname = File.dirname(config[:database])
24
32
  Dir.mkdir(dirname) unless File.directory?(dirname)
@@ -26,11 +34,9 @@ module ActiveRecord
26
34
 
27
35
  db = SQLite3::Database.new(
28
36
  config[:database].to_s,
29
- :results_as_hash => true
37
+ config.merge(results_as_hash: true)
30
38
  )
31
39
 
32
- db.busy_timeout(ConnectionAdapters::SQLite3Adapter.type_cast_config_to_integer(config[:timeout])) if config[:timeout]
33
-
34
40
  ConnectionAdapters::SQLite3Adapter.new(db, logger, nil, config)
35
41
  rescue Errno::ENOENT => error
36
42
  if error.message.include?("No such file or directory")
@@ -49,12 +55,14 @@ module ActiveRecord
49
55
  #
50
56
  # * <tt>:database</tt> - Path to the database file.
51
57
  class SQLite3Adapter < AbstractAdapter
52
- ADAPTER_NAME = 'SQLite'.freeze
58
+ ADAPTER_NAME = "SQLite"
53
59
 
54
60
  include SQLite3::Quoting
61
+ include SQLite3::SchemaStatements
62
+ include SQLite3::DatabaseStatements
55
63
 
56
64
  NATIVE_DATABASE_TYPES = {
57
- primary_key: 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL',
65
+ primary_key: "integer PRIMARY KEY AUTOINCREMENT NOT NULL",
58
66
  string: { name: "varchar" },
59
67
  text: { name: "text" },
60
68
  integer: { name: "integer" },
@@ -64,30 +72,40 @@ module ActiveRecord
64
72
  time: { name: "time" },
65
73
  date: { name: "date" },
66
74
  binary: { name: "blob" },
67
- boolean: { name: "boolean" }
75
+ boolean: { name: "boolean" },
76
+ json: { name: "json" },
68
77
  }
69
78
 
70
- class StatementPool < ConnectionAdapters::StatementPool
71
- private
72
-
73
- def dealloc(stmt)
74
- stmt[:stmt].close unless stmt[:stmt].closed?
79
+ def self.represent_boolean_as_integer=(value) # :nodoc:
80
+ if value == false
81
+ raise "`.represent_boolean_as_integer=` is now always true, so make sure your application can work with it and remove this settings."
75
82
  end
76
- end
77
83
 
78
- def schema_creation # :nodoc:
79
- SQLite3::SchemaCreation.new self
84
+ ActiveSupport::Deprecation.warn(
85
+ "`.represent_boolean_as_integer=` is now always true, so setting this is deprecated and will be removed in Rails 6.1."
86
+ )
80
87
  end
81
88
 
82
- def arel_visitor # :nodoc:
83
- Arel::Visitors::SQLite.new(self)
89
+ class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
90
+ private
91
+ def dealloc(stmt)
92
+ stmt.close unless stmt.closed?
93
+ end
84
94
  end
85
95
 
86
96
  def initialize(connection, logger, connection_options, config)
87
97
  super(connection, logger, config)
98
+ configure_connection
99
+ end
88
100
 
89
- @active = nil
90
- @statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
101
+ def self.database_exists?(config)
102
+ config = config.symbolize_keys
103
+ if config[:database] == ":memory:"
104
+ return true
105
+ else
106
+ database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database]
107
+ File.exist?(database_file)
108
+ end
91
109
  end
92
110
 
93
111
  def supports_ddl_transactions?
@@ -99,25 +117,18 @@ module ActiveRecord
99
117
  end
100
118
 
101
119
  def supports_partial_index?
102
- sqlite_version >= '3.8.0'
103
- end
104
-
105
- # Returns true, since this connection adapter supports prepared statement
106
- # caching.
107
- def supports_statement_cache?
108
120
  true
109
121
  end
110
122
 
111
- # Returns true, since this connection adapter supports migrations.
112
- def supports_migrations? #:nodoc:
113
- true
123
+ def supports_expression_index?
124
+ database_version >= "3.9.0"
114
125
  end
115
126
 
116
- def supports_primary_key? #:nodoc:
127
+ def requires_reloading?
117
128
  true
118
129
  end
119
130
 
120
- def requires_reloading?
131
+ def supports_foreign_keys?
121
132
  true
122
133
  end
123
134
 
@@ -129,37 +140,43 @@ module ActiveRecord
129
140
  true
130
141
  end
131
142
 
132
- def supports_multi_insert?
133
- sqlite_version >= '3.7.11'
143
+ def supports_json?
144
+ true
145
+ end
146
+
147
+ def supports_common_table_expressions?
148
+ database_version >= "3.8.3"
134
149
  end
135
150
 
151
+ def supports_insert_on_conflict?
152
+ database_version >= "3.24.0"
153
+ end
154
+ alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
155
+ alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
156
+ alias supports_insert_conflict_target? supports_insert_on_conflict?
157
+
136
158
  def active?
137
- @active != false
159
+ !@connection.closed?
160
+ end
161
+
162
+ def reconnect!
163
+ super
164
+ connect if @connection.closed?
138
165
  end
139
166
 
140
167
  # Disconnects from the database if already connected. Otherwise, this
141
168
  # method does nothing.
142
169
  def disconnect!
143
170
  super
144
- @active = false
145
171
  @connection.close rescue nil
146
172
  end
147
173
 
148
- # Clears the prepared statements cache.
149
- def clear_cache!
150
- @statements.clear
151
- end
152
-
153
174
  def supports_index_sort_order?
154
175
  true
155
176
  end
156
177
 
157
- def valid_type?(type)
158
- true
159
- end
160
-
161
178
  # Returns 62. SQLite supports index names up to 64
162
- # characters. The rest is used by rails internally to perform
179
+ # characters. The rest is used by Rails internally to perform
163
180
  # temporary rename operations
164
181
  def allowed_index_name_length
165
182
  index_name_length - 2
@@ -178,174 +195,39 @@ module ActiveRecord
178
195
  true
179
196
  end
180
197
 
181
- #--
182
- # DATABASE STATEMENTS ======================================
183
- #++
184
-
185
- def explain(arel, binds = [])
186
- sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
187
- SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', []))
198
+ def supports_lazy_transactions?
199
+ true
188
200
  end
189
201
 
190
- def exec_query(sql, name = nil, binds = [], prepare: false)
191
- type_casted_binds = type_casted_binds(binds)
202
+ # REFERENTIAL INTEGRITY ====================================
192
203
 
193
- log(sql, name, binds, type_casted_binds) do
194
- # Don't cache statements if they are not prepared
195
- unless prepare
196
- stmt = @connection.prepare(sql)
197
- begin
198
- cols = stmt.columns
199
- unless without_prepared_statement?(binds)
200
- stmt.bind_params(type_casted_binds)
201
- end
202
- records = stmt.to_a
203
- ensure
204
- stmt.close
205
- end
206
- else
207
- cache = @statements[sql] ||= {
208
- :stmt => @connection.prepare(sql)
209
- }
210
- stmt = cache[:stmt]
211
- cols = cache[:cols] ||= stmt.columns
212
- stmt.reset!
213
- stmt.bind_params(type_casted_binds)
214
- records = stmt.to_a
215
- end
204
+ def disable_referential_integrity # :nodoc:
205
+ old_foreign_keys = query_value("PRAGMA foreign_keys")
206
+ old_defer_foreign_keys = query_value("PRAGMA defer_foreign_keys")
216
207
 
217
- ActiveRecord::Result.new(cols, records)
208
+ begin
209
+ execute("PRAGMA defer_foreign_keys = ON")
210
+ execute("PRAGMA foreign_keys = OFF")
211
+ yield
212
+ ensure
213
+ execute("PRAGMA defer_foreign_keys = #{old_defer_foreign_keys}")
214
+ execute("PRAGMA foreign_keys = #{old_foreign_keys}")
218
215
  end
219
216
  end
220
217
 
221
- def exec_delete(sql, name = 'SQL', binds = [])
222
- exec_query(sql, name, binds)
223
- @connection.changes
224
- end
225
- alias :exec_update :exec_delete
226
-
227
- def last_inserted_id(result)
228
- @connection.last_insert_row_id
229
- end
230
-
231
- def execute(sql, name = nil) #:nodoc:
232
- log(sql, name) { @connection.execute(sql) }
233
- end
234
-
235
- def begin_db_transaction #:nodoc:
236
- log('begin transaction',nil) { @connection.transaction }
237
- end
238
-
239
- def commit_db_transaction #:nodoc:
240
- log('commit transaction',nil) { @connection.commit }
241
- end
242
-
243
- def exec_rollback_db_transaction #:nodoc:
244
- log('rollback transaction',nil) { @connection.rollback }
218
+ #--
219
+ # DATABASE STATEMENTS ======================================
220
+ #++
221
+ def explain(arel, binds = [])
222
+ sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
223
+ SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
245
224
  end
246
225
 
247
226
  # SCHEMA STATEMENTS ========================================
248
227
 
249
- def tables(name = nil) # :nodoc:
250
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
251
- #tables currently returns both tables and views.
252
- This behavior is deprecated and will be changed with Rails 5.1 to only return tables.
253
- Use #data_sources instead.
254
- MSG
255
-
256
- if name
257
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
258
- Passing arguments to #tables is deprecated without replacement.
259
- MSG
260
- end
261
-
262
- data_sources
263
- end
264
-
265
- def data_sources
266
- select_values("SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'", 'SCHEMA')
267
- end
268
-
269
- def table_exists?(table_name)
270
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
271
- #table_exists? currently checks both tables and views.
272
- This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
273
- Use #data_source_exists? instead.
274
- MSG
275
-
276
- data_source_exists?(table_name)
277
- end
278
-
279
- def data_source_exists?(table_name)
280
- return false unless table_name.present?
281
-
282
- sql = "SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'"
283
- sql << " AND name = #{quote(table_name)}"
284
-
285
- select_values(sql, 'SCHEMA').any?
286
- end
287
-
288
- def views # :nodoc:
289
- select_values("SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'", 'SCHEMA')
290
- end
291
-
292
- def view_exists?(view_name) # :nodoc:
293
- return false unless view_name.present?
294
-
295
- sql = "SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'"
296
- sql << " AND name = #{quote(view_name)}"
297
-
298
- select_values(sql, 'SCHEMA').any?
299
- end
300
-
301
- # Returns an array of +Column+ objects for the table specified by +table_name+.
302
- def columns(table_name) # :nodoc:
303
- table_name = table_name.to_s
304
- table_structure(table_name).map do |field|
305
- case field["dflt_value"]
306
- when /^null$/i
307
- field["dflt_value"] = nil
308
- when /^'(.*)'$/m
309
- field["dflt_value"] = $1.gsub("''", "'")
310
- when /^"(.*)"$/m
311
- field["dflt_value"] = $1.gsub('""', '"')
312
- end
313
-
314
- collation = field['collation']
315
- sql_type = field['type']
316
- type_metadata = fetch_type_metadata(sql_type)
317
- new_column(field['name'], field['dflt_value'], type_metadata, field['notnull'].to_i == 0, table_name, nil, collation)
318
- end
319
- end
320
-
321
- # Returns an array of indexes for the given table.
322
- def indexes(table_name, name = nil) #:nodoc:
323
- exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", 'SCHEMA').map do |row|
324
- sql = <<-SQL
325
- SELECT sql
326
- FROM sqlite_master
327
- WHERE name=#{quote(row['name'])} AND type='index'
328
- UNION ALL
329
- SELECT sql
330
- FROM sqlite_temp_master
331
- WHERE name=#{quote(row['name'])} AND type='index'
332
- SQL
333
- index_sql = exec_query(sql).first['sql']
334
- match = /\sWHERE\s+(.+)$/i.match(index_sql)
335
- where = match[1] if match
336
- IndexDefinition.new(
337
- table_name,
338
- row['name'],
339
- row['unique'] != 0,
340
- exec_query("PRAGMA index_info('#{row['name']}')", "SCHEMA").map { |col|
341
- col['name']
342
- }, nil, nil, where)
343
- end
344
- end
345
-
346
228
  def primary_keys(table_name) # :nodoc:
347
- pks = table_structure(table_name).select { |f| f['pk'] > 0 }
348
- pks.sort_by { |f| f['pk'] }.map { |f| f['name'] }
229
+ pks = table_structure(table_name).select { |f| f["pk"] > 0 }
230
+ pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
349
231
  end
350
232
 
351
233
  def remove_index(table_name, options = {}) #:nodoc:
@@ -362,25 +244,22 @@ module ActiveRecord
362
244
  rename_table_indexes(table_name, new_name)
363
245
  end
364
246
 
365
- # See: http://www.sqlite.org/lang_altertable.html
366
- # SQLite has an additional restriction on the ALTER TABLE statement
367
- def valid_alter_table_type?(type)
368
- type.to_sym != :primary_key
369
- end
370
-
371
247
  def add_column(table_name, column_name, type, options = {}) #:nodoc:
372
- if valid_alter_table_type?(type)
373
- super(table_name, column_name, type, options)
374
- else
248
+ if invalid_alter_table_type?(type, options)
375
249
  alter_table(table_name) do |definition|
376
250
  definition.column(column_name, type, options)
377
251
  end
252
+ else
253
+ super
378
254
  end
379
255
  end
380
256
 
381
257
  def remove_column(table_name, column_name, type = nil, options = {}) #:nodoc:
382
258
  alter_table(table_name) do |definition|
383
259
  definition.remove_column column_name
260
+ definition.foreign_keys.delete_if do |_, fk_options|
261
+ fk_options[:column] == column_name.to_s
262
+ end
384
263
  end
385
264
  end
386
265
 
@@ -403,14 +282,13 @@ module ActiveRecord
403
282
 
404
283
  def change_column(table_name, column_name, type, options = {}) #:nodoc:
405
284
  alter_table(table_name) do |definition|
406
- include_default = options_include_default?(options)
407
285
  definition[column_name].instance_eval do
408
286
  self.type = type
409
287
  self.limit = options[:limit] if options.include?(:limit)
410
- self.default = options[:default] if include_default
288
+ self.default = options[:default] if options.include?(:default)
411
289
  self.null = options[:null] if options.include?(:null)
412
290
  self.precision = options[:precision] if options.include?(:precision)
413
- self.scale = options[:scale] if options.include?(:scale)
291
+ self.scale = options[:scale] if options.include?(:scale)
414
292
  self.collation = options[:collation] if options.include?(:collation)
415
293
  end
416
294
  end
@@ -418,52 +296,127 @@ module ActiveRecord
418
296
 
419
297
  def rename_column(table_name, column_name, new_column_name) #:nodoc:
420
298
  column = column_for(table_name, column_name)
421
- alter_table(table_name, rename: {column.name => new_column_name.to_s})
299
+ alter_table(table_name, rename: { column.name => new_column_name.to_s })
422
300
  rename_column_indexes(table_name, column.name, new_column_name)
423
301
  end
424
302
 
425
- protected
303
+ def add_reference(table_name, ref_name, **options) # :nodoc:
304
+ super(table_name, ref_name, type: :integer, **options)
305
+ end
306
+ alias :add_belongs_to :add_reference
307
+
308
+ def foreign_keys(table_name)
309
+ fk_info = exec_query("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA")
310
+ fk_info.map do |row|
311
+ options = {
312
+ column: row["from"],
313
+ primary_key: row["to"],
314
+ on_delete: extract_foreign_key_action(row["on_delete"]),
315
+ on_update: extract_foreign_key_action(row["on_update"])
316
+ }
317
+ ForeignKeyDefinition.new(table_name, row["table"], options)
318
+ end
319
+ end
320
+
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
+ sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
329
+ end
330
+
331
+ sql
332
+ end
333
+
334
+ def get_database_version # :nodoc:
335
+ SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
336
+ end
337
+
338
+ def check_version # :nodoc:
339
+ if database_version < "3.8.0"
340
+ raise "Your version of SQLite (#{database_version}) is too old. Active Record supports SQLite >= 3.8."
341
+ end
342
+ end
343
+
344
+ private
345
+ # See https://www.sqlite.org/limits.html,
346
+ # the default value is 999 when not configured.
347
+ def bind_params_length
348
+ 999
349
+ end
350
+
351
+ def initialize_type_map(m = type_map)
352
+ super
353
+ register_class_with_limit m, %r(int)i, SQLite3Integer
354
+ end
426
355
 
427
356
  def table_structure(table_name)
428
- structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", 'SCHEMA')
357
+ structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
429
358
  raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
430
359
  table_structure_with_collation(table_name, structure)
431
360
  end
361
+ alias column_definitions table_structure
432
362
 
433
- def alter_table(table_name, options = {}) #:nodoc:
363
+ # See: https://www.sqlite.org/lang_altertable.html
364
+ # SQLite has an additional restriction on the ALTER TABLE statement
365
+ def invalid_alter_table_type?(type, options)
366
+ type.to_sym == :primary_key || options[:primary_key]
367
+ end
368
+
369
+ def alter_table(table_name, foreign_keys = foreign_keys(table_name), **options)
434
370
  altered_table_name = "a#{table_name}"
435
- caller = lambda {|definition| yield definition if block_given?}
371
+
372
+ caller = lambda do |definition|
373
+ rename = options[:rename] || {}
374
+ foreign_keys.each do |fk|
375
+ if column = rename[fk.options[:column]]
376
+ fk.options[:column] = column
377
+ end
378
+ to_table = strip_table_name_prefix_and_suffix(fk.to_table)
379
+ definition.foreign_key(to_table, fk.options)
380
+ end
381
+
382
+ yield definition if block_given?
383
+ end
436
384
 
437
385
  transaction do
438
- move_table(table_name, altered_table_name,
439
- options.merge(:temporary => true))
440
- move_table(altered_table_name, table_name, &caller)
386
+ disable_referential_integrity do
387
+ move_table(table_name, altered_table_name, options.merge(temporary: true))
388
+ move_table(altered_table_name, table_name, &caller)
389
+ end
441
390
  end
442
391
  end
443
392
 
444
- def move_table(from, to, options = {}, &block) #:nodoc:
393
+ def move_table(from, to, options = {}, &block)
445
394
  copy_table(from, to, options, &block)
446
395
  drop_table(from)
447
396
  end
448
397
 
449
- def copy_table(from, to, options = {}) #:nodoc:
398
+ def copy_table(from, to, options = {})
450
399
  from_primary_key = primary_key(from)
451
400
  options[:id] = false
452
401
  create_table(to, options) do |definition|
453
402
  @definition = definition
454
- @definition.primary_key(from_primary_key) if from_primary_key.present?
403
+ if from_primary_key.is_a?(Array)
404
+ @definition.primary_keys from_primary_key
405
+ end
455
406
  columns(from).each do |column|
456
407
  column_name = options[:rename] ?
457
408
  (options[:rename][column.name] ||
458
409
  options[:rename][column.name.to_sym] ||
459
410
  column.name) : column.name
460
- next if column_name == from_primary_key
461
411
 
462
412
  @definition.column(column_name, column.type,
463
- :limit => column.limit, :default => column.default,
464
- :precision => column.precision, :scale => column.scale,
465
- :null => column.null, collation: column.collation)
413
+ limit: column.limit, default: column.default,
414
+ precision: column.precision, scale: column.scale,
415
+ null: column.null, collation: column.collation,
416
+ primary_key: column_name == from_primary_key
417
+ )
466
418
  end
419
+
467
420
  yield @definition if block_given?
468
421
  end
469
422
  copy_table_indexes(from, to, options[:rename] || {})
@@ -472,7 +425,7 @@ module ActiveRecord
472
425
  options[:rename] || {})
473
426
  end
474
427
 
475
- def copy_table_indexes(from, to, rename = {}) #:nodoc:
428
+ def copy_table_indexes(from, to, rename = {})
476
429
  indexes(from).each do |index|
477
430
  name = index.name
478
431
  if to == "a#{from}"
@@ -481,89 +434,128 @@ module ActiveRecord
481
434
  name = name[1..-1]
482
435
  end
483
436
 
484
- to_column_names = columns(to).map(&:name)
485
- columns = index.columns.map {|c| rename[c] || c }.select do |column|
486
- to_column_names.include?(column)
437
+ columns = index.columns
438
+ if columns.is_a?(Array)
439
+ to_column_names = columns(to).map(&:name)
440
+ columns = columns.map { |c| rename[c] || c }.select do |column|
441
+ to_column_names.include?(column)
442
+ end
487
443
  end
488
444
 
489
445
  unless columns.empty?
490
446
  # index name can't be the same
491
447
  opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
492
448
  opts[:unique] = true if index.unique
449
+ opts[:where] = index.where if index.where
493
450
  add_index(to, columns, opts)
494
451
  end
495
452
  end
496
453
  end
497
454
 
498
- def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
499
- column_mappings = Hash[columns.map {|name| [name, name]}]
455
+ def copy_table_contents(from, to, columns, rename = {})
456
+ column_mappings = Hash[columns.map { |name| [name, name] }]
500
457
  rename.each { |a| column_mappings[a.last] = a.first }
501
458
  from_columns = columns(from).collect(&:name)
502
- columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
459
+ columns = columns.find_all { |col| from_columns.include?(column_mappings[col]) }
503
460
  from_columns_to_copy = columns.map { |col| column_mappings[col] }
504
- quoted_columns = columns.map { |col| quote_column_name(col) } * ','
505
- quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * ','
461
+ quoted_columns = columns.map { |col| quote_column_name(col) } * ","
462
+ quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * ","
506
463
 
507
464
  exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns})
508
465
  SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
509
466
  end
510
467
 
511
- def sqlite_version
512
- @sqlite_version ||= SQLite3Adapter::Version.new(select_value('select sqlite_version(*)'))
513
- end
514
-
515
- def translate_exception(exception, message)
468
+ def translate_exception(exception, message:, sql:, binds:)
516
469
  case exception.message
517
470
  # SQLite 3.8.2 returns a newly formatted error message:
518
471
  # UNIQUE constraint failed: *table_name*.*column_name*
519
472
  # Older versions of SQLite return:
520
473
  # column *column_name* is not unique
521
474
  when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
522
- RecordNotUnique.new(message)
475
+ RecordNotUnique.new(message, sql: sql, binds: binds)
476
+ when /.* may not be NULL/, /NOT NULL constraint failed: .*/
477
+ NotNullViolation.new(message, sql: sql, binds: binds)
478
+ when /FOREIGN KEY constraint failed/i
479
+ InvalidForeignKey.new(message, sql: sql, binds: binds)
523
480
  else
524
481
  super
525
482
  end
526
483
  end
527
484
 
528
- private
529
485
  COLLATE_REGEX = /.*\"(\w+)\".*collate\s+\"(\w+)\".*/i.freeze
530
486
 
531
487
  def table_structure_with_collation(table_name, basic_structure)
532
488
  collation_hash = {}
533
- sql = "SELECT sql FROM
534
- (SELECT * FROM sqlite_master UNION ALL
535
- SELECT * FROM sqlite_temp_master)
536
- WHERE type='table' and name='#{ table_name }' \;"
489
+ sql = <<~SQL
490
+ SELECT sql FROM
491
+ (SELECT * FROM sqlite_master UNION ALL
492
+ SELECT * FROM sqlite_temp_master)
493
+ WHERE type = 'table' AND name = #{quote(table_name)}
494
+ SQL
537
495
 
538
496
  # Result will have following sample string
539
497
  # CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
540
498
  # "password_digest" varchar COLLATE "NOCASE");
541
- result = exec_query(sql, 'SCHEMA').first
499
+ result = exec_query(sql, "SCHEMA").first
542
500
 
543
501
  if result
544
- # Splitting with left parentheses and picking up last will return all
502
+ # Splitting with left parentheses and discarding the first part will return all
545
503
  # columns separated with comma(,).
546
- columns_string = result["sql"].split('(').last
504
+ columns_string = result["sql"].split("(", 2).last
547
505
 
548
- columns_string.split(',').each do |column_string|
506
+ columns_string.split(",").each do |column_string|
549
507
  # This regex will match the column name and collation type and will save
550
508
  # the value in $1 and $2 respectively.
551
- collation_hash[$1] = $2 if (COLLATE_REGEX =~ column_string)
509
+ collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string
552
510
  end
553
511
 
554
512
  basic_structure.map! do |column|
555
- column_name = column['name']
513
+ column_name = column["name"]
556
514
 
557
515
  if collation_hash.has_key? column_name
558
- column['collation'] = collation_hash[column_name]
516
+ column["collation"] = collation_hash[column_name]
559
517
  end
560
518
 
561
519
  column
562
520
  end
563
521
  else
564
- basic_structure.to_hash
522
+ basic_structure.to_a
565
523
  end
566
524
  end
525
+
526
+ def arel_visitor
527
+ Arel::Visitors::SQLite.new(self)
528
+ end
529
+
530
+ def build_statement_pool
531
+ StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
532
+ end
533
+
534
+ def connect
535
+ @connection = ::SQLite3::Database.new(
536
+ @config[:database].to_s,
537
+ @config.merge(results_as_hash: true)
538
+ )
539
+ configure_connection
540
+ end
541
+
542
+ def configure_connection
543
+ @connection.busy_timeout(self.class.type_cast_config_to_integer(@config[:timeout])) if @config[:timeout]
544
+
545
+ execute("PRAGMA foreign_keys = ON", "SCHEMA")
546
+ end
547
+
548
+ class SQLite3Integer < Type::Integer # :nodoc:
549
+ private
550
+ def _limit
551
+ # INTEGER storage class can be stored 8 bytes value.
552
+ # See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
553
+ limit || 8
554
+ end
555
+ end
556
+
557
+ ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
567
558
  end
559
+ ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
568
560
  end
569
561
  end