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
@@ -5,33 +5,112 @@ require "active_support/multibyte/chars"
5
5
 
6
6
  module ActiveRecord
7
7
  module ConnectionAdapters # :nodoc:
8
+ # = Active Record Connection Adapters \Quoting
8
9
  module Quoting
10
+ extend ActiveSupport::Concern
11
+
12
+ module ClassMethods # :nodoc:
13
+ # Regexp for column names (with or without a table name prefix).
14
+ # Matches the following:
15
+ #
16
+ # "#{table_name}.#{column_name}"
17
+ # "#{column_name}"
18
+ def column_name_matcher
19
+ /
20
+ \A
21
+ (
22
+ (?:
23
+ # table_name.column_name | function(one or no argument)
24
+ ((?:\w+\.)?\w+ | \w+\((?:|\g<2>)\))
25
+ )
26
+ (?:(?:\s+AS)?\s+\w+)?
27
+ )
28
+ (?:\s*,\s*\g<1>)*
29
+ \z
30
+ /ix
31
+ end
32
+
33
+ # Regexp for column names with order (with or without a table name prefix,
34
+ # with or without various order modifiers). Matches the following:
35
+ #
36
+ # "#{table_name}.#{column_name}"
37
+ # "#{table_name}.#{column_name} #{direction}"
38
+ # "#{table_name}.#{column_name} #{direction} NULLS FIRST"
39
+ # "#{table_name}.#{column_name} NULLS LAST"
40
+ # "#{column_name}"
41
+ # "#{column_name} #{direction}"
42
+ # "#{column_name} #{direction} NULLS FIRST"
43
+ # "#{column_name} NULLS LAST"
44
+ def column_name_with_order_matcher
45
+ /
46
+ \A
47
+ (
48
+ (?:
49
+ # table_name.column_name | function(one or no argument)
50
+ ((?:\w+\.)?\w+ | \w+\((?:|\g<2>)\))
51
+ )
52
+ (?:\s+ASC|\s+DESC)?
53
+ (?:\s+NULLS\s+(?:FIRST|LAST))?
54
+ )
55
+ (?:\s*,\s*\g<1>)*
56
+ \z
57
+ /ix
58
+ end
59
+
60
+ # Quotes the column name. Must be implemented by subclasses
61
+ def quote_column_name(column_name)
62
+ raise NotImplementedError
63
+ end
64
+
65
+ # Quotes the table name. Defaults to column name quoting.
66
+ def quote_table_name(table_name)
67
+ quote_column_name(table_name)
68
+ end
69
+ end
70
+
9
71
  # Quotes the column value to help prevent
10
72
  # {SQL injection attacks}[https://en.wikipedia.org/wiki/SQL_injection].
11
73
  def quote(value)
12
- value = id_value_for_database(value) if value.is_a?(Base)
13
-
14
- if value.respond_to?(:value_for_database)
15
- value = value.value_for_database
74
+ case value
75
+ when String, Symbol, ActiveSupport::Multibyte::Chars
76
+ "'#{quote_string(value.to_s)}'"
77
+ when true then quoted_true
78
+ when false then quoted_false
79
+ when nil then "NULL"
80
+ # BigDecimals need to be put in a non-normalized form and quoted.
81
+ when BigDecimal then value.to_s("F")
82
+ when Numeric then value.to_s
83
+ when Type::Binary::Data then quoted_binary(value)
84
+ when Type::Time::Value then "'#{quoted_time(value)}'"
85
+ when Date, Time then "'#{quoted_date(value)}'"
86
+ when Class then "'#{value}'"
87
+ else raise TypeError, "can't quote #{value.class.name}"
16
88
  end
17
-
18
- _quote(value)
19
89
  end
20
90
 
21
91
  # Cast a +value+ to a type that the database understands. For example,
22
92
  # SQLite does not understand dates, so this method will convert a Date
23
93
  # to a String.
24
- def type_cast(value, column = nil)
25
- value = id_value_for_database(value) if value.is_a?(Base)
26
-
27
- if column
28
- value = type_cast_from_column(column, value)
94
+ def type_cast(value)
95
+ case value
96
+ when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
97
+ value.to_s
98
+ when true then unquoted_true
99
+ when false then unquoted_false
100
+ # BigDecimals need to be put in a non-normalized form and quoted.
101
+ when BigDecimal then value.to_s("F")
102
+ when nil, Numeric, String then value
103
+ when Type::Time::Value then quoted_time(value)
104
+ when Date, Time then quoted_date(value)
105
+ else raise TypeError, "can't cast #{value.class.name}"
29
106
  end
107
+ end
30
108
 
31
- _type_cast(value)
32
- rescue TypeError
33
- to_type = column ? " to #{column.type}" : ""
34
- raise TypeError, "can't cast #{value.class}#{to_type}"
109
+ # Cast a value to be used as a bound parameter of unknown type. For example,
110
+ # MySQL might perform dangerous castings when comparing a string to a number,
111
+ # so this method will cast numbers to string.
112
+ def cast_bound_value(value) # :nodoc:
113
+ value
35
114
  end
36
115
 
37
116
  # If you are having to call this function, you are likely doing something
@@ -43,16 +122,6 @@ module ActiveRecord
43
122
  # represent the type doesn't sufficiently reflect the differences
44
123
  # (varchar vs binary) for example. The type used to get this primitive
45
124
  # should have been provided before reaching the connection adapter.
46
- def type_cast_from_column(column, value) # :nodoc:
47
- if column
48
- type = lookup_cast_type_from_column(column)
49
- type.serialize(value)
50
- else
51
- value
52
- end
53
- end
54
-
55
- # See docs for #type_cast_from_column
56
125
  def lookup_cast_type_from_column(column) # :nodoc:
57
126
  lookup_cast_type(column.sql_type)
58
127
  end
@@ -60,23 +129,23 @@ module ActiveRecord
60
129
  # Quotes a string, escaping any ' (single quote) and \ (backslash)
61
130
  # characters.
62
131
  def quote_string(s)
63
- s.gsub('\\', '\&\&').gsub("'", "''") # ' (for ruby-mode)
132
+ s.gsub("\\", '\&\&').gsub("'", "''") # ' (for ruby-mode)
64
133
  end
65
134
 
66
- # Quotes the column name. Defaults to no quoting.
135
+ # Quotes the column name.
67
136
  def quote_column_name(column_name)
68
- column_name.to_s
137
+ self.class.quote_column_name(column_name)
69
138
  end
70
139
 
71
- # Quotes the table name. Defaults to column name quoting.
140
+ # Quotes the table name.
72
141
  def quote_table_name(table_name)
73
- quote_column_name(table_name)
142
+ self.class.quote_table_name(table_name)
74
143
  end
75
144
 
76
145
  # Override to return the quoted table name for assignment. Defaults to
77
146
  # table quoting.
78
147
  #
79
- # This works for mysql2 where table.column can be used to
148
+ # This works for MySQL where table.column can be used to
80
149
  # resolve ambiguity.
81
150
  #
82
151
  # We override this in the sqlite3 and postgresql adapters to use only
@@ -114,16 +183,16 @@ module ActiveRecord
114
183
  # if the value is a Time responding to usec.
115
184
  def quoted_date(value)
116
185
  if value.acts_like?(:time)
117
- zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
118
-
119
- if value.respond_to?(zone_conversion_method)
120
- value = value.send(zone_conversion_method)
186
+ if default_timezone == :utc
187
+ value = value.getutc if !value.utc?
188
+ else
189
+ value = value.getlocal
121
190
  end
122
191
  end
123
192
 
124
- result = value.to_s(:db)
193
+ result = value.to_fs(:db)
125
194
  if value.respond_to?(:usec) && value.usec > 0
126
- "#{result}.#{sprintf("%06d", value.usec)}"
195
+ result << "." << sprintf("%06d", value.usec)
127
196
  else
128
197
  result
129
198
  end
@@ -139,113 +208,32 @@ module ActiveRecord
139
208
  end
140
209
 
141
210
  def sanitize_as_sql_comment(value) # :nodoc:
142
- value.to_s.gsub(%r{ (/ (?: | \g<1>) \*) \+? \s* | \s* (\* (?: | \g<2>) /) }x, "")
143
- end
144
-
145
- def column_name_matcher # :nodoc:
146
- COLUMN_NAME
147
- end
148
-
149
- def column_name_with_order_matcher # :nodoc:
150
- COLUMN_NAME_WITH_ORDER
211
+ # Sanitize a string to appear within a SQL comment
212
+ # For compatibility, this also surrounding "/*+", "/*", and "*/"
213
+ # charcacters, possibly with single surrounding space.
214
+ # Then follows that by replacing any internal "*/" or "/ *" with
215
+ # "* /" or "/ *"
216
+ comment = value.to_s.dup
217
+ comment.gsub!(%r{\A\s*/\*\+?\s?|\s?\*/\s*\Z}, "")
218
+ comment.gsub!("*/", "* /")
219
+ comment.gsub!("/*", "/ *")
220
+ comment
151
221
  end
152
222
 
153
- # Regexp for column names (with or without a table name prefix).
154
- # Matches the following:
155
- #
156
- # "#{table_name}.#{column_name}"
157
- # "#{column_name}"
158
- COLUMN_NAME = /
159
- \A
160
- (
161
- (?:
162
- # table_name.column_name | function(one or no argument)
163
- ((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
164
- )
165
- (?:\s+AS\s+\w+)?
166
- )
167
- (?:\s*,\s*\g<1>)*
168
- \z
169
- /ix
170
-
171
- # Regexp for column names with order (with or without a table name prefix,
172
- # with or without various order modifiers). Matches the following:
173
- #
174
- # "#{table_name}.#{column_name}"
175
- # "#{table_name}.#{column_name} #{direction}"
176
- # "#{table_name}.#{column_name} #{direction} NULLS FIRST"
177
- # "#{table_name}.#{column_name} NULLS LAST"
178
- # "#{column_name}"
179
- # "#{column_name} #{direction}"
180
- # "#{column_name} #{direction} NULLS FIRST"
181
- # "#{column_name} NULLS LAST"
182
- COLUMN_NAME_WITH_ORDER = /
183
- \A
184
- (
185
- (?:
186
- # table_name.column_name | function(one or no argument)
187
- ((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
188
- )
189
- (?:\s+ASC|\s+DESC)?
190
- (?:\s+NULLS\s+(?:FIRST|LAST))?
191
- )
192
- (?:\s*,\s*\g<1>)*
193
- \z
194
- /ix
195
-
196
- private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
197
-
198
223
  private
199
224
  def type_casted_binds(binds)
200
- if binds.first.is_a?(Array)
201
- binds.map { |column, value| type_cast(value, column) }
202
- else
203
- binds.map { |attr| type_cast(attr.value_for_database) }
225
+ binds.map do |value|
226
+ if ActiveModel::Attribute === value
227
+ type_cast(value.value_for_database)
228
+ else
229
+ type_cast(value)
230
+ end
204
231
  end
205
232
  end
206
233
 
207
234
  def lookup_cast_type(sql_type)
208
235
  type_map.lookup(sql_type)
209
236
  end
210
-
211
- def id_value_for_database(value)
212
- if primary_key = value.class.primary_key
213
- value.instance_variable_get(:@attributes)[primary_key].value_for_database
214
- end
215
- end
216
-
217
- def _quote(value)
218
- case value
219
- when String, Symbol, ActiveSupport::Multibyte::Chars
220
- "'#{quote_string(value.to_s)}'"
221
- when true then quoted_true
222
- when false then quoted_false
223
- when nil then "NULL"
224
- # BigDecimals need to be put in a non-normalized form and quoted.
225
- when BigDecimal then value.to_s("F")
226
- when Numeric, ActiveSupport::Duration then value.to_s
227
- when Type::Binary::Data then quoted_binary(value)
228
- when Type::Time::Value then "'#{quoted_time(value)}'"
229
- when Date, Time then "'#{quoted_date(value)}'"
230
- when Class then "'#{value}'"
231
- else raise TypeError, "can't quote #{value.class.name}"
232
- end
233
- end
234
-
235
- def _type_cast(value)
236
- case value
237
- when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
238
- value.to_s
239
- when true then unquoted_true
240
- when false then unquoted_false
241
- # BigDecimals need to be put in a non-normalized form and quoted.
242
- when BigDecimal then value.to_s("F")
243
- when nil, Numeric, String then value
244
- when Type::Time::Value then quoted_time(value)
245
- when Date, Time then quoted_date(value)
246
- else raise TypeError
247
- end
248
- end
249
237
  end
250
238
  end
251
239
  end
@@ -2,21 +2,22 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters
5
+ # = Active Record Connection Adapters \Savepoints
5
6
  module Savepoints
6
7
  def current_savepoint_name
7
8
  current_transaction.savepoint_name
8
9
  end
9
10
 
10
11
  def create_savepoint(name = current_savepoint_name)
11
- execute("SAVEPOINT #{name}")
12
+ internal_execute("SAVEPOINT #{name}", "TRANSACTION")
12
13
  end
13
14
 
14
15
  def exec_rollback_to_savepoint(name = current_savepoint_name)
15
- execute("ROLLBACK TO SAVEPOINT #{name}")
16
+ internal_execute("ROLLBACK TO SAVEPOINT #{name}", "TRANSACTION")
16
17
  end
17
18
 
18
19
  def release_savepoint(name = current_savepoint_name)
19
- execute("RELEASE SAVEPOINT #{name}")
20
+ internal_execute("RELEASE SAVEPOINT #{name}", "TRANSACTION")
20
21
  end
21
22
  end
22
23
  end
@@ -2,152 +2,189 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters
5
- class AbstractAdapter
6
- class SchemaCreation # :nodoc:
7
- def initialize(conn)
8
- @conn = conn
9
- @cache = {}
5
+ class SchemaCreation # :nodoc:
6
+ def initialize(conn)
7
+ @conn = conn
8
+ @cache = {}
9
+ end
10
+
11
+ def accept(o)
12
+ m = @cache[o.class] ||= "visit_#{o.class.name.split('::').last}"
13
+ send m, o
14
+ end
15
+
16
+ delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
17
+ :options_include_default?, :supports_indexes_in_create?, :use_foreign_keys?,
18
+ :quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?,
19
+ :supports_index_include?, :supports_exclusion_constraints?, :supports_unique_constraints?,
20
+ :supports_nulls_not_distinct?,
21
+ to: :@conn, private: true
22
+
23
+ private
24
+ def visit_AlterTable(o)
25
+ sql = +"ALTER TABLE #{quote_table_name(o.name)} "
26
+ sql << o.adds.map { |col| accept col }.join(" ")
27
+ sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(" ")
28
+ sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ")
29
+ sql << o.check_constraint_adds.map { |con| visit_AddCheckConstraint con }.join(" ")
30
+ sql << o.check_constraint_drops.map { |con| visit_DropCheckConstraint con }.join(" ")
31
+ end
32
+
33
+ def visit_ColumnDefinition(o)
34
+ o.sql_type = type_to_sql(o.type, **o.options)
35
+ column_sql = +"#{quote_column_name(o.name)} #{o.sql_type}"
36
+ add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
37
+ column_sql
10
38
  end
11
39
 
12
- def accept(o)
13
- m = @cache[o.class] ||= "visit_#{o.class.name.split('::').last}"
14
- send m, o
40
+ def visit_AddColumnDefinition(o)
41
+ +"ADD #{accept(o.column)}"
15
42
  end
16
43
 
17
- delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
18
- :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options,
19
- to: :@conn, private: true
44
+ def visit_TableDefinition(o)
45
+ create_sql = +"CREATE#{table_modifier_in_create(o)} TABLE "
46
+ create_sql << "IF NOT EXISTS " if o.if_not_exists
47
+ create_sql << "#{quote_table_name(o.name)} "
20
48
 
21
- private
49
+ statements = o.columns.map { |c| accept c }
50
+ statements << accept(o.primary_keys) if o.primary_keys
22
51
 
23
- def visit_AlterTable(o)
24
- sql = +"ALTER TABLE #{quote_table_name(o.name)} "
25
- sql << o.adds.map { |col| accept col }.join(" ")
26
- sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(" ")
27
- sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ")
52
+ if supports_indexes_in_create?
53
+ statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
28
54
  end
29
55
 
30
- def visit_ColumnDefinition(o)
31
- o.sql_type = type_to_sql(o.type, o.options)
32
- column_sql = +"#{quote_column_name(o.name)} #{o.sql_type}"
33
- add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
34
- column_sql
56
+ if use_foreign_keys?
57
+ statements.concat(o.foreign_keys.map { |fk| accept fk })
35
58
  end
36
59
 
37
- def visit_AddColumnDefinition(o)
38
- +"ADD #{accept(o.column)}"
60
+ if supports_check_constraints?
61
+ statements.concat(o.check_constraints.map { |chk| accept chk })
39
62
  end
40
63
 
41
- def visit_TableDefinition(o)
42
- create_sql = +"CREATE#{table_modifier_in_create(o)} TABLE "
43
- create_sql << "IF NOT EXISTS " if o.if_not_exists
44
- create_sql << "#{quote_table_name(o.name)} "
64
+ if supports_exclusion_constraints?
65
+ statements.concat(o.exclusion_constraints.map { |exc| accept exc })
66
+ end
45
67
 
46
- statements = o.columns.map { |c| accept c }
47
- statements << accept(o.primary_keys) if o.primary_keys
68
+ if supports_unique_constraints?
69
+ statements.concat(o.unique_constraints.map { |exc| accept exc })
70
+ end
48
71
 
49
- if supports_indexes_in_create?
50
- statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
51
- end
72
+ create_sql << "(#{statements.join(', ')})" if statements.present?
73
+ add_table_options!(create_sql, o)
74
+ create_sql << " AS #{to_sql(o.as)}" if o.as
75
+ create_sql
76
+ end
52
77
 
53
- if supports_foreign_keys?
54
- statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
55
- end
78
+ def visit_PrimaryKeyDefinition(o)
79
+ "PRIMARY KEY (#{o.name.map { |name| quote_column_name(name) }.join(', ')})"
80
+ end
56
81
 
57
- create_sql << "(#{statements.join(', ')})" if statements.present?
58
- add_table_options!(create_sql, table_options(o))
59
- create_sql << " AS #{to_sql(o.as)}" if o.as
60
- create_sql
61
- end
82
+ def visit_ForeignKeyDefinition(o)
83
+ quoted_columns = Array(o.column).map { |c| quote_column_name(c) }
84
+ quoted_primary_keys = Array(o.primary_key).map { |c| quote_column_name(c) }
85
+ sql = +<<~SQL
86
+ CONSTRAINT #{quote_column_name(o.name)}
87
+ FOREIGN KEY (#{quoted_columns.join(", ")})
88
+ REFERENCES #{quote_table_name(o.to_table)} (#{quoted_primary_keys.join(", ")})
89
+ SQL
90
+ sql << " #{action_sql('DELETE', o.on_delete)}" if o.on_delete
91
+ sql << " #{action_sql('UPDATE', o.on_update)}" if o.on_update
92
+ sql
93
+ end
62
94
 
63
- def visit_PrimaryKeyDefinition(o)
64
- "PRIMARY KEY (#{o.name.map { |name| quote_column_name(name) }.join(', ')})"
65
- end
95
+ def visit_AddForeignKey(o)
96
+ "ADD #{accept(o)}"
97
+ end
66
98
 
67
- def visit_ForeignKeyDefinition(o)
68
- sql = +<<~SQL
69
- CONSTRAINT #{quote_column_name(o.name)}
70
- FOREIGN KEY (#{quote_column_name(o.column)})
71
- REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
72
- SQL
73
- sql << " #{action_sql('DELETE', o.on_delete)}" if o.on_delete
74
- sql << " #{action_sql('UPDATE', o.on_update)}" if o.on_update
75
- sql
76
- end
99
+ def visit_DropForeignKey(name)
100
+ "DROP CONSTRAINT #{quote_column_name(name)}"
101
+ end
77
102
 
78
- def visit_AddForeignKey(o)
79
- "ADD #{accept(o)}"
80
- end
103
+ def visit_CreateIndexDefinition(o)
104
+ index = o.index
105
+
106
+ sql = ["CREATE"]
107
+ sql << "UNIQUE" if index.unique
108
+ sql << "INDEX"
109
+ sql << o.algorithm if o.algorithm
110
+ sql << "IF NOT EXISTS" if o.if_not_exists
111
+ sql << index.type if index.type
112
+ sql << "#{quote_column_name(index.name)} ON #{quote_table_name(index.table)}"
113
+ sql << "USING #{index.using}" if supports_index_using? && index.using
114
+ sql << "(#{quoted_columns(index)})"
115
+ sql << "INCLUDE (#{quoted_include_columns(index.include)})" if supports_index_include? && index.include
116
+ sql << "NULLS NOT DISTINCT" if supports_nulls_not_distinct? && index.nulls_not_distinct
117
+ sql << "WHERE #{index.where}" if supports_partial_index? && index.where
118
+
119
+ sql.join(" ")
120
+ end
81
121
 
82
- def visit_DropForeignKey(name)
83
- "DROP CONSTRAINT #{quote_column_name(name)}"
84
- end
122
+ def visit_CheckConstraintDefinition(o)
123
+ "CONSTRAINT #{o.name} CHECK (#{o.expression})"
124
+ end
85
125
 
86
- def table_options(o)
87
- table_options = {}
88
- table_options[:comment] = o.comment
89
- table_options[:options] = o.options
90
- table_options
91
- end
126
+ def visit_AddCheckConstraint(o)
127
+ "ADD #{accept(o)}"
128
+ end
92
129
 
93
- def add_table_options!(create_sql, options)
94
- if options_sql = options[:options]
95
- create_sql << " #{options_sql}"
96
- end
97
- create_sql
98
- end
130
+ def visit_DropCheckConstraint(name)
131
+ "DROP CONSTRAINT #{quote_column_name(name)}"
132
+ end
99
133
 
100
- def column_options(o)
101
- o.options.merge(column: o)
102
- end
134
+ def quoted_columns(o)
135
+ String === o.columns ? o.columns : quoted_columns_for_index(o.columns, o.column_options)
136
+ end
103
137
 
104
- def add_column_options!(sql, options)
105
- sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
106
- # must explicitly check for :null to allow change_column to work on migrations
107
- if options[:null] == false
108
- sql << " NOT NULL"
109
- end
110
- if options[:auto_increment] == true
111
- sql << " AUTO_INCREMENT"
112
- end
113
- if options[:primary_key] == true
114
- sql << " PRIMARY KEY"
115
- end
116
- sql
117
- end
138
+ def supports_index_using?
139
+ true
140
+ end
118
141
 
119
- def to_sql(sql)
120
- sql = sql.to_sql if sql.respond_to?(:to_sql)
121
- sql
122
- end
142
+ def add_table_options!(create_sql, o)
143
+ create_sql << " #{o.options}" if o.options
144
+ create_sql
145
+ end
123
146
 
124
- # Returns any SQL string to go between CREATE and TABLE. May be nil.
125
- def table_modifier_in_create(o)
126
- " TEMPORARY" if o.temporary
127
- end
147
+ def column_options(o)
148
+ o.options.merge(column: o)
149
+ end
128
150
 
129
- def foreign_key_in_create(from_table, to_table, options)
130
- prefix = ActiveRecord::Base.table_name_prefix
131
- suffix = ActiveRecord::Base.table_name_suffix
132
- to_table = "#{prefix}#{to_table}#{suffix}"
133
- options = foreign_key_options(from_table, to_table, options)
134
- accept ForeignKeyDefinition.new(from_table, to_table, options)
151
+ def add_column_options!(sql, options)
152
+ sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
153
+ # must explicitly check for :null to allow change_column to work on migrations
154
+ if options[:null] == false
155
+ sql << " NOT NULL"
156
+ end
157
+ if options[:auto_increment] == true
158
+ sql << " AUTO_INCREMENT"
159
+ end
160
+ if options[:primary_key] == true
161
+ sql << " PRIMARY KEY"
135
162
  end
163
+ sql
164
+ end
165
+
166
+ def to_sql(sql)
167
+ sql = sql.to_sql if sql.respond_to?(:to_sql)
168
+ sql
169
+ end
170
+
171
+ # Returns any SQL string to go between CREATE and TABLE. May be nil.
172
+ def table_modifier_in_create(o)
173
+ " TEMPORARY" if o.temporary
174
+ end
136
175
 
137
- def action_sql(action, dependency)
138
- case dependency
139
- when :nullify then "ON #{action} SET NULL"
140
- when :cascade then "ON #{action} CASCADE"
141
- when :restrict then "ON #{action} RESTRICT"
142
- else
143
- raise ArgumentError, <<~MSG
144
- '#{dependency}' is not supported for :on_update or :on_delete.
145
- Supported values are: :nullify, :cascade, :restrict
146
- MSG
147
- end
176
+ def action_sql(action, dependency)
177
+ case dependency
178
+ when :nullify then "ON #{action} SET NULL"
179
+ when :cascade then "ON #{action} CASCADE"
180
+ when :restrict then "ON #{action} RESTRICT"
181
+ else
182
+ raise ArgumentError, <<~MSG
183
+ '#{dependency}' is not supported for :on_update or :on_delete.
184
+ Supported values are: :nullify, :cascade, :restrict
185
+ MSG
148
186
  end
149
- end
187
+ end
150
188
  end
151
- SchemaCreation = AbstractAdapter::SchemaCreation # :nodoc:
152
189
  end
153
190
  end