activerecord 5.2.6 → 6.0.5

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 (294) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +928 -559
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +5 -3
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/advisory_lock_base.rb +18 -0
  7. data/lib/active_record/aggregations.rb +4 -3
  8. data/lib/active_record/association_relation.rb +10 -8
  9. data/lib/active_record/associations/alias_tracker.rb +0 -1
  10. data/lib/active_record/associations/association.rb +55 -19
  11. data/lib/active_record/associations/association_scope.rb +11 -7
  12. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  14. data/lib/active_record/associations/builder/association.rb +14 -18
  15. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  16. data/lib/active_record/associations/builder/collection_association.rb +3 -13
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +35 -1
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +19 -23
  22. data/lib/active_record/associations/collection_proxy.rb +14 -17
  23. data/lib/active_record/associations/foreign_association.rb +7 -0
  24. data/lib/active_record/associations/has_many_association.rb +2 -11
  25. data/lib/active_record/associations/has_many_through_association.rb +14 -14
  26. data/lib/active_record/associations/has_one_association.rb +28 -30
  27. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  28. data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
  29. data/lib/active_record/associations/join_dependency/join_part.rb +4 -4
  30. data/lib/active_record/associations/join_dependency.rb +47 -30
  31. data/lib/active_record/associations/preloader/association.rb +61 -41
  32. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  33. data/lib/active_record/associations/preloader.rb +44 -33
  34. data/lib/active_record/associations/singular_association.rb +2 -16
  35. data/lib/active_record/associations/through_association.rb +1 -1
  36. data/lib/active_record/associations.rb +21 -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/before_type_cast.rb +4 -2
  40. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  41. data/lib/active_record/attribute_methods/primary_key.rb +15 -24
  42. data/lib/active_record/attribute_methods/query.rb +2 -3
  43. data/lib/active_record/attribute_methods/read.rb +15 -54
  44. data/lib/active_record/attribute_methods/serialization.rb +1 -2
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
  46. data/lib/active_record/attribute_methods/write.rb +17 -25
  47. data/lib/active_record/attribute_methods.rb +28 -100
  48. data/lib/active_record/attributes.rb +13 -1
  49. data/lib/active_record/autosave_association.rb +12 -14
  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 +109 -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 +105 -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 +197 -43
  64. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -217
  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 +139 -19
  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/date_time.rb +8 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -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 +25 -7
  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 +137 -147
  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 +107 -66
  110. data/lib/active_record/counter_cache.rb +8 -30
  111. data/lib/active_record/database_configurations/database_config.rb +37 -0
  112. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  113. data/lib/active_record/database_configurations/url_config.rb +78 -0
  114. data/lib/active_record/database_configurations.rb +233 -0
  115. data/lib/active_record/dynamic_matchers.rb +3 -4
  116. data/lib/active_record/enum.rb +44 -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 +14 -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/resolver/session.rb +45 -0
  133. data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
  134. data/lib/active_record/middleware/database_selector.rb +74 -0
  135. data/lib/active_record/migration/command_recorder.rb +54 -22
  136. data/lib/active_record/migration/compatibility.rb +79 -52
  137. data/lib/active_record/migration/join_table.rb +0 -1
  138. data/lib/active_record/migration.rb +104 -85
  139. data/lib/active_record/model_schema.rb +62 -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 +51 -51
  151. data/lib/active_record/relation/batches.rb +13 -11
  152. data/lib/active_record/relation/calculations.rb +55 -49
  153. data/lib/active_record/relation/delegation.rb +35 -50
  154. data/lib/active_record/relation/finder_methods.rb +23 -28
  155. data/lib/active_record/relation/from_clause.rb +4 -0
  156. data/lib/active_record/relation/merger.rb +12 -17
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  158. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  159. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  160. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  161. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  162. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  163. data/lib/active_record/relation/predicate_builder.rb +5 -11
  164. data/lib/active_record/relation/query_attribute.rb +13 -8
  165. data/lib/active_record/relation/query_methods.rb +232 -69
  166. data/lib/active_record/relation/spawn_methods.rb +1 -2
  167. data/lib/active_record/relation/where_clause.rb +14 -11
  168. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  169. data/lib/active_record/relation.rb +326 -81
  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/default.rb +4 -6
  176. data/lib/active_record/scoping/named.rb +25 -16
  177. data/lib/active_record/scoping.rb +8 -9
  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 +243 -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/adapter_specific_registry.rb +3 -13
  193. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  194. data/lib/active_record/type/serialized.rb +0 -1
  195. data/lib/active_record/type/time.rb +10 -0
  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.rb +3 -5
  199. data/lib/active_record/type_caster/connection.rb +15 -14
  200. data/lib/active_record/type_caster/map.rb +1 -4
  201. data/lib/active_record/validations/associated.rb +0 -1
  202. data/lib/active_record/validations/uniqueness.rb +15 -27
  203. data/lib/active_record/validations.rb +3 -3
  204. data/lib/active_record.rb +10 -2
  205. data/lib/arel/alias_predication.rb +9 -0
  206. data/lib/arel/attributes/attribute.rb +37 -0
  207. data/lib/arel/attributes.rb +22 -0
  208. data/lib/arel/collectors/bind.rb +24 -0
  209. data/lib/arel/collectors/composite.rb +31 -0
  210. data/lib/arel/collectors/plain_string.rb +20 -0
  211. data/lib/arel/collectors/sql_string.rb +20 -0
  212. data/lib/arel/collectors/substitute_binds.rb +28 -0
  213. data/lib/arel/crud.rb +42 -0
  214. data/lib/arel/delete_manager.rb +18 -0
  215. data/lib/arel/errors.rb +9 -0
  216. data/lib/arel/expressions.rb +29 -0
  217. data/lib/arel/factory_methods.rb +49 -0
  218. data/lib/arel/insert_manager.rb +49 -0
  219. data/lib/arel/math.rb +45 -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/nodes.rb +68 -0
  264. data/lib/arel/order_predications.rb +13 -0
  265. data/lib/arel/predications.rb +256 -0
  266. data/lib/arel/select_manager.rb +271 -0
  267. data/lib/arel/table.rb +110 -0
  268. data/lib/arel/tree_manager.rb +72 -0
  269. data/lib/arel/update_manager.rb +34 -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/visitors.rb +20 -0
  284. data/lib/arel/window_predications.rb +9 -0
  285. data/lib/arel.rb +62 -0
  286. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  287. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  288. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  289. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  290. data/lib/rails/generators/active_record/migration.rb +14 -2
  291. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  292. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  293. metadata +116 -29
  294. 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
@@ -63,6 +63,10 @@ module ActiveRecord
63
63
  end
64
64
  CODE
65
65
  end
66
+
67
+ def aliased_types(name, fallback)
68
+ "timestamp" == name ? :datetime : fallback
69
+ end
66
70
  end
67
71
 
68
72
  AddColumnDefinition = Struct.new(:column) # :nodoc:
@@ -101,13 +105,14 @@ module ActiveRecord
101
105
  end
102
106
  alias validated? validate?
103
107
 
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
108
+ def export_name_on_schema_dump?
109
+ !ActiveRecord::SchemaDumper.fk_ignore_pattern.match?(name) if name
110
+ end
111
+
112
+ def defined_for?(to_table: nil, validate: nil, **options)
113
+ (to_table.nil? || to_table.to_s == self.to_table) &&
114
+ (validate.nil? || validate == options.fetch(:validate, validate)) &&
115
+ options.all? { |k, v| self.options[k].to_s == v.to_s }
111
116
  end
112
117
 
113
118
  private
@@ -139,7 +144,8 @@ module ActiveRecord
139
144
 
140
145
  def add_to(table)
141
146
  columns.each do |column_options|
142
- table.column(*column_options)
147
+ kwargs = column_options.extract_options!
148
+ table.column(*column_options, **kwargs)
143
149
  end
144
150
 
145
151
  if index
@@ -147,17 +153,12 @@ module ActiveRecord
147
153
  end
148
154
 
149
155
  if foreign_key
150
- table.foreign_key(foreign_table_name, foreign_key_options)
156
+ table.foreign_key(foreign_table_name, **foreign_key_options)
151
157
  end
152
158
  end
153
159
 
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
160
  private
161
+ attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options
161
162
 
162
163
  def as_options(value)
163
164
  value.is_a?(Hash) ? value : {}
@@ -199,41 +200,44 @@ module ActiveRecord
199
200
  end
200
201
 
201
202
  module ColumnMethods
203
+ extend ActiveSupport::Concern
204
+
202
205
  # Appends a primary key definition to the table definition.
203
206
  # Can be called multiple times, but this is probably not a good idea.
204
207
  def primary_key(name, type = :primary_key, **options)
205
- column(name, type, options.merge(primary_key: true))
208
+ column(name, type, **options.merge(primary_key: true))
206
209
  end
207
210
 
211
+ ##
212
+ # :method: column
213
+ # :call-seq: column(name, type, **options)
214
+ #
208
215
  # Appends a column or columns of a specified type.
209
216
  #
210
217
  # t.string(:goat)
211
218
  # t.string(:goat, :sheep)
212
219
  #
213
220
  # 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) }
221
+
222
+ included do
223
+ define_column_methods :bigint, :binary, :boolean, :date, :datetime, :decimal,
224
+ :float, :integer, :json, :string, :text, :time, :timestamp, :virtual
225
+
226
+ alias :numeric :decimal
227
+ end
228
+
229
+ class_methods do
230
+ private def define_column_methods(*column_types) # :nodoc:
231
+ column_types.each do |column_type|
232
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
233
+ def #{column_type}(*names, **options)
234
+ raise ArgumentError, "Missing column name(s) for #{column_type}" if names.empty?
235
+ names.each { |name| column(name, :#{column_type}, **options) }
236
+ end
237
+ RUBY
233
238
  end
234
- CODE
239
+ end
235
240
  end
236
- alias_method :numeric, :decimal
237
241
  end
238
242
 
239
243
  # Represents the schema of an SQL table in an abstract way. This class
@@ -257,15 +261,25 @@ module ActiveRecord
257
261
  class TableDefinition
258
262
  include ColumnMethods
259
263
 
260
- attr_accessor :indexes
261
- attr_reader :name, :temporary, :options, :as, :foreign_keys, :comment
264
+ attr_reader :name, :temporary, :if_not_exists, :options, :as, :comment, :indexes, :foreign_keys
262
265
 
263
- def initialize(name, temporary = false, options = nil, as = nil, comment: nil)
266
+ def initialize(
267
+ conn,
268
+ name,
269
+ temporary: false,
270
+ if_not_exists: false,
271
+ options: nil,
272
+ as: nil,
273
+ comment: nil,
274
+ **
275
+ )
276
+ @conn = conn
264
277
  @columns_hash = {}
265
278
  @indexes = []
266
279
  @foreign_keys = []
267
280
  @primary_keys = nil
268
281
  @temporary = temporary
282
+ @if_not_exists = if_not_exists
269
283
  @options = options
270
284
  @as = as
271
285
  @name = name
@@ -349,21 +363,24 @@ module ActiveRecord
349
363
  #
350
364
  # create_table :taggings do |t|
351
365
  # 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' }
366
+ # t.references :tagger, polymorphic: true
367
+ # t.references :taggable, polymorphic: { default: 'Photo' }, index: false
354
368
  # end
355
- def column(name, type, options = {})
369
+ def column(name, type, **options)
356
370
  name = name.to_s
357
371
  type = type.to_sym if type
358
- options = options.dup
359
372
 
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."
373
+ if @columns_hash[name]
374
+ if @columns_hash[name].primary_key?
375
+ raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
376
+ else
377
+ raise ArgumentError, "you can't define an already defined column '#{name}'."
378
+ end
362
379
  end
363
380
 
364
381
  index_options = options.delete(:index)
365
382
  index(name, index_options.is_a?(Hash) ? index_options : {}) if index_options
366
- @columns_hash[name] = new_column_definition(name, type, options)
383
+ @columns_hash[name] = new_column_definition(name, type, **options)
367
384
  self
368
385
  end
369
386
 
@@ -381,11 +398,8 @@ module ActiveRecord
381
398
  indexes << [column_name, options]
382
399
  end
383
400
 
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])
401
+ def foreign_key(table_name, **options) # :nodoc:
402
+ foreign_keys << [table_name, options]
389
403
  end
390
404
 
391
405
  # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
@@ -395,19 +409,24 @@ module ActiveRecord
395
409
  def timestamps(**options)
396
410
  options[:null] = false if options[:null].nil?
397
411
 
398
- column(:created_at, :datetime, options)
399
- column(:updated_at, :datetime, options)
412
+ if !options.key?(:precision) && @conn.supports_datetime_with_precision?
413
+ options[:precision] = 6
414
+ end
415
+
416
+ column(:created_at, :datetime, **options)
417
+ column(:updated_at, :datetime, **options)
400
418
  end
401
419
 
402
420
  # Adds a reference.
403
421
  #
404
422
  # t.references(:user)
405
423
  # t.belongs_to(:supplier, foreign_key: true)
424
+ # t.belongs_to(:supplier, foreign_key: true, type: :integer)
406
425
  #
407
426
  # See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
408
427
  def references(*args, **options)
409
428
  args.each do |ref_name|
410
- ReferenceDefinition.new(ref_name, options).add_to(self)
429
+ ReferenceDefinition.new(ref_name, **options).add_to(self)
411
430
  end
412
431
  end
413
432
  alias :belongs_to :references
@@ -462,10 +481,10 @@ module ActiveRecord
462
481
  @foreign_key_drops << name
463
482
  end
464
483
 
465
- def add_column(name, type, options)
484
+ def add_column(name, type, **options)
466
485
  name = name.to_s
467
486
  type = type.to_sym
468
- @adds << AddColumnDefinition.new(@td.new_column_definition(name, type, options))
487
+ @adds << AddColumnDefinition.new(@td.new_column_definition(name, type, **options))
469
488
  end
470
489
  end
471
490
 
@@ -502,6 +521,7 @@ module ActiveRecord
502
521
  # t.json
503
522
  # t.virtual
504
523
  # t.remove
524
+ # t.remove_foreign_key
505
525
  # t.remove_references
506
526
  # t.remove_belongs_to
507
527
  # t.remove_index
@@ -523,8 +543,10 @@ module ActiveRecord
523
543
  # t.column(:name, :string)
524
544
  #
525
545
  # 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)
546
+ def column(column_name, type, **options)
547
+ index_options = options.delete(:index)
548
+ @base.add_column(name, column_name, type, **options)
549
+ index(column_name, index_options.is_a?(Hash) ? index_options : {}) if index_options
528
550
  end
529
551
 
530
552
  # Checks to see if a column exists.
@@ -532,8 +554,8 @@ module ActiveRecord
532
554
  # t.string(:name) unless t.column_exists?(:name, :string)
533
555
  #
534
556
  # 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)
557
+ def column_exists?(column_name, type = nil, **options)
558
+ @base.column_exists?(name, column_name, type, **options)
537
559
  end
538
560
 
539
561
  # Adds a new index to the table. +column_name+ can be a single Symbol, or
@@ -573,8 +595,8 @@ module ActiveRecord
573
595
  # t.timestamps(null: false)
574
596
  #
575
597
  # See {connection.add_timestamps}[rdoc-ref:SchemaStatements#add_timestamps]
576
- def timestamps(options = {})
577
- @base.add_timestamps(name, options)
598
+ def timestamps(**options)
599
+ @base.add_timestamps(name, **options)
578
600
  end
579
601
 
580
602
  # Changes the column's definition according to the new options.
@@ -624,8 +646,8 @@ module ActiveRecord
624
646
  # t.remove_timestamps
625
647
  #
626
648
  # See {connection.remove_timestamps}[rdoc-ref:SchemaStatements#remove_timestamps]
627
- def remove_timestamps(options = {})
628
- @base.remove_timestamps(name, options)
649
+ def remove_timestamps(**options)
650
+ @base.remove_timestamps(name, **options)
629
651
  end
630
652
 
631
653
  # Renames a column.
@@ -645,7 +667,7 @@ module ActiveRecord
645
667
  # See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
646
668
  def references(*args, **options)
647
669
  args.each do |ref_name|
648
- @base.add_reference(name, ref_name, options)
670
+ @base.add_reference(name, ref_name, **options)
649
671
  end
650
672
  end
651
673
  alias :belongs_to :references
@@ -658,18 +680,29 @@ module ActiveRecord
658
680
  # See {connection.remove_reference}[rdoc-ref:SchemaStatements#remove_reference]
659
681
  def remove_references(*args, **options)
660
682
  args.each do |ref_name|
661
- @base.remove_reference(name, ref_name, options)
683
+ @base.remove_reference(name, ref_name, **options)
662
684
  end
663
685
  end
664
686
  alias :remove_belongs_to :remove_references
665
687
 
666
- # Adds a foreign key.
688
+ # Adds a foreign key to the table using a supplied table name.
667
689
  #
668
690
  # t.foreign_key(:authors)
691
+ # t.foreign_key(:authors, column: :author_id, primary_key: "id")
669
692
  #
670
693
  # See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
671
- def foreign_key(*args)
672
- @base.add_foreign_key(name, *args)
694
+ def foreign_key(*args, **options)
695
+ @base.add_foreign_key(name, *args, **options)
696
+ end
697
+
698
+ # Removes the given foreign key from the table.
699
+ #
700
+ # t.remove_foreign_key(:authors)
701
+ # t.remove_foreign_key(column: :author_id)
702
+ #
703
+ # See {connection.remove_foreign_key}[rdoc-ref:SchemaStatements#remove_foreign_key]
704
+ def remove_foreign_key(*args, **options)
705
+ @base.remove_foreign_key(name, *args, **options)
673
706
  end
674
707
 
675
708
  # Checks to see if a foreign key exists.
@@ -677,8 +710,8 @@ module ActiveRecord
677
710
  # t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
678
711
  #
679
712
  # See {connection.foreign_key_exists?}[rdoc-ref:SchemaStatements#foreign_key_exists?]
680
- def foreign_key_exists?(*args)
681
- @base.foreign_key_exists?(name, *args)
713
+ def foreign_key_exists?(*args, **options)
714
+ @base.foreign_key_exists?(name, *args, **options)
682
715
  end
683
716
  end
684
717
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/hash/compact"
4
-
5
3
  module ActiveRecord
6
4
  module ConnectionAdapters # :nodoc:
7
5
  class SchemaDumper < SchemaDumper # :nodoc:
@@ -17,7 +15,7 @@ module ActiveRecord
17
15
  def column_spec_for_primary_key(column)
18
16
  return {} if default_primary_key?(column)
19
17
  spec = { id: schema_type(column).inspect }
20
- spec.merge!(prepare_column_options(column).except!(:null))
18
+ spec.merge!(prepare_column_options(column).except!(:null, :comment))
21
19
  spec[:default] ||= "nil" if explicit_primary_key_default?(column)
22
20
  spec
23
21
  end