activerecord 6.0.0 → 7.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +996 -594
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +34 -34
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +22 -20
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations/alias_tracker.rb +41 -30
  9. data/lib/active_record/associations/association.rb +106 -41
  10. data/lib/active_record/associations/association_scope.rb +30 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +69 -14
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +20 -6
  13. data/lib/active_record/associations/builder/association.rb +39 -6
  14. data/lib/active_record/associations/builder/belongs_to.rb +47 -17
  15. data/lib/active_record/associations/builder/collection_association.rb +14 -6
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -10
  17. data/lib/active_record/associations/builder/has_many.rb +7 -3
  18. data/lib/active_record/associations/builder/has_one.rb +13 -16
  19. data/lib/active_record/associations/builder/singular_association.rb +7 -3
  20. data/lib/active_record/associations/collection_association.rb +90 -53
  21. data/lib/active_record/associations/collection_proxy.rb +54 -19
  22. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  23. data/lib/active_record/associations/errors.rb +265 -0
  24. data/lib/active_record/associations/foreign_association.rb +21 -1
  25. data/lib/active_record/associations/has_many_association.rb +41 -10
  26. data/lib/active_record/associations/has_many_through_association.rb +29 -12
  27. data/lib/active_record/associations/has_one_association.rb +33 -9
  28. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  29. data/lib/active_record/associations/join_dependency/join_association.rb +41 -17
  30. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  31. data/lib/active_record/associations/join_dependency.rb +97 -54
  32. data/lib/active_record/associations/nested_error.rb +47 -0
  33. data/lib/active_record/associations/preloader/association.rb +237 -54
  34. data/lib/active_record/associations/preloader/batch.rb +48 -0
  35. data/lib/active_record/associations/preloader/branch.rb +153 -0
  36. data/lib/active_record/associations/preloader/through_association.rb +51 -17
  37. data/lib/active_record/associations/preloader.rb +55 -121
  38. data/lib/active_record/associations/singular_association.rb +16 -4
  39. data/lib/active_record/associations/through_association.rb +26 -15
  40. data/lib/active_record/associations.rb +454 -440
  41. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  42. data/lib/active_record/attribute_assignment.rb +11 -14
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +36 -11
  44. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  45. data/lib/active_record/attribute_methods/dirty.rb +75 -34
  46. data/lib/active_record/attribute_methods/primary_key.rb +53 -31
  47. data/lib/active_record/attribute_methods/query.rb +31 -22
  48. data/lib/active_record/attribute_methods/read.rb +16 -17
  49. data/lib/active_record/attribute_methods/serialization.rb +177 -35
  50. data/lib/active_record/attribute_methods/time_zone_conversion.rb +18 -15
  51. data/lib/active_record/attribute_methods/write.rb +16 -28
  52. data/lib/active_record/attribute_methods.rb +227 -100
  53. data/lib/active_record/attributes.rb +94 -56
  54. data/lib/active_record/autosave_association.rb +119 -73
  55. data/lib/active_record/base.rb +31 -21
  56. data/lib/active_record/callbacks.rb +168 -55
  57. data/lib/active_record/coders/column_serializer.rb +61 -0
  58. data/lib/active_record/coders/json.rb +1 -1
  59. data/lib/active_record/coders/yaml_column.rb +70 -25
  60. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +367 -565
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -57
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +277 -89
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +241 -69
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +122 -134
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +324 -72
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +17 -4
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +611 -211
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +425 -82
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +698 -211
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +464 -239
  76. data/lib/active_record/connection_adapters/column.rb +28 -1
  77. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  78. data/lib/active_record/connection_adapters/mysql/column.rb +2 -1
  79. data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -137
  80. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  81. data/lib/active_record/connection_adapters/mysql/quoting.rb +90 -43
  82. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +41 -7
  83. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +18 -1
  84. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +13 -4
  85. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +53 -15
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  87. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  88. data/lib/active_record/connection_adapters/mysql2_adapter.rb +127 -63
  89. data/lib/active_record/connection_adapters/pool_config.rb +83 -0
  90. data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
  91. data/lib/active_record/connection_adapters/postgresql/column.rb +54 -2
  92. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +127 -100
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +9 -5
  95. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
  97. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -15
  99. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  101. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -4
  103. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  105. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +35 -8
  106. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  110. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -4
  111. data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
  112. data/lib/active_record/connection_adapters/postgresql/quoting.rb +139 -106
  113. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -2
  114. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +98 -4
  115. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +176 -4
  116. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -1
  117. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -118
  118. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  119. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -11
  120. data/lib/active_record/connection_adapters/postgresql_adapter.rb +585 -295
  121. data/lib/active_record/connection_adapters/schema_cache.rb +399 -60
  122. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  123. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  124. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +99 -48
  125. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +80 -54
  126. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +27 -1
  127. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
  128. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  129. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +102 -24
  130. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +425 -174
  131. data/lib/active_record/connection_adapters/statement_pool.rb +7 -1
  132. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  133. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  134. data/lib/active_record/connection_adapters.rb +176 -0
  135. data/lib/active_record/connection_handling.rb +243 -115
  136. data/lib/active_record/core.rb +481 -199
  137. data/lib/active_record/counter_cache.rb +69 -32
  138. data/lib/active_record/database_configurations/connection_url_resolver.rb +107 -0
  139. data/lib/active_record/database_configurations/database_config.rb +77 -10
  140. data/lib/active_record/database_configurations/hash_config.rb +148 -26
  141. data/lib/active_record/database_configurations/url_config.rb +44 -45
  142. data/lib/active_record/database_configurations.rb +190 -114
  143. data/lib/active_record/delegated_type.rb +279 -0
  144. data/lib/active_record/deprecator.rb +7 -0
  145. data/lib/active_record/destroy_association_async_job.rb +38 -0
  146. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  147. data/lib/active_record/dynamic_matchers.rb +5 -6
  148. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  149. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  150. data/lib/active_record/encryption/cipher.rb +53 -0
  151. data/lib/active_record/encryption/config.rb +68 -0
  152. data/lib/active_record/encryption/configurable.rb +60 -0
  153. data/lib/active_record/encryption/context.rb +42 -0
  154. data/lib/active_record/encryption/contexts.rb +76 -0
  155. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  156. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  157. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  158. data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
  159. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  160. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  161. data/lib/active_record/encryption/encryptor.rb +171 -0
  162. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  163. data/lib/active_record/encryption/errors.rb +15 -0
  164. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  165. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  166. data/lib/active_record/encryption/key.rb +28 -0
  167. data/lib/active_record/encryption/key_generator.rb +53 -0
  168. data/lib/active_record/encryption/key_provider.rb +46 -0
  169. data/lib/active_record/encryption/message.rb +33 -0
  170. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  171. data/lib/active_record/encryption/message_serializer.rb +96 -0
  172. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  173. data/lib/active_record/encryption/properties.rb +76 -0
  174. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  175. data/lib/active_record/encryption/scheme.rb +100 -0
  176. data/lib/active_record/encryption.rb +58 -0
  177. data/lib/active_record/enum.rb +224 -73
  178. data/lib/active_record/errors.rb +254 -36
  179. data/lib/active_record/explain.rb +30 -17
  180. data/lib/active_record/explain_registry.rb +11 -6
  181. data/lib/active_record/explain_subscriber.rb +2 -2
  182. data/lib/active_record/fixture_set/file.rb +22 -15
  183. data/lib/active_record/fixture_set/model_metadata.rb +15 -6
  184. data/lib/active_record/fixture_set/render_context.rb +3 -1
  185. data/lib/active_record/fixture_set/table_row.rb +88 -16
  186. data/lib/active_record/fixture_set/table_rows.rb +4 -5
  187. data/lib/active_record/fixtures.rb +229 -116
  188. data/lib/active_record/future_result.rb +178 -0
  189. data/lib/active_record/gem_version.rb +4 -4
  190. data/lib/active_record/inheritance.rb +121 -48
  191. data/lib/active_record/insert_all.rb +178 -29
  192. data/lib/active_record/integration.rb +16 -14
  193. data/lib/active_record/internal_metadata.rb +132 -21
  194. data/lib/active_record/legacy_yaml_adapter.rb +3 -36
  195. data/lib/active_record/locking/optimistic.rb +64 -33
  196. data/lib/active_record/locking/pessimistic.rb +21 -8
  197. data/lib/active_record/log_subscriber.rb +61 -30
  198. data/lib/active_record/marshalling.rb +59 -0
  199. data/lib/active_record/message_pack.rb +124 -0
  200. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  201. data/lib/active_record/middleware/database_selector/resolver.rb +19 -19
  202. data/lib/active_record/middleware/database_selector.rb +25 -13
  203. data/lib/active_record/middleware/shard_selector.rb +62 -0
  204. data/lib/active_record/migration/command_recorder.rb +160 -55
  205. data/lib/active_record/migration/compatibility.rb +286 -43
  206. data/lib/active_record/migration/default_strategy.rb +22 -0
  207. data/lib/active_record/migration/execution_strategy.rb +19 -0
  208. data/lib/active_record/migration/join_table.rb +1 -2
  209. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  210. data/lib/active_record/migration.rb +421 -193
  211. data/lib/active_record/model_schema.rb +217 -125
  212. data/lib/active_record/nested_attributes.rb +62 -27
  213. data/lib/active_record/no_touching.rb +4 -4
  214. data/lib/active_record/normalization.rb +163 -0
  215. data/lib/active_record/persistence.rb +322 -319
  216. data/lib/active_record/promise.rb +84 -0
  217. data/lib/active_record/query_cache.rb +18 -15
  218. data/lib/active_record/query_logs.rb +193 -0
  219. data/lib/active_record/query_logs_formatter.rb +41 -0
  220. data/lib/active_record/querying.rb +54 -14
  221. data/lib/active_record/railtie.rb +250 -72
  222. data/lib/active_record/railties/console_sandbox.rb +2 -4
  223. data/lib/active_record/railties/controller_runtime.rb +25 -11
  224. data/lib/active_record/railties/databases.rake +312 -197
  225. data/lib/active_record/railties/job_runtime.rb +23 -0
  226. data/lib/active_record/readonly_attributes.rb +45 -3
  227. data/lib/active_record/reflection.rb +389 -146
  228. data/lib/active_record/relation/batches/batch_enumerator.rb +61 -16
  229. data/lib/active_record/relation/batches.rb +214 -73
  230. data/lib/active_record/relation/calculations.rb +379 -124
  231. data/lib/active_record/relation/delegation.rb +36 -23
  232. data/lib/active_record/relation/finder_methods.rb +159 -49
  233. data/lib/active_record/relation/from_clause.rb +5 -1
  234. data/lib/active_record/relation/merger.rb +41 -33
  235. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -11
  236. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -7
  237. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +20 -13
  238. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  239. data/lib/active_record/relation/predicate_builder.rb +79 -53
  240. data/lib/active_record/relation/query_attribute.rb +30 -12
  241. data/lib/active_record/relation/query_methods.rb +1156 -279
  242. data/lib/active_record/relation/record_fetch_warning.rb +12 -11
  243. data/lib/active_record/relation/spawn_methods.rb +10 -9
  244. data/lib/active_record/relation/where_clause.rb +100 -66
  245. data/lib/active_record/relation.rb +829 -194
  246. data/lib/active_record/result.rb +76 -56
  247. data/lib/active_record/runtime_registry.rb +71 -13
  248. data/lib/active_record/sanitization.rb +86 -47
  249. data/lib/active_record/schema.rb +39 -23
  250. data/lib/active_record/schema_dumper.rb +140 -33
  251. data/lib/active_record/schema_migration.rb +74 -29
  252. data/lib/active_record/scoping/default.rb +73 -19
  253. data/lib/active_record/scoping/named.rb +10 -28
  254. data/lib/active_record/scoping.rb +65 -35
  255. data/lib/active_record/secure_password.rb +60 -0
  256. data/lib/active_record/secure_token.rb +34 -8
  257. data/lib/active_record/serialization.rb +11 -4
  258. data/lib/active_record/signed_id.rb +138 -0
  259. data/lib/active_record/statement_cache.rb +26 -10
  260. data/lib/active_record/store.rb +19 -14
  261. data/lib/active_record/suppressor.rb +15 -17
  262. data/lib/active_record/table_metadata.rb +46 -36
  263. data/lib/active_record/tasks/database_tasks.rb +371 -205
  264. data/lib/active_record/tasks/mysql_database_tasks.rb +43 -36
  265. data/lib/active_record/tasks/postgresql_database_tasks.rb +54 -41
  266. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -13
  267. data/lib/active_record/test_databases.rb +5 -4
  268. data/lib/active_record/test_fixtures.rb +189 -104
  269. data/lib/active_record/testing/query_assertions.rb +121 -0
  270. data/lib/active_record/timestamp.rb +35 -25
  271. data/lib/active_record/token_for.rb +123 -0
  272. data/lib/active_record/touch_later.rb +31 -27
  273. data/lib/active_record/transaction.rb +132 -0
  274. data/lib/active_record/transactions.rb +131 -99
  275. data/lib/active_record/translation.rb +3 -5
  276. data/lib/active_record/type/adapter_specific_registry.rb +33 -18
  277. data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
  278. data/lib/active_record/type/internal/timezone.rb +7 -2
  279. data/lib/active_record/type/serialized.rb +11 -6
  280. data/lib/active_record/type/time.rb +14 -0
  281. data/lib/active_record/type/type_map.rb +17 -21
  282. data/lib/active_record/type/unsigned_integer.rb +0 -1
  283. data/lib/active_record/type.rb +7 -2
  284. data/lib/active_record/type_caster/connection.rb +4 -5
  285. data/lib/active_record/type_caster/map.rb +8 -5
  286. data/lib/active_record/validations/absence.rb +1 -1
  287. data/lib/active_record/validations/associated.rb +13 -8
  288. data/lib/active_record/validations/numericality.rb +36 -0
  289. data/lib/active_record/validations/presence.rb +5 -28
  290. data/lib/active_record/validations/uniqueness.rb +88 -18
  291. data/lib/active_record/validations.rb +15 -8
  292. data/lib/active_record/version.rb +1 -1
  293. data/lib/active_record.rb +446 -40
  294. data/lib/arel/alias_predication.rb +1 -1
  295. data/lib/arel/attributes/attribute.rb +4 -8
  296. data/lib/arel/collectors/bind.rb +8 -1
  297. data/lib/arel/collectors/composite.rb +15 -0
  298. data/lib/arel/collectors/sql_string.rb +7 -0
  299. data/lib/arel/collectors/substitute_binds.rb +7 -0
  300. data/lib/arel/crud.rb +30 -22
  301. data/lib/arel/delete_manager.rb +23 -4
  302. data/lib/arel/errors.rb +10 -0
  303. data/lib/arel/factory_methods.rb +4 -0
  304. data/lib/arel/filter_predications.rb +9 -0
  305. data/lib/arel/insert_manager.rb +2 -3
  306. data/lib/arel/nodes/binary.rb +82 -9
  307. data/lib/arel/nodes/bind_param.rb +8 -0
  308. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  309. data/lib/arel/nodes/casted.rb +22 -10
  310. data/lib/arel/nodes/cte.rb +36 -0
  311. data/lib/arel/nodes/delete_statement.rb +14 -13
  312. data/lib/arel/nodes/equality.rb +6 -9
  313. data/lib/arel/nodes/filter.rb +10 -0
  314. data/lib/arel/nodes/fragments.rb +35 -0
  315. data/lib/arel/nodes/function.rb +1 -0
  316. data/lib/arel/nodes/grouping.rb +3 -0
  317. data/lib/arel/nodes/homogeneous_in.rb +68 -0
  318. data/lib/arel/nodes/in.rb +8 -1
  319. data/lib/arel/nodes/infix_operation.rb +13 -1
  320. data/lib/arel/nodes/insert_statement.rb +2 -2
  321. data/lib/arel/nodes/join_source.rb +1 -1
  322. data/lib/arel/nodes/leading_join.rb +8 -0
  323. data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
  324. data/lib/arel/nodes/node.rb +122 -11
  325. data/lib/arel/nodes/ordering.rb +27 -0
  326. data/lib/arel/nodes/select_core.rb +2 -2
  327. data/lib/arel/nodes/select_statement.rb +2 -2
  328. data/lib/arel/nodes/sql_literal.rb +16 -0
  329. data/lib/arel/nodes/table_alias.rb +11 -3
  330. data/lib/arel/nodes/unary.rb +0 -1
  331. data/lib/arel/nodes/update_statement.rb +11 -4
  332. data/lib/arel/nodes.rb +10 -3
  333. data/lib/arel/predications.rb +31 -28
  334. data/lib/arel/select_manager.rb +18 -9
  335. data/lib/arel/table.rb +21 -10
  336. data/lib/arel/tree_manager.rb +8 -15
  337. data/lib/arel/update_manager.rb +25 -5
  338. data/lib/arel/visitors/dot.rb +94 -90
  339. data/lib/arel/visitors/mysql.rb +34 -6
  340. data/lib/arel/visitors/postgresql.rb +5 -16
  341. data/lib/arel/visitors/sqlite.rb +25 -1
  342. data/lib/arel/visitors/to_sql.rb +227 -81
  343. data/lib/arel/visitors/visitor.rb +2 -3
  344. data/lib/arel/visitors.rb +0 -7
  345. data/lib/arel.rb +37 -15
  346. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  347. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  348. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  349. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  350. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +6 -1
  351. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  352. data/lib/rails/generators/active_record/migration.rb +9 -3
  353. data/lib/rails/generators/active_record/model/USAGE +113 -0
  354. data/lib/rails/generators/active_record/model/model_generator.rb +49 -4
  355. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  356. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  357. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  358. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  359. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  360. metadata +117 -30
  361. data/lib/active_record/attribute_decorators.rb +0 -90
  362. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  363. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  364. data/lib/active_record/define_callbacks.rb +0 -22
  365. data/lib/active_record/null_relation.rb +0 -68
  366. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  367. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  368. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  369. data/lib/arel/attributes.rb +0 -22
  370. data/lib/arel/visitors/depth_first.rb +0 -204
  371. data/lib/arel/visitors/ibm_db.rb +0 -34
  372. data/lib/arel/visitors/informix.rb +0 -62
  373. data/lib/arel/visitors/mssql.rb +0 -157
  374. data/lib/arel/visitors/oracle.rb +0 -159
  375. data/lib/arel/visitors/oracle12.rb +0 -66
  376. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -4,41 +4,36 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module SQLite3
6
6
  module DatabaseStatements
7
- READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :commit, :explain, :select, :pragma, :release, :savepoint, :rollback) # :nodoc:
7
+ READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
8
+ :pragma
9
+ ) # :nodoc:
8
10
  private_constant :READ_QUERY
9
11
 
10
12
  def write_query?(sql) # :nodoc:
11
13
  !READ_QUERY.match?(sql)
14
+ rescue ArgumentError # Invalid encoding
15
+ !READ_QUERY.match?(sql.b)
12
16
  end
13
17
 
14
- def execute(sql, name = nil) #:nodoc:
15
- if preventing_writes? && write_query?(sql)
16
- raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
17
- end
18
-
19
- materialize_transactions
20
-
21
- log(sql, name) do
22
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
23
- @connection.execute(sql)
24
- end
25
- end
18
+ def explain(arel, binds = [], _options = [])
19
+ sql = "EXPLAIN QUERY PLAN " + to_sql(arel, binds)
20
+ result = internal_exec_query(sql, "EXPLAIN", [])
21
+ SQLite3::ExplainPrettyPrinter.new.pp(result)
26
22
  end
27
23
 
28
- def exec_query(sql, name = nil, binds = [], prepare: false)
29
- if preventing_writes? && write_query?(sql)
30
- raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
31
- end
24
+ def internal_exec_query(sql, name = nil, binds = [], prepare: false, async: false, allow_retry: false) # :nodoc:
25
+ sql = transform_query(sql)
26
+ check_if_write_query(sql)
32
27
 
33
- materialize_transactions
28
+ mark_transaction_written_if_write(sql)
34
29
 
35
30
  type_casted_binds = type_casted_binds(binds)
36
31
 
37
- log(sql, name, binds, type_casted_binds) do
38
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
32
+ log(sql, name, binds, type_casted_binds, async: async) do |notification_payload|
33
+ with_raw_connection do |conn|
39
34
  # Don't cache statements if they are not prepared
40
35
  unless prepare
41
- stmt = @connection.prepare(sql)
36
+ stmt = conn.prepare(sql)
42
37
  begin
43
38
  cols = stmt.columns
44
39
  unless without_prepared_statement?(binds)
@@ -49,54 +44,109 @@ module ActiveRecord
49
44
  stmt.close
50
45
  end
51
46
  else
52
- stmt = @statements[sql] ||= @connection.prepare(sql)
47
+ stmt = @statements[sql] ||= conn.prepare(sql)
53
48
  cols = stmt.columns
54
49
  stmt.reset!
55
50
  stmt.bind_params(type_casted_binds)
56
51
  records = stmt.to_a
57
52
  end
53
+ verified!
58
54
 
59
- ActiveRecord::Result.new(cols, records)
55
+ result = build_result(columns: cols, rows: records)
56
+ notification_payload[:row_count] = result.length
57
+ result
60
58
  end
61
59
  end
62
60
  end
63
61
 
64
- def exec_delete(sql, name = "SQL", binds = [])
65
- exec_query(sql, name, binds)
66
- @connection.changes
62
+ def exec_delete(sql, name = "SQL", binds = []) # :nodoc:
63
+ internal_exec_query(sql, name, binds)
64
+ @raw_connection.changes
67
65
  end
68
66
  alias :exec_update :exec_delete
69
67
 
70
- def begin_db_transaction #:nodoc:
71
- log("begin transaction", nil) { @connection.transaction }
72
- end
68
+ def begin_isolated_db_transaction(isolation) # :nodoc:
69
+ raise TransactionIsolationError, "SQLite3 only supports the `read_uncommitted` transaction isolation level" if isolation != :read_uncommitted
70
+ raise StandardError, "You need to enable the shared-cache mode in SQLite mode before attempting to change the transaction isolation level" unless shared_cache?
73
71
 
74
- def commit_db_transaction #:nodoc:
75
- log("commit transaction", nil) { @connection.commit }
72
+ with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
73
+ ActiveSupport::IsolatedExecutionState[:active_record_read_uncommitted] = conn.get_first_value("PRAGMA read_uncommitted")
74
+ conn.read_uncommitted = true
75
+ begin_db_transaction
76
+ end
76
77
  end
77
78
 
78
- def exec_rollback_db_transaction #:nodoc:
79
- log("rollback transaction", nil) { @connection.rollback }
79
+ def begin_db_transaction # :nodoc:
80
+ log("begin transaction", "TRANSACTION") do
81
+ with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
82
+ result = conn.transaction
83
+ verified!
84
+ result
85
+ end
86
+ end
80
87
  end
81
88
 
89
+ def commit_db_transaction # :nodoc:
90
+ log("commit transaction", "TRANSACTION") do
91
+ with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
92
+ conn.commit
93
+ end
94
+ end
95
+ reset_read_uncommitted
96
+ end
82
97
 
83
- private
84
- def execute_batch(sql, name = nil)
85
- if preventing_writes? && write_query?(sql)
86
- raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
98
+ def exec_rollback_db_transaction # :nodoc:
99
+ log("rollback transaction", "TRANSACTION") do
100
+ with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
101
+ conn.rollback
87
102
  end
103
+ end
104
+ reset_read_uncommitted
105
+ end
106
+
107
+ # https://stackoverflow.com/questions/17574784
108
+ # https://www.sqlite.org/lang_datefunc.html
109
+ HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')", retryable: true).freeze # :nodoc:
110
+ private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
88
111
 
89
- materialize_transactions
112
+ def high_precision_current_timestamp
113
+ HIGH_PRECISION_CURRENT_TIMESTAMP
114
+ end
90
115
 
91
- log(sql, name) do
92
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
93
- @connection.execute_batch2(sql)
116
+ private
117
+ def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: false)
118
+ log(sql, name, async: async) do |notification_payload|
119
+ with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
120
+ result = conn.execute(sql)
121
+ verified!
122
+ notification_payload[:row_count] = result.length
123
+ result
94
124
  end
95
125
  end
96
126
  end
97
127
 
98
- def last_inserted_id(result)
99
- @connection.last_insert_row_id
128
+ def reset_read_uncommitted
129
+ read_uncommitted = ActiveSupport::IsolatedExecutionState[:active_record_read_uncommitted]
130
+ return unless read_uncommitted
131
+
132
+ @raw_connection&.read_uncommitted = read_uncommitted
133
+ end
134
+
135
+ def execute_batch(statements, name = nil)
136
+ statements = statements.map { |sql| transform_query(sql) }
137
+ sql = combine_multi_statements(statements)
138
+
139
+ check_if_write_query(sql)
140
+ mark_transaction_written_if_write(sql)
141
+
142
+ log(sql, name) do |notification_payload|
143
+ with_raw_connection do |conn|
144
+ result = conn.execute_batch2(sql)
145
+ verified!
146
+ notification_payload[:row_count] = result.length
147
+ result
148
+ end
149
+ end
100
150
  end
101
151
 
102
152
  def build_fixture_statements(fixture_set)
@@ -106,11 +156,12 @@ module ActiveRecord
106
156
  end.compact
107
157
  end
108
158
 
109
- def build_truncate_statements(*table_names)
110
- truncate_tables = table_names.map do |table_name|
111
- "DELETE FROM #{quote_table_name(table_name)}"
112
- end
113
- combine_multi_statements(truncate_tables)
159
+ def build_truncate_statement(table_name)
160
+ "DELETE FROM #{quote_table_name(table_name)}"
161
+ end
162
+
163
+ def returning_column_values(result)
164
+ result.rows.first
114
165
  end
115
166
  end
116
167
  end
@@ -4,20 +4,71 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module SQLite3
6
6
  module Quoting # :nodoc:
7
- def quote_string(s)
8
- @connection.class.quote(s)
7
+ extend ActiveSupport::Concern
8
+
9
+ QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
10
+ QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
11
+
12
+ module ClassMethods # :nodoc:
13
+ def column_name_matcher
14
+ /
15
+ \A
16
+ (
17
+ (?:
18
+ # "table_name"."column_name" | function(one or no argument)
19
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
20
+ )
21
+ (?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
22
+ )
23
+ (?:\s*,\s*\g<1>)*
24
+ \z
25
+ /ix
26
+ end
27
+
28
+ def column_name_with_order_matcher
29
+ /
30
+ \A
31
+ (
32
+ (?:
33
+ # "table_name"."column_name" | function(one or no argument)
34
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
35
+ )
36
+ (?:\s+COLLATE\s+(?:\w+|"\w+"))?
37
+ (?:\s+ASC|\s+DESC)?
38
+ )
39
+ (?:\s*,\s*\g<1>)*
40
+ \z
41
+ /ix
42
+ end
43
+
44
+ def quote_column_name(name)
45
+ QUOTED_COLUMN_NAMES[name] ||= %Q("#{name.to_s.gsub('"', '""')}").freeze
46
+ end
47
+
48
+ def quote_table_name(name)
49
+ QUOTED_TABLE_NAMES[name] ||= %Q("#{name.to_s.gsub('"', '""').gsub(".", "\".\"")}").freeze
50
+ end
9
51
  end
10
52
 
11
- def quote_table_name_for_assignment(table, attr)
12
- quote_column_name(attr)
53
+ def quote(value) # :nodoc:
54
+ case value
55
+ when Numeric
56
+ if value.finite?
57
+ super
58
+ else
59
+ "'#{value}'"
60
+ end
61
+ else
62
+ super
63
+ end
13
64
  end
14
65
 
15
- def quote_table_name(name)
16
- self.class.quoted_table_names[name] ||= super.gsub(".", "\".\"").freeze
66
+ def quote_string(s)
67
+ ::SQLite3::Database.quote(s)
17
68
  end
18
69
 
19
- def quote_column_name(name)
20
- self.class.quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}")
70
+ def quote_table_name_for_assignment(table, attr)
71
+ quote_column_name(attr)
21
72
  end
22
73
 
23
74
  def quoted_time(value)
@@ -45,58 +96,33 @@ module ActiveRecord
45
96
  0
46
97
  end
47
98
 
48
- def column_name_matcher
49
- COLUMN_NAME
50
- end
51
-
52
- def column_name_with_order_matcher
53
- COLUMN_NAME_WITH_ORDER
99
+ def quote_default_expression(value, column) # :nodoc:
100
+ if value.is_a?(Proc)
101
+ value = value.call
102
+ if value.match?(/\A\w+\(.*\)\z/)
103
+ "(#{value})"
104
+ else
105
+ value
106
+ end
107
+ else
108
+ super
109
+ end
54
110
  end
55
111
 
56
- COLUMN_NAME = /
57
- \A
58
- (
59
- (?:
60
- # "table_name"."column_name" | function(one or no argument)
61
- ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")) | \w+\((?:|\g<2>)\)
62
- )
63
- (?:\s+AS\s+(?:\w+|"\w+"))?
64
- )
65
- (?:\s*,\s*\g<1>)*
66
- \z
67
- /ix
68
-
69
- COLUMN_NAME_WITH_ORDER = /
70
- \A
71
- (
72
- (?:
73
- # "table_name"."column_name" | function(one or no argument)
74
- ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")) | \w+\((?:|\g<2>)\)
75
- )
76
- (?:\s+ASC|\s+DESC)?
77
- )
78
- (?:\s*,\s*\g<1>)*
79
- \z
80
- /ix
81
-
82
- private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
83
-
84
- private
85
-
86
- def _type_cast(value)
87
- case value
88
- when BigDecimal
89
- value.to_f
90
- when String
91
- if value.encoding == Encoding::ASCII_8BIT
92
- super(value.encode(Encoding::UTF_8))
93
- else
94
- super
95
- end
112
+ def type_cast(value) # :nodoc:
113
+ case value
114
+ when BigDecimal, Rational
115
+ value.to_f
116
+ when String
117
+ if value.encoding == Encoding::ASCII_8BIT
118
+ super(value.encode(Encoding::UTF_8))
96
119
  else
97
120
  super
98
121
  end
122
+ else
123
+ super
99
124
  end
125
+ end
100
126
  end
101
127
  end
102
128
  end
@@ -3,12 +3,38 @@
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module SQLite3
6
- class SchemaCreation < AbstractAdapter::SchemaCreation # :nodoc:
6
+ class SchemaCreation < SchemaCreation # :nodoc:
7
7
  private
8
+ def visit_AddForeignKey(o)
9
+ super.dup.tap do |sql|
10
+ sql << " DEFERRABLE INITIALLY #{o.options[:deferrable].to_s.upcase}" if o.deferrable
11
+ end
12
+ end
13
+
14
+ def visit_ForeignKeyDefinition(o)
15
+ super.dup.tap do |sql|
16
+ sql << " DEFERRABLE INITIALLY #{o.deferrable.to_s.upcase}" if o.deferrable
17
+ end
18
+ end
19
+
20
+ def supports_index_using?
21
+ false
22
+ end
23
+
8
24
  def add_column_options!(sql, options)
9
25
  if options[:collation]
10
26
  sql << " COLLATE \"#{options[:collation]}\""
11
27
  end
28
+
29
+ if as = options[:as]
30
+ sql << " GENERATED ALWAYS AS (#{as})"
31
+
32
+ if options[:stored]
33
+ sql << " STORED"
34
+ else
35
+ sql << " VIRTUAL"
36
+ end
37
+ end
12
38
  super
13
39
  end
14
40
  end
@@ -3,16 +3,36 @@
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module SQLite3
6
+ # = Active Record SQLite3 Adapter \Table Definition
6
7
  class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
8
+ def change_column(column_name, type, **options)
9
+ name = column_name.to_s
10
+ @columns_hash[name] = nil
11
+ column(name, type, **options)
12
+ end
13
+
7
14
  def references(*args, **options)
8
15
  super(*args, type: :integer, **options)
9
16
  end
10
17
  alias :belongs_to :references
11
18
 
19
+ def new_column_definition(name, type, **options) # :nodoc:
20
+ case type
21
+ when :virtual
22
+ type = options[:type]
23
+ end
24
+
25
+ super
26
+ end
27
+
12
28
  private
13
29
  def integer_like_primary_key_type(type, options)
14
30
  :primary_key
15
31
  end
32
+
33
+ def valid_column_definition_options
34
+ super + [:as, :type, :stored]
35
+ end
16
36
  end
17
37
  end
18
38
  end
@@ -12,6 +12,22 @@ module ActiveRecord
12
12
  def explicit_primary_key_default?(column)
13
13
  column.bigint?
14
14
  end
15
+
16
+ def prepare_column_options(column)
17
+ spec = super
18
+
19
+ if @connection.supports_virtual_columns? && column.virtual?
20
+ spec[:as] = extract_expression_for_virtual_column(column)
21
+ spec[:stored] = column.virtual_stored?
22
+ spec = { type: schema_type(column).inspect }.merge!(spec)
23
+ end
24
+
25
+ spec
26
+ end
27
+
28
+ def extract_expression_for_virtual_column(column)
29
+ column.default_function.inspect
30
+ end
15
31
  end
16
32
  end
17
33
  end
@@ -6,10 +6,10 @@ module ActiveRecord
6
6
  module SchemaStatements # :nodoc:
7
7
  # Returns an array of indexes for the given table.
8
8
  def indexes(table_name)
9
- exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").map do |row|
9
+ internal_exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").filter_map do |row|
10
10
  # Indexes SQLite creates implicitly for internal use start with "sqlite_".
11
11
  # See https://www.sqlite.org/fileformat2.html#intschema
12
- next if row["name"].starts_with?("sqlite_")
12
+ next if row["name"].start_with?("sqlite_")
13
13
 
14
14
  index_sql = query_value(<<~SQL, "SCHEMA")
15
15
  SELECT sql
@@ -21,9 +21,9 @@ module ActiveRecord
21
21
  WHERE name = #{quote(row['name'])} AND type = 'index'
22
22
  SQL
23
23
 
24
- /\bON\b\s*"?(\w+?)"?\s*\((?<expressions>.+?)\)(?:\s*WHERE\b\s*(?<where>.+))?\z/i =~ index_sql
24
+ /\bON\b\s*"?(\w+?)"?\s*\((?<expressions>.+?)\)(?:\s*WHERE\b\s*(?<where>.+))?(?:\s*\/\*.*\*\/)?\z/i =~ index_sql
25
25
 
26
- columns = exec_query("PRAGMA index_info(#{quote(row['name'])})", "SCHEMA").map do |col|
26
+ columns = internal_exec_query("PRAGMA index_info(#{quote(row['name'])})", "SCHEMA").map do |col|
27
27
  col["name"]
28
28
  end
29
29
 
@@ -49,19 +49,23 @@ module ActiveRecord
49
49
  where: where,
50
50
  orders: orders
51
51
  )
52
- end.compact
52
+ end
53
53
  end
54
54
 
55
55
  def add_foreign_key(from_table, to_table, **options)
56
+ assert_valid_deferrable(options[:deferrable])
57
+
56
58
  alter_table(from_table) do |definition|
57
59
  to_table = strip_table_name_prefix_and_suffix(to_table)
58
- definition.foreign_key(to_table, options)
60
+ definition.foreign_key(to_table, **options)
59
61
  end
60
62
  end
61
63
 
62
64
  def remove_foreign_key(from_table, to_table = nil, **options)
65
+ return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table)
66
+
63
67
  to_table ||= options[:to_table]
64
- options = options.except(:name, :to_table)
68
+ options = options.except(:name, :to_table, :validate)
65
69
  foreign_keys = foreign_keys(from_table)
66
70
 
67
71
  fkey = foreign_keys.detect do |fk|
@@ -70,6 +74,7 @@ module ActiveRecord
70
74
  Base.pluralize_table_names ? table.pluralize : table
71
75
  end
72
76
  table = strip_table_name_prefix_and_suffix(table)
77
+ options = options.slice(*fk.options.keys)
73
78
  fk_to_table = strip_table_name_prefix_and_suffix(fk.to_table)
74
79
  fk_to_table == table && options.all? { |k, v| fk.options[k].to_s == v.to_s }
75
80
  end || raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{to_table || options}")
@@ -78,34 +83,94 @@ module ActiveRecord
78
83
  alter_table(from_table, foreign_keys)
79
84
  end
80
85
 
86
+ def check_constraints(table_name)
87
+ table_sql = query_value(<<-SQL, "SCHEMA")
88
+ SELECT sql
89
+ FROM sqlite_master
90
+ WHERE name = #{quote(table_name)} AND type = 'table'
91
+ UNION ALL
92
+ SELECT sql
93
+ FROM sqlite_temp_master
94
+ WHERE name = #{quote(table_name)} AND type = 'table'
95
+ SQL
96
+
97
+ table_sql.to_s.scan(/CONSTRAINT\s+(?<name>\w+)\s+CHECK\s+\((?<expression>(:?[^()]|\(\g<expression>\))+)\)/i).map do |name, expression|
98
+ CheckConstraintDefinition.new(table_name, expression, name: name)
99
+ end
100
+ end
101
+
102
+ def add_check_constraint(table_name, expression, **options)
103
+ alter_table(table_name) do |definition|
104
+ definition.check_constraint(expression, **options)
105
+ end
106
+ end
107
+
108
+ def remove_check_constraint(table_name, expression = nil, if_exists: false, **options)
109
+ return if if_exists && !check_constraint_exists?(table_name, **options)
110
+
111
+ check_constraints = check_constraints(table_name)
112
+ chk_name_to_delete = check_constraint_for!(table_name, expression: expression, **options).name
113
+ check_constraints.delete_if { |chk| chk.name == chk_name_to_delete }
114
+ alter_table(table_name, foreign_keys(table_name), check_constraints)
115
+ end
116
+
81
117
  def create_schema_dumper(options)
82
118
  SQLite3::SchemaDumper.create(self, options)
83
119
  end
84
120
 
121
+ def schema_creation # :nodoc
122
+ SQLite3::SchemaCreation.new(self)
123
+ end
124
+
85
125
  private
86
- def schema_creation
87
- SQLite3::SchemaCreation.new(self)
126
+ def valid_table_definition_options
127
+ super + [:rename]
88
128
  end
89
129
 
90
- def create_table_definition(*args)
91
- SQLite3::TableDefinition.new(self, *args)
130
+ def create_table_definition(name, **options)
131
+ SQLite3::TableDefinition.new(self, name, **options)
92
132
  end
93
133
 
94
- def new_column_from_field(table_name, field)
95
- default = \
96
- case field["dflt_value"]
97
- when /^null$/i
98
- nil
99
- when /^'(.*)'$/m
100
- $1.gsub("''", "'")
101
- when /^"(.*)"$/m
102
- $1.gsub('""', '"')
103
- else
104
- field["dflt_value"]
105
- end
134
+ def validate_index_length!(table_name, new_name, internal = false)
135
+ super unless internal
136
+ end
137
+
138
+ def new_column_from_field(table_name, field, definitions)
139
+ default = field["dflt_value"]
106
140
 
107
141
  type_metadata = fetch_type_metadata(field["type"])
108
- Column.new(field["name"], default, type_metadata, field["notnull"].to_i == 0, collation: field["collation"])
142
+ default_value = extract_value_from_default(default)
143
+ generated_type = extract_generated_type(field)
144
+
145
+ if generated_type.present?
146
+ default_function = default
147
+ else
148
+ default_function = extract_default_function(default_value, default)
149
+ end
150
+
151
+ rowid = is_column_the_rowid?(field, definitions)
152
+
153
+ Column.new(
154
+ field["name"],
155
+ default_value,
156
+ type_metadata,
157
+ field["notnull"].to_i == 0,
158
+ default_function,
159
+ collation: field["collation"],
160
+ auto_increment: field["auto_increment"],
161
+ rowid: rowid,
162
+ generated_type: generated_type
163
+ )
164
+ end
165
+
166
+ INTEGER_REGEX = /integer/i
167
+ # if a rowid table has a primary key that consists of a single column
168
+ # and the declared type of that column is "INTEGER" in any mixture of upper and lower case,
169
+ # then the column becomes an alias for the rowid.
170
+ def is_column_the_rowid?(field, column_definitions)
171
+ return false unless INTEGER_REGEX.match?(field["type"]) && field["pk"] == 1
172
+ # is the primary key a single column?
173
+ column_definitions.one? { |c| c["pk"] > 0 }
109
174
  end
110
175
 
111
176
  def data_source_sql(name = nil, type: nil)
@@ -131,6 +196,19 @@ module ActiveRecord
131
196
  scope[:type] = type if type
132
197
  scope
133
198
  end
199
+
200
+ def assert_valid_deferrable(deferrable)
201
+ return if !deferrable || %i(immediate deferred).include?(deferrable)
202
+
203
+ raise ArgumentError, "deferrable must be `:immediate` or `:deferred`, got: `#{deferrable.inspect}`"
204
+ end
205
+
206
+ def extract_generated_type(field)
207
+ case field["hidden"]
208
+ when 2 then :virtual
209
+ when 3 then :stored
210
+ end
211
+ end
134
212
  end
135
213
  end
136
214
  end