activerecord 5.2.4.4 → 6.0.3.4

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

Potentially problematic release.


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

Files changed (292) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +777 -552
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +5 -3
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record.rb +10 -2
  7. data/lib/active_record/advisory_lock_base.rb +18 -0
  8. data/lib/active_record/aggregations.rb +4 -3
  9. data/lib/active_record/association_relation.rb +10 -8
  10. data/lib/active_record/associations.rb +21 -16
  11. data/lib/active_record/associations/alias_tracker.rb +0 -1
  12. data/lib/active_record/associations/association.rb +56 -19
  13. data/lib/active_record/associations/association_scope.rb +4 -6
  14. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  16. data/lib/active_record/associations/builder/association.rb +14 -18
  17. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  18. data/lib/active_record/associations/builder/collection_association.rb +3 -13
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
  20. data/lib/active_record/associations/builder/has_many.rb +2 -0
  21. data/lib/active_record/associations/builder/has_one.rb +35 -1
  22. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  23. data/lib/active_record/associations/collection_association.rb +12 -23
  24. data/lib/active_record/associations/collection_proxy.rb +13 -17
  25. data/lib/active_record/associations/foreign_association.rb +7 -0
  26. data/lib/active_record/associations/has_many_association.rb +2 -11
  27. data/lib/active_record/associations/has_many_through_association.rb +14 -14
  28. data/lib/active_record/associations/has_one_association.rb +28 -30
  29. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  30. data/lib/active_record/associations/join_dependency.rb +37 -28
  31. data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
  32. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  33. data/lib/active_record/associations/preloader.rb +39 -32
  34. data/lib/active_record/associations/preloader/association.rb +38 -36
  35. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  36. data/lib/active_record/associations/singular_association.rb +2 -16
  37. data/lib/active_record/attribute_assignment.rb +7 -11
  38. data/lib/active_record/attribute_decorators.rb +0 -2
  39. data/lib/active_record/attribute_methods.rb +28 -100
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
  41. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  42. data/lib/active_record/attribute_methods/primary_key.rb +15 -24
  43. data/lib/active_record/attribute_methods/query.rb +2 -3
  44. data/lib/active_record/attribute_methods/read.rb +15 -54
  45. data/lib/active_record/attribute_methods/serialization.rb +1 -2
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
  47. data/lib/active_record/attribute_methods/write.rb +17 -25
  48. data/lib/active_record/attributes.rb +13 -1
  49. data/lib/active_record/autosave_association.rb +3 -5
  50. data/lib/active_record/base.rb +2 -3
  51. data/lib/active_record/callbacks.rb +6 -21
  52. data/lib/active_record/coders/yaml_column.rb +0 -1
  53. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +103 -18
  54. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  55. data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
  56. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
  57. data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
  58. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
  59. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +100 -72
  60. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  61. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
  62. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
  63. data/lib/active_record/connection_adapters/abstract_adapter.rb +191 -43
  64. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +142 -215
  65. data/lib/active_record/connection_adapters/column.rb +17 -13
  66. data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
  67. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  68. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  69. data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
  70. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
  71. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  72. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
  73. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  74. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  75. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +132 -16
  76. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
  78. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  79. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  82. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  83. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  91. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  92. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  93. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  94. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  96. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  97. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +63 -75
  98. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
  101. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  102. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  103. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
  104. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  105. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +135 -146
  107. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  108. data/lib/active_record/connection_handling.rb +139 -26
  109. data/lib/active_record/core.rb +103 -61
  110. data/lib/active_record/counter_cache.rb +8 -30
  111. data/lib/active_record/database_configurations.rb +233 -0
  112. data/lib/active_record/database_configurations/database_config.rb +37 -0
  113. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  114. data/lib/active_record/database_configurations/url_config.rb +78 -0
  115. data/lib/active_record/dynamic_matchers.rb +3 -4
  116. data/lib/active_record/enum.rb +37 -7
  117. data/lib/active_record/errors.rb +15 -7
  118. data/lib/active_record/explain.rb +1 -2
  119. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  120. data/lib/active_record/fixture_set/render_context.rb +17 -0
  121. data/lib/active_record/fixture_set/table_row.rb +152 -0
  122. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  123. data/lib/active_record/fixtures.rb +144 -474
  124. data/lib/active_record/gem_version.rb +3 -3
  125. data/lib/active_record/inheritance.rb +13 -6
  126. data/lib/active_record/insert_all.rb +179 -0
  127. data/lib/active_record/integration.rb +68 -16
  128. data/lib/active_record/internal_metadata.rb +11 -3
  129. data/lib/active_record/locking/optimistic.rb +5 -7
  130. data/lib/active_record/locking/pessimistic.rb +3 -3
  131. data/lib/active_record/log_subscriber.rb +8 -27
  132. data/lib/active_record/middleware/database_selector.rb +74 -0
  133. data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
  134. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  135. data/lib/active_record/migration.rb +104 -85
  136. data/lib/active_record/migration/command_recorder.rb +54 -22
  137. data/lib/active_record/migration/compatibility.rb +79 -52
  138. data/lib/active_record/migration/join_table.rb +0 -1
  139. data/lib/active_record/model_schema.rb +33 -11
  140. data/lib/active_record/nested_attributes.rb +2 -4
  141. data/lib/active_record/no_touching.rb +9 -2
  142. data/lib/active_record/null_relation.rb +0 -1
  143. data/lib/active_record/persistence.rb +232 -29
  144. data/lib/active_record/query_cache.rb +11 -4
  145. data/lib/active_record/querying.rb +33 -21
  146. data/lib/active_record/railtie.rb +80 -43
  147. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  148. data/lib/active_record/railties/controller_runtime.rb +30 -35
  149. data/lib/active_record/railties/databases.rake +199 -46
  150. data/lib/active_record/reflection.rb +40 -38
  151. data/lib/active_record/relation.rb +322 -80
  152. data/lib/active_record/relation/batches.rb +13 -11
  153. data/lib/active_record/relation/calculations.rb +54 -48
  154. data/lib/active_record/relation/delegation.rb +33 -49
  155. data/lib/active_record/relation/finder_methods.rb +23 -28
  156. data/lib/active_record/relation/from_clause.rb +4 -0
  157. data/lib/active_record/relation/merger.rb +11 -21
  158. data/lib/active_record/relation/predicate_builder.rb +5 -11
  159. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  160. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  161. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  162. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  163. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  164. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  165. data/lib/active_record/relation/query_attribute.rb +13 -8
  166. data/lib/active_record/relation/query_methods.rb +221 -70
  167. data/lib/active_record/relation/spawn_methods.rb +1 -2
  168. data/lib/active_record/relation/where_clause.rb +14 -11
  169. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  170. data/lib/active_record/result.rb +30 -12
  171. data/lib/active_record/sanitization.rb +32 -40
  172. data/lib/active_record/schema.rb +2 -11
  173. data/lib/active_record/schema_dumper.rb +22 -7
  174. data/lib/active_record/schema_migration.rb +6 -2
  175. data/lib/active_record/scoping.rb +8 -9
  176. data/lib/active_record/scoping/default.rb +4 -6
  177. data/lib/active_record/scoping/named.rb +21 -17
  178. data/lib/active_record/statement_cache.rb +30 -3
  179. data/lib/active_record/store.rb +87 -8
  180. data/lib/active_record/suppressor.rb +2 -2
  181. data/lib/active_record/table_metadata.rb +23 -15
  182. data/lib/active_record/tasks/database_tasks.rb +194 -25
  183. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
  184. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
  185. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
  186. data/lib/active_record/test_databases.rb +23 -0
  187. data/lib/active_record/test_fixtures.rb +225 -0
  188. data/lib/active_record/timestamp.rb +39 -26
  189. data/lib/active_record/touch_later.rb +5 -4
  190. data/lib/active_record/transactions.rb +64 -73
  191. data/lib/active_record/translation.rb +1 -1
  192. data/lib/active_record/type.rb +3 -5
  193. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  194. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  195. data/lib/active_record/type/serialized.rb +0 -1
  196. data/lib/active_record/type/type_map.rb +0 -1
  197. data/lib/active_record/type/unsigned_integer.rb +0 -1
  198. data/lib/active_record/type_caster/connection.rb +15 -14
  199. data/lib/active_record/type_caster/map.rb +1 -4
  200. data/lib/active_record/validations.rb +3 -3
  201. data/lib/active_record/validations/associated.rb +1 -2
  202. data/lib/active_record/validations/uniqueness.rb +15 -27
  203. data/lib/arel.rb +62 -0
  204. data/lib/arel/alias_predication.rb +9 -0
  205. data/lib/arel/attributes.rb +22 -0
  206. data/lib/arel/attributes/attribute.rb +37 -0
  207. data/lib/arel/collectors/bind.rb +24 -0
  208. data/lib/arel/collectors/composite.rb +31 -0
  209. data/lib/arel/collectors/plain_string.rb +20 -0
  210. data/lib/arel/collectors/sql_string.rb +20 -0
  211. data/lib/arel/collectors/substitute_binds.rb +28 -0
  212. data/lib/arel/crud.rb +42 -0
  213. data/lib/arel/delete_manager.rb +18 -0
  214. data/lib/arel/errors.rb +9 -0
  215. data/lib/arel/expressions.rb +29 -0
  216. data/lib/arel/factory_methods.rb +49 -0
  217. data/lib/arel/insert_manager.rb +49 -0
  218. data/lib/arel/math.rb +45 -0
  219. data/lib/arel/nodes.rb +68 -0
  220. data/lib/arel/nodes/and.rb +32 -0
  221. data/lib/arel/nodes/ascending.rb +23 -0
  222. data/lib/arel/nodes/binary.rb +52 -0
  223. data/lib/arel/nodes/bind_param.rb +36 -0
  224. data/lib/arel/nodes/case.rb +55 -0
  225. data/lib/arel/nodes/casted.rb +50 -0
  226. data/lib/arel/nodes/comment.rb +29 -0
  227. data/lib/arel/nodes/count.rb +12 -0
  228. data/lib/arel/nodes/delete_statement.rb +45 -0
  229. data/lib/arel/nodes/descending.rb +23 -0
  230. data/lib/arel/nodes/equality.rb +18 -0
  231. data/lib/arel/nodes/extract.rb +24 -0
  232. data/lib/arel/nodes/false.rb +16 -0
  233. data/lib/arel/nodes/full_outer_join.rb +8 -0
  234. data/lib/arel/nodes/function.rb +44 -0
  235. data/lib/arel/nodes/grouping.rb +8 -0
  236. data/lib/arel/nodes/in.rb +8 -0
  237. data/lib/arel/nodes/infix_operation.rb +80 -0
  238. data/lib/arel/nodes/inner_join.rb +8 -0
  239. data/lib/arel/nodes/insert_statement.rb +37 -0
  240. data/lib/arel/nodes/join_source.rb +20 -0
  241. data/lib/arel/nodes/matches.rb +18 -0
  242. data/lib/arel/nodes/named_function.rb +23 -0
  243. data/lib/arel/nodes/node.rb +50 -0
  244. data/lib/arel/nodes/node_expression.rb +13 -0
  245. data/lib/arel/nodes/outer_join.rb +8 -0
  246. data/lib/arel/nodes/over.rb +15 -0
  247. data/lib/arel/nodes/regexp.rb +16 -0
  248. data/lib/arel/nodes/right_outer_join.rb +8 -0
  249. data/lib/arel/nodes/select_core.rb +67 -0
  250. data/lib/arel/nodes/select_statement.rb +41 -0
  251. data/lib/arel/nodes/sql_literal.rb +16 -0
  252. data/lib/arel/nodes/string_join.rb +11 -0
  253. data/lib/arel/nodes/table_alias.rb +27 -0
  254. data/lib/arel/nodes/terminal.rb +16 -0
  255. data/lib/arel/nodes/true.rb +16 -0
  256. data/lib/arel/nodes/unary.rb +45 -0
  257. data/lib/arel/nodes/unary_operation.rb +20 -0
  258. data/lib/arel/nodes/unqualified_column.rb +22 -0
  259. data/lib/arel/nodes/update_statement.rb +41 -0
  260. data/lib/arel/nodes/values_list.rb +9 -0
  261. data/lib/arel/nodes/window.rb +126 -0
  262. data/lib/arel/nodes/with.rb +11 -0
  263. data/lib/arel/order_predications.rb +13 -0
  264. data/lib/arel/predications.rb +256 -0
  265. data/lib/arel/select_manager.rb +271 -0
  266. data/lib/arel/table.rb +110 -0
  267. data/lib/arel/tree_manager.rb +72 -0
  268. data/lib/arel/update_manager.rb +34 -0
  269. data/lib/arel/visitors.rb +20 -0
  270. data/lib/arel/visitors/depth_first.rb +203 -0
  271. data/lib/arel/visitors/dot.rb +296 -0
  272. data/lib/arel/visitors/ibm_db.rb +34 -0
  273. data/lib/arel/visitors/informix.rb +62 -0
  274. data/lib/arel/visitors/mssql.rb +156 -0
  275. data/lib/arel/visitors/mysql.rb +83 -0
  276. data/lib/arel/visitors/oracle.rb +158 -0
  277. data/lib/arel/visitors/oracle12.rb +65 -0
  278. data/lib/arel/visitors/postgresql.rb +109 -0
  279. data/lib/arel/visitors/sqlite.rb +38 -0
  280. data/lib/arel/visitors/to_sql.rb +888 -0
  281. data/lib/arel/visitors/visitor.rb +45 -0
  282. data/lib/arel/visitors/where_sql.rb +22 -0
  283. data/lib/arel/window_predications.rb +9 -0
  284. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  285. data/lib/rails/generators/active_record/migration.rb +14 -2
  286. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  287. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  288. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  289. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  290. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  291. metadata +115 -29
  292. data/lib/active_record/collection_cache_key.rb +0 -53
@@ -7,7 +7,8 @@ module ActiveRecord
7
7
  module QueryCache
8
8
  class << self
9
9
  def included(base) #:nodoc:
10
- dirties_query_cache base, :insert, :update, :delete, :rollback_to_savepoint, :rollback_db_transaction
10
+ dirties_query_cache base, :insert, :update, :delete, :truncate, :truncate_tables,
11
+ :rollback_to_savepoint, :rollback_db_transaction, :exec_insert_all
11
12
 
12
13
  base.set_callback :checkout, :after, :configure_query_cache!
13
14
  base.set_callback :checkin, :after, :disable_query_cache!
@@ -17,7 +18,7 @@ module ActiveRecord
17
18
  method_names.each do |method_name|
18
19
  base.class_eval <<-end_code, __FILE__, __LINE__ + 1
19
20
  def #{method_name}(*)
20
- clear_query_cache if @query_cache_enabled
21
+ ActiveRecord::Base.clear_query_caches_for_current_thread if @query_cache_enabled
21
22
  super
22
23
  end
23
24
  end_code
@@ -108,19 +109,13 @@ module ActiveRecord
108
109
  end
109
110
 
110
111
  private
111
-
112
112
  def cache_sql(sql, name, binds)
113
113
  @lock.synchronize do
114
114
  result =
115
115
  if @query_cache[sql].key?(binds)
116
116
  ActiveSupport::Notifications.instrument(
117
117
  "sql.active_record",
118
- sql: sql,
119
- binds: binds,
120
- type_casted_binds: -> { type_casted_binds(binds) },
121
- name: name,
122
- connection_id: object_id,
123
- cached: true,
118
+ cache_notification_info(sql, name, binds)
124
119
  )
125
120
  @query_cache[sql][binds]
126
121
  else
@@ -130,6 +125,20 @@ module ActiveRecord
130
125
  end
131
126
  end
132
127
 
128
+ # Database adapters can override this method to
129
+ # provide custom cache information.
130
+ def cache_notification_info(sql, name, binds)
131
+ {
132
+ sql: sql,
133
+ binds: binds,
134
+ type_casted_binds: -> { type_casted_binds(binds) },
135
+ name: name,
136
+ connection_id: object_id,
137
+ connection: self,
138
+ cached: true
139
+ }
140
+ end
141
+
133
142
  # If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
134
143
  # queries should not be cached.
135
144
  def locked?(arel)
@@ -60,7 +60,7 @@ module ActiveRecord
60
60
  # Quotes a string, escaping any ' (single quote) and \ (backslash)
61
61
  # characters.
62
62
  def quote_string(s)
63
- s.gsub('\\'.freeze, '\&\&'.freeze).gsub("'".freeze, "''".freeze) # ' (for ruby-mode)
63
+ s.gsub('\\', '\&\&').gsub("'", "''") # ' (for ruby-mode)
64
64
  end
65
65
 
66
66
  # Quotes the column name. Defaults to no quoting.
@@ -95,7 +95,7 @@ module ActiveRecord
95
95
  end
96
96
 
97
97
  def quoted_true
98
- "TRUE".freeze
98
+ "TRUE"
99
99
  end
100
100
 
101
101
  def unquoted_true
@@ -103,7 +103,7 @@ module ActiveRecord
103
103
  end
104
104
 
105
105
  def quoted_false
106
- "FALSE".freeze
106
+ "FALSE"
107
107
  end
108
108
 
109
109
  def unquoted_false
@@ -138,15 +138,72 @@ module ActiveRecord
138
138
  "'#{quote_string(value.to_s)}'"
139
139
  end
140
140
 
141
- def type_casted_binds(binds) # :nodoc:
142
- if binds.first.is_a?(Array)
143
- binds.map { |column, value| type_cast(value, column) }
144
- else
145
- binds.map { |attr| type_cast(attr.value_for_database) }
146
- end
141
+ 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
147
  end
148
148
 
149
+ def column_name_with_order_matcher # :nodoc:
150
+ COLUMN_NAME_WITH_ORDER
151
+ end
152
+
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
+
149
198
  private
199
+ 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) }
204
+ end
205
+ end
206
+
150
207
  def lookup_cast_type(sql_type)
151
208
  type_map.lookup(sql_type)
152
209
  end
@@ -157,13 +214,9 @@ module ActiveRecord
157
214
  end
158
215
  end
159
216
 
160
- def types_which_need_no_typecasting
161
- [nil, Numeric, String]
162
- end
163
-
164
217
  def _quote(value)
165
218
  case value
166
- when String, ActiveSupport::Multibyte::Chars
219
+ when String, Symbol, ActiveSupport::Multibyte::Chars
167
220
  "'#{quote_string(value.to_s)}'"
168
221
  when true then quoted_true
169
222
  when false then quoted_false
@@ -174,7 +227,6 @@ module ActiveRecord
174
227
  when Type::Binary::Data then quoted_binary(value)
175
228
  when Type::Time::Value then "'#{quoted_time(value)}'"
176
229
  when Date, Time then "'#{quoted_date(value)}'"
177
- when Symbol then "'#{quote_string(value.to_s)}'"
178
230
  when Class then "'#{value}'"
179
231
  else raise TypeError, "can't quote #{value.class.name}"
180
232
  end
@@ -188,10 +240,9 @@ module ActiveRecord
188
240
  when false then unquoted_false
189
241
  # BigDecimals need to be put in a non-normalized form and quoted.
190
242
  when BigDecimal then value.to_s("F")
243
+ when nil, Numeric, String then value
191
244
  when Type::Time::Value then quoted_time(value)
192
245
  when Date, Time then quoted_date(value)
193
- when *types_which_need_no_typecasting
194
- value
195
246
  else raise TypeError
196
247
  end
197
248
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/string/strip"
4
-
5
3
  module ActiveRecord
6
4
  module ConnectionAdapters
7
5
  class AbstractAdapter
@@ -17,32 +15,32 @@ module ActiveRecord
17
15
  end
18
16
 
19
17
  delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
20
- :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys_in_create?, :foreign_key_options, to: :@conn
21
- private :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
22
- :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys_in_create?, :foreign_key_options
18
+ :options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options,
19
+ to: :@conn, private: true
23
20
 
24
21
  private
25
-
26
22
  def visit_AlterTable(o)
27
- sql = "ALTER TABLE #{quote_table_name(o.name)} ".dup
23
+ sql = +"ALTER TABLE #{quote_table_name(o.name)} "
28
24
  sql << o.adds.map { |col| accept col }.join(" ")
29
25
  sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(" ")
30
26
  sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ")
31
27
  end
32
28
 
33
29
  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}".dup
30
+ o.sql_type = type_to_sql(o.type, **o.options)
31
+ column_sql = +"#{quote_column_name(o.name)} #{o.sql_type}"
36
32
  add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
37
33
  column_sql
38
34
  end
39
35
 
40
36
  def visit_AddColumnDefinition(o)
41
- "ADD #{accept(o.column)}".dup
37
+ +"ADD #{accept(o.column)}"
42
38
  end
43
39
 
44
40
  def visit_TableDefinition(o)
45
- create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} ".dup
41
+ create_sql = +"CREATE#{table_modifier_in_create(o)} TABLE "
42
+ create_sql << "IF NOT EXISTS " if o.if_not_exists
43
+ create_sql << "#{quote_table_name(o.name)} "
46
44
 
47
45
  statements = o.columns.map { |c| accept c }
48
46
  statements << accept(o.primary_keys) if o.primary_keys
@@ -51,7 +49,7 @@ module ActiveRecord
51
49
  statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
52
50
  end
53
51
 
54
- if supports_foreign_keys_in_create?
52
+ if supports_foreign_keys?
55
53
  statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
56
54
  end
57
55
 
@@ -66,7 +64,7 @@ module ActiveRecord
66
64
  end
67
65
 
68
66
  def visit_ForeignKeyDefinition(o)
69
- sql = <<-SQL.strip_heredoc
67
+ sql = +<<~SQL
70
68
  CONSTRAINT #{quote_column_name(o.name)}
71
69
  FOREIGN KEY (#{quote_column_name(o.column)})
72
70
  REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
@@ -122,7 +120,15 @@ module ActiveRecord
122
120
  sql
123
121
  end
124
122
 
123
+ # Returns any SQL string to go between CREATE and TABLE. May be nil.
124
+ def table_modifier_in_create(o)
125
+ " TEMPORARY" if o.temporary
126
+ end
127
+
125
128
  def foreign_key_in_create(from_table, to_table, options)
129
+ prefix = ActiveRecord::Base.table_name_prefix
130
+ suffix = ActiveRecord::Base.table_name_suffix
131
+ to_table = "#{prefix}#{to_table}#{suffix}"
126
132
  options = foreign_key_options(from_table, to_table, options)
127
133
  accept ForeignKeyDefinition.new(from_table, to_table, options)
128
134
  end
@@ -133,7 +139,7 @@ module ActiveRecord
133
139
  when :cascade then "ON #{action} CASCADE"
134
140
  when :restrict then "ON #{action} RESTRICT"
135
141
  else
136
- raise ArgumentError, <<-MSG.strip_heredoc
142
+ raise ArgumentError, <<~MSG
137
143
  '#{dependency}' is not supported for :on_update or :on_delete.
138
144
  Supported values are: :nullify, :cascade, :restrict
139
145
  MSG
@@ -101,13 +101,13 @@ module ActiveRecord
101
101
  end
102
102
  alias validated? validate?
103
103
 
104
- def defined_for?(to_table_ord = nil, to_table: nil, **options)
105
- if to_table_ord
106
- self.to_table == to_table_ord.to_s
107
- else
108
- (to_table.nil? || to_table.to_s == self.to_table) &&
109
- options.all? { |k, v| self.options[k].to_s == v.to_s }
110
- end
104
+ def export_name_on_schema_dump?
105
+ !ActiveRecord::SchemaDumper.fk_ignore_pattern.match?(name) if name
106
+ end
107
+
108
+ def defined_for?(to_table: nil, **options)
109
+ (to_table.nil? || to_table.to_s == self.to_table) &&
110
+ options.all? { |k, v| self.options[k].to_s == v.to_s }
111
111
  end
112
112
 
113
113
  private
@@ -139,7 +139,8 @@ module ActiveRecord
139
139
 
140
140
  def add_to(table)
141
141
  columns.each do |column_options|
142
- table.column(*column_options)
142
+ kwargs = column_options.extract_options!
143
+ table.column(*column_options, **kwargs)
143
144
  end
144
145
 
145
146
  if index
@@ -147,17 +148,12 @@ module ActiveRecord
147
148
  end
148
149
 
149
150
  if foreign_key
150
- table.foreign_key(foreign_table_name, foreign_key_options)
151
+ table.foreign_key(foreign_table_name, **foreign_key_options)
151
152
  end
152
153
  end
153
154
 
154
- # TODO Change this to private once we've dropped Ruby 2.2 support.
155
- # Workaround for Ruby 2.2 "private attribute?" warning.
156
- protected
157
-
158
- attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options
159
-
160
155
  private
156
+ attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options
161
157
 
162
158
  def as_options(value)
163
159
  value.is_a?(Hash) ? value : {}
@@ -199,41 +195,44 @@ module ActiveRecord
199
195
  end
200
196
 
201
197
  module ColumnMethods
198
+ extend ActiveSupport::Concern
199
+
202
200
  # Appends a primary key definition to the table definition.
203
201
  # Can be called multiple times, but this is probably not a good idea.
204
202
  def primary_key(name, type = :primary_key, **options)
205
- column(name, type, options.merge(primary_key: true))
203
+ column(name, type, **options.merge(primary_key: true))
206
204
  end
207
205
 
206
+ ##
207
+ # :method: column
208
+ # :call-seq: column(name, type, **options)
209
+ #
208
210
  # Appends a column or columns of a specified type.
209
211
  #
210
212
  # t.string(:goat)
211
213
  # t.string(:goat, :sheep)
212
214
  #
213
215
  # See TableDefinition#column
214
- [
215
- :bigint,
216
- :binary,
217
- :boolean,
218
- :date,
219
- :datetime,
220
- :decimal,
221
- :float,
222
- :integer,
223
- :json,
224
- :string,
225
- :text,
226
- :time,
227
- :timestamp,
228
- :virtual,
229
- ].each do |column_type|
230
- module_eval <<-CODE, __FILE__, __LINE__ + 1
231
- def #{column_type}(*args, **options)
232
- args.each { |name| column(name, :#{column_type}, options) }
216
+
217
+ included do
218
+ define_column_methods :bigint, :binary, :boolean, :date, :datetime, :decimal,
219
+ :float, :integer, :json, :string, :text, :time, :timestamp, :virtual
220
+
221
+ alias :numeric :decimal
222
+ end
223
+
224
+ class_methods do
225
+ private def define_column_methods(*column_types) # :nodoc:
226
+ column_types.each do |column_type|
227
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
228
+ def #{column_type}(*names, **options)
229
+ raise ArgumentError, "Missing column name(s) for #{column_type}" if names.empty?
230
+ names.each { |name| column(name, :#{column_type}, **options) }
231
+ end
232
+ RUBY
233
233
  end
234
- CODE
234
+ end
235
235
  end
236
- alias_method :numeric, :decimal
237
236
  end
238
237
 
239
238
  # Represents the schema of an SQL table in an abstract way. This class
@@ -257,15 +256,25 @@ module ActiveRecord
257
256
  class TableDefinition
258
257
  include ColumnMethods
259
258
 
260
- attr_accessor :indexes
261
- attr_reader :name, :temporary, :options, :as, :foreign_keys, :comment
259
+ attr_reader :name, :temporary, :if_not_exists, :options, :as, :comment, :indexes, :foreign_keys
262
260
 
263
- def initialize(name, temporary = false, options = nil, as = nil, comment: nil)
261
+ def initialize(
262
+ conn,
263
+ name,
264
+ temporary: false,
265
+ if_not_exists: false,
266
+ options: nil,
267
+ as: nil,
268
+ comment: nil,
269
+ **
270
+ )
271
+ @conn = conn
264
272
  @columns_hash = {}
265
273
  @indexes = []
266
274
  @foreign_keys = []
267
275
  @primary_keys = nil
268
276
  @temporary = temporary
277
+ @if_not_exists = if_not_exists
269
278
  @options = options
270
279
  @as = as
271
280
  @name = name
@@ -349,21 +358,24 @@ module ActiveRecord
349
358
  #
350
359
  # create_table :taggings do |t|
351
360
  # t.references :tag, index: { name: 'index_taggings_on_tag_id' }
352
- # t.references :tagger, polymorphic: true, index: true
353
- # t.references :taggable, polymorphic: { default: 'Photo' }
361
+ # t.references :tagger, polymorphic: true
362
+ # t.references :taggable, polymorphic: { default: 'Photo' }, index: false
354
363
  # end
355
- def column(name, type, options = {})
364
+ def column(name, type, **options)
356
365
  name = name.to_s
357
366
  type = type.to_sym if type
358
- options = options.dup
359
367
 
360
- if @columns_hash[name] && @columns_hash[name].primary_key?
361
- raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
368
+ if @columns_hash[name]
369
+ if @columns_hash[name].primary_key?
370
+ raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
371
+ else
372
+ raise ArgumentError, "you can't define an already defined column '#{name}'."
373
+ end
362
374
  end
363
375
 
364
376
  index_options = options.delete(:index)
365
377
  index(name, index_options.is_a?(Hash) ? index_options : {}) if index_options
366
- @columns_hash[name] = new_column_definition(name, type, options)
378
+ @columns_hash[name] = new_column_definition(name, type, **options)
367
379
  self
368
380
  end
369
381
 
@@ -381,11 +393,8 @@ module ActiveRecord
381
393
  indexes << [column_name, options]
382
394
  end
383
395
 
384
- def foreign_key(table_name, options = {}) # :nodoc:
385
- table_name_prefix = ActiveRecord::Base.table_name_prefix
386
- table_name_suffix = ActiveRecord::Base.table_name_suffix
387
- table_name = "#{table_name_prefix}#{table_name}#{table_name_suffix}"
388
- foreign_keys.push([table_name, options])
396
+ def foreign_key(table_name, **options) # :nodoc:
397
+ foreign_keys << [table_name, options]
389
398
  end
390
399
 
391
400
  # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
@@ -395,19 +404,24 @@ module ActiveRecord
395
404
  def timestamps(**options)
396
405
  options[:null] = false if options[:null].nil?
397
406
 
398
- column(:created_at, :datetime, options)
399
- column(:updated_at, :datetime, options)
407
+ if !options.key?(:precision) && @conn.supports_datetime_with_precision?
408
+ options[:precision] = 6
409
+ end
410
+
411
+ column(:created_at, :datetime, **options)
412
+ column(:updated_at, :datetime, **options)
400
413
  end
401
414
 
402
415
  # Adds a reference.
403
416
  #
404
417
  # t.references(:user)
405
418
  # t.belongs_to(:supplier, foreign_key: true)
419
+ # t.belongs_to(:supplier, foreign_key: true, type: :integer)
406
420
  #
407
421
  # See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
408
422
  def references(*args, **options)
409
423
  args.each do |ref_name|
410
- ReferenceDefinition.new(ref_name, options).add_to(self)
424
+ ReferenceDefinition.new(ref_name, **options).add_to(self)
411
425
  end
412
426
  end
413
427
  alias :belongs_to :references
@@ -462,10 +476,10 @@ module ActiveRecord
462
476
  @foreign_key_drops << name
463
477
  end
464
478
 
465
- def add_column(name, type, options)
479
+ def add_column(name, type, **options)
466
480
  name = name.to_s
467
481
  type = type.to_sym
468
- @adds << AddColumnDefinition.new(@td.new_column_definition(name, type, options))
482
+ @adds << AddColumnDefinition.new(@td.new_column_definition(name, type, **options))
469
483
  end
470
484
  end
471
485
 
@@ -502,6 +516,7 @@ module ActiveRecord
502
516
  # t.json
503
517
  # t.virtual
504
518
  # t.remove
519
+ # t.remove_foreign_key
505
520
  # t.remove_references
506
521
  # t.remove_belongs_to
507
522
  # t.remove_index
@@ -523,8 +538,10 @@ module ActiveRecord
523
538
  # t.column(:name, :string)
524
539
  #
525
540
  # See TableDefinition#column for details of the options you can use.
526
- def column(column_name, type, options = {})
527
- @base.add_column(name, column_name, type, options)
541
+ def column(column_name, type, **options)
542
+ index_options = options.delete(:index)
543
+ @base.add_column(name, column_name, type, **options)
544
+ index(column_name, index_options.is_a?(Hash) ? index_options : {}) if index_options
528
545
  end
529
546
 
530
547
  # Checks to see if a column exists.
@@ -532,8 +549,8 @@ module ActiveRecord
532
549
  # t.string(:name) unless t.column_exists?(:name, :string)
533
550
  #
534
551
  # See {connection.column_exists?}[rdoc-ref:SchemaStatements#column_exists?]
535
- def column_exists?(column_name, type = nil, options = {})
536
- @base.column_exists?(name, column_name, type, options)
552
+ def column_exists?(column_name, type = nil, **options)
553
+ @base.column_exists?(name, column_name, type, **options)
537
554
  end
538
555
 
539
556
  # Adds a new index to the table. +column_name+ can be a single Symbol, or
@@ -573,8 +590,8 @@ module ActiveRecord
573
590
  # t.timestamps(null: false)
574
591
  #
575
592
  # See {connection.add_timestamps}[rdoc-ref:SchemaStatements#add_timestamps]
576
- def timestamps(options = {})
577
- @base.add_timestamps(name, options)
593
+ def timestamps(**options)
594
+ @base.add_timestamps(name, **options)
578
595
  end
579
596
 
580
597
  # Changes the column's definition according to the new options.
@@ -624,8 +641,8 @@ module ActiveRecord
624
641
  # t.remove_timestamps
625
642
  #
626
643
  # See {connection.remove_timestamps}[rdoc-ref:SchemaStatements#remove_timestamps]
627
- def remove_timestamps(options = {})
628
- @base.remove_timestamps(name, options)
644
+ def remove_timestamps(**options)
645
+ @base.remove_timestamps(name, **options)
629
646
  end
630
647
 
631
648
  # Renames a column.
@@ -645,7 +662,7 @@ module ActiveRecord
645
662
  # See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
646
663
  def references(*args, **options)
647
664
  args.each do |ref_name|
648
- @base.add_reference(name, ref_name, options)
665
+ @base.add_reference(name, ref_name, **options)
649
666
  end
650
667
  end
651
668
  alias :belongs_to :references
@@ -658,18 +675,29 @@ module ActiveRecord
658
675
  # See {connection.remove_reference}[rdoc-ref:SchemaStatements#remove_reference]
659
676
  def remove_references(*args, **options)
660
677
  args.each do |ref_name|
661
- @base.remove_reference(name, ref_name, options)
678
+ @base.remove_reference(name, ref_name, **options)
662
679
  end
663
680
  end
664
681
  alias :remove_belongs_to :remove_references
665
682
 
666
- # Adds a foreign key.
683
+ # Adds a foreign key to the table using a supplied table name.
667
684
  #
668
685
  # t.foreign_key(:authors)
686
+ # t.foreign_key(:authors, column: :author_id, primary_key: "id")
669
687
  #
670
688
  # See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
671
- def foreign_key(*args)
672
- @base.add_foreign_key(name, *args)
689
+ def foreign_key(*args, **options)
690
+ @base.add_foreign_key(name, *args, **options)
691
+ end
692
+
693
+ # Removes the given foreign key from the table.
694
+ #
695
+ # t.remove_foreign_key(:authors)
696
+ # t.remove_foreign_key(column: :author_id)
697
+ #
698
+ # See {connection.remove_foreign_key}[rdoc-ref:SchemaStatements#remove_foreign_key]
699
+ def remove_foreign_key(*args, **options)
700
+ @base.remove_foreign_key(name, *args, **options)
673
701
  end
674
702
 
675
703
  # Checks to see if a foreign key exists.
@@ -677,8 +705,8 @@ module ActiveRecord
677
705
  # t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
678
706
  #
679
707
  # See {connection.foreign_key_exists?}[rdoc-ref:SchemaStatements#foreign_key_exists?]
680
- def foreign_key_exists?(*args)
681
- @base.foreign_key_exists?(name, *args)
708
+ def foreign_key_exists?(*args, **options)
709
+ @base.foreign_key_exists?(name, *args, **options)
682
710
  end
683
711
  end
684
712
  end