activerecord 6.0.6.1 → 6.1.7.6

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 (243) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1152 -779
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/active_record/aggregations.rb +5 -5
  6. data/lib/active_record/association_relation.rb +30 -12
  7. data/lib/active_record/associations/alias_tracker.rb +19 -15
  8. data/lib/active_record/associations/association.rb +49 -26
  9. data/lib/active_record/associations/association_scope.rb +18 -20
  10. data/lib/active_record/associations/belongs_to_association.rb +23 -10
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
  12. data/lib/active_record/associations/builder/association.rb +32 -5
  13. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
  16. data/lib/active_record/associations/builder/has_many.rb +6 -2
  17. data/lib/active_record/associations/builder/has_one.rb +11 -14
  18. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  19. data/lib/active_record/associations/collection_association.rb +32 -18
  20. data/lib/active_record/associations/collection_proxy.rb +12 -5
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -2
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  24. data/lib/active_record/associations/has_one_association.rb +15 -1
  25. data/lib/active_record/associations/join_dependency/join_association.rb +37 -21
  26. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +63 -49
  28. data/lib/active_record/associations/preloader/association.rb +14 -8
  29. data/lib/active_record/associations/preloader/through_association.rb +1 -1
  30. data/lib/active_record/associations/preloader.rb +5 -3
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations.rb +118 -11
  33. data/lib/active_record/attribute_assignment.rb +10 -8
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  35. data/lib/active_record/attribute_methods/dirty.rb +1 -11
  36. data/lib/active_record/attribute_methods/primary_key.rb +6 -2
  37. data/lib/active_record/attribute_methods/query.rb +3 -6
  38. data/lib/active_record/attribute_methods/read.rb +8 -11
  39. data/lib/active_record/attribute_methods/serialization.rb +11 -5
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
  41. data/lib/active_record/attribute_methods/write.rb +12 -20
  42. data/lib/active_record/attribute_methods.rb +64 -54
  43. data/lib/active_record/attributes.rb +33 -8
  44. data/lib/active_record/autosave_association.rb +47 -30
  45. data/lib/active_record/base.rb +2 -14
  46. data/lib/active_record/callbacks.rb +152 -22
  47. data/lib/active_record/coders/yaml_column.rb +1 -1
  48. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
  49. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  50. data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -23
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -8
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  53. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  54. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  55. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +114 -26
  56. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +228 -83
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +92 -33
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +52 -76
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
  61. data/lib/active_record/connection_adapters/column.rb +15 -1
  62. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  63. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +24 -24
  65. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
  67. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
  68. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  69. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
  70. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -4
  71. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  72. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
  73. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  74. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  75. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  76. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +14 -53
  77. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  78. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  79. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  80. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  86. data/lib/active_record/connection_adapters/postgresql/quoting.rb +30 -4
  87. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  88. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  89. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  90. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  91. data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -64
  92. data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
  93. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  94. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +32 -5
  95. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  96. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  97. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
  98. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
  99. data/lib/active_record/connection_adapters.rb +52 -0
  100. data/lib/active_record/connection_handling.rb +218 -71
  101. data/lib/active_record/core.rb +264 -63
  102. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  103. data/lib/active_record/database_configurations/database_config.rb +52 -9
  104. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  105. data/lib/active_record/database_configurations/url_config.rb +15 -40
  106. data/lib/active_record/database_configurations.rb +125 -85
  107. data/lib/active_record/delegated_type.rb +209 -0
  108. data/lib/active_record/destroy_association_async_job.rb +36 -0
  109. data/lib/active_record/enum.rb +69 -34
  110. data/lib/active_record/errors.rb +47 -12
  111. data/lib/active_record/explain.rb +9 -4
  112. data/lib/active_record/explain_subscriber.rb +1 -1
  113. data/lib/active_record/fixture_set/file.rb +10 -17
  114. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  115. data/lib/active_record/fixture_set/render_context.rb +1 -1
  116. data/lib/active_record/fixture_set/table_row.rb +2 -2
  117. data/lib/active_record/fixtures.rb +58 -9
  118. data/lib/active_record/gem_version.rb +3 -3
  119. data/lib/active_record/inheritance.rb +40 -18
  120. data/lib/active_record/insert_all.rb +38 -5
  121. data/lib/active_record/integration.rb +3 -5
  122. data/lib/active_record/internal_metadata.rb +18 -7
  123. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  124. data/lib/active_record/locking/optimistic.rb +24 -17
  125. data/lib/active_record/locking/pessimistic.rb +6 -2
  126. data/lib/active_record/log_subscriber.rb +27 -8
  127. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  128. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  129. data/lib/active_record/middleware/database_selector.rb +4 -1
  130. data/lib/active_record/migration/command_recorder.rb +47 -27
  131. data/lib/active_record/migration/compatibility.rb +72 -18
  132. data/lib/active_record/migration.rb +114 -84
  133. data/lib/active_record/model_schema.rb +89 -14
  134. data/lib/active_record/nested_attributes.rb +2 -3
  135. data/lib/active_record/no_touching.rb +1 -1
  136. data/lib/active_record/persistence.rb +50 -45
  137. data/lib/active_record/query_cache.rb +15 -5
  138. data/lib/active_record/querying.rb +11 -6
  139. data/lib/active_record/railtie.rb +64 -44
  140. data/lib/active_record/railties/console_sandbox.rb +2 -4
  141. data/lib/active_record/railties/databases.rake +279 -101
  142. data/lib/active_record/readonly_attributes.rb +4 -0
  143. data/lib/active_record/reflection.rb +60 -44
  144. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  145. data/lib/active_record/relation/batches.rb +38 -31
  146. data/lib/active_record/relation/calculations.rb +104 -43
  147. data/lib/active_record/relation/finder_methods.rb +44 -14
  148. data/lib/active_record/relation/from_clause.rb +1 -1
  149. data/lib/active_record/relation/merger.rb +20 -23
  150. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  151. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  152. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
  153. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  154. data/lib/active_record/relation/predicate_builder.rb +61 -38
  155. data/lib/active_record/relation/query_methods.rb +322 -196
  156. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  157. data/lib/active_record/relation/spawn_methods.rb +8 -7
  158. data/lib/active_record/relation/where_clause.rb +111 -61
  159. data/lib/active_record/relation.rb +100 -81
  160. data/lib/active_record/result.rb +41 -33
  161. data/lib/active_record/runtime_registry.rb +2 -2
  162. data/lib/active_record/sanitization.rb +6 -17
  163. data/lib/active_record/schema_dumper.rb +34 -4
  164. data/lib/active_record/schema_migration.rb +2 -8
  165. data/lib/active_record/scoping/default.rb +1 -3
  166. data/lib/active_record/scoping/named.rb +1 -17
  167. data/lib/active_record/secure_token.rb +16 -8
  168. data/lib/active_record/serialization.rb +5 -3
  169. data/lib/active_record/signed_id.rb +116 -0
  170. data/lib/active_record/statement_cache.rb +20 -4
  171. data/lib/active_record/store.rb +8 -3
  172. data/lib/active_record/suppressor.rb +2 -2
  173. data/lib/active_record/table_metadata.rb +42 -51
  174. data/lib/active_record/tasks/database_tasks.rb +140 -113
  175. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  176. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  177. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  178. data/lib/active_record/test_databases.rb +5 -4
  179. data/lib/active_record/test_fixtures.rb +79 -31
  180. data/lib/active_record/timestamp.rb +4 -6
  181. data/lib/active_record/touch_later.rb +21 -21
  182. data/lib/active_record/transactions.rb +19 -66
  183. data/lib/active_record/type/serialized.rb +6 -2
  184. data/lib/active_record/type.rb +8 -1
  185. data/lib/active_record/type_caster/connection.rb +0 -1
  186. data/lib/active_record/type_caster/map.rb +8 -5
  187. data/lib/active_record/validations/associated.rb +1 -1
  188. data/lib/active_record/validations/numericality.rb +35 -0
  189. data/lib/active_record/validations/uniqueness.rb +24 -4
  190. data/lib/active_record/validations.rb +1 -0
  191. data/lib/active_record.rb +7 -14
  192. data/lib/arel/attributes/attribute.rb +4 -0
  193. data/lib/arel/collectors/bind.rb +5 -0
  194. data/lib/arel/collectors/composite.rb +8 -0
  195. data/lib/arel/collectors/sql_string.rb +7 -0
  196. data/lib/arel/collectors/substitute_binds.rb +7 -0
  197. data/lib/arel/nodes/binary.rb +82 -8
  198. data/lib/arel/nodes/bind_param.rb +8 -0
  199. data/lib/arel/nodes/casted.rb +21 -9
  200. data/lib/arel/nodes/equality.rb +6 -9
  201. data/lib/arel/nodes/grouping.rb +3 -0
  202. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  203. data/lib/arel/nodes/in.rb +8 -1
  204. data/lib/arel/nodes/infix_operation.rb +13 -1
  205. data/lib/arel/nodes/join_source.rb +1 -1
  206. data/lib/arel/nodes/node.rb +7 -6
  207. data/lib/arel/nodes/ordering.rb +27 -0
  208. data/lib/arel/nodes/sql_literal.rb +3 -0
  209. data/lib/arel/nodes/table_alias.rb +7 -3
  210. data/lib/arel/nodes/unary.rb +0 -1
  211. data/lib/arel/nodes.rb +3 -1
  212. data/lib/arel/predications.rb +12 -18
  213. data/lib/arel/select_manager.rb +1 -2
  214. data/lib/arel/table.rb +13 -5
  215. data/lib/arel/visitors/dot.rb +14 -2
  216. data/lib/arel/visitors/mysql.rb +11 -1
  217. data/lib/arel/visitors/postgresql.rb +15 -4
  218. data/lib/arel/visitors/to_sql.rb +89 -78
  219. data/lib/arel/visitors.rb +0 -7
  220. data/lib/arel.rb +5 -13
  221. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  222. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  223. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  224. data/lib/rails/generators/active_record/migration.rb +6 -1
  225. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  226. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  227. metadata +25 -26
  228. data/lib/active_record/advisory_lock_base.rb +0 -18
  229. data/lib/active_record/attribute_decorators.rb +0 -88
  230. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  231. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  232. data/lib/active_record/define_callbacks.rb +0 -22
  233. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  234. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  235. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  236. data/lib/arel/attributes.rb +0 -22
  237. data/lib/arel/visitors/depth_first.rb +0 -203
  238. data/lib/arel/visitors/ibm_db.rb +0 -34
  239. data/lib/arel/visitors/informix.rb +0 -62
  240. data/lib/arel/visitors/mssql.rb +0 -156
  241. data/lib/arel/visitors/oracle.rb +0 -158
  242. data/lib/arel/visitors/oracle12.rb +0 -65
  243. data/lib/arel/visitors/where_sql.rb +0 -22
@@ -2,151 +2,188 @@
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?, :supports_foreign_keys?, :foreign_key_options,
18
+ :quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?, :check_constraint_options,
19
+ to: :@conn, private: true
20
+
21
+ private
22
+ def visit_AlterTable(o)
23
+ sql = +"ALTER TABLE #{quote_table_name(o.name)} "
24
+ sql << o.adds.map { |col| accept col }.join(" ")
25
+ sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(" ")
26
+ sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ")
27
+ sql << o.check_constraint_adds.map { |con| visit_AddCheckConstraint con }.join(" ")
28
+ sql << o.check_constraint_drops.map { |con| visit_DropCheckConstraint con }.join(" ")
29
+ end
30
+
31
+ def visit_ColumnDefinition(o)
32
+ o.sql_type = type_to_sql(o.type, **o.options)
33
+ column_sql = +"#{quote_column_name(o.name)} #{o.sql_type}"
34
+ add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
35
+ column_sql
10
36
  end
11
37
 
12
- def accept(o)
13
- m = @cache[o.class] ||= "visit_#{o.class.name.split('::').last}"
14
- send m, o
38
+ def visit_AddColumnDefinition(o)
39
+ +"ADD #{accept(o.column)}"
15
40
  end
16
41
 
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
42
+ def visit_TableDefinition(o)
43
+ create_sql = +"CREATE#{table_modifier_in_create(o)} TABLE "
44
+ create_sql << "IF NOT EXISTS " if o.if_not_exists
45
+ create_sql << "#{quote_table_name(o.name)} "
20
46
 
21
- private
22
- def visit_AlterTable(o)
23
- sql = +"ALTER TABLE #{quote_table_name(o.name)} "
24
- sql << o.adds.map { |col| accept col }.join(" ")
25
- sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(" ")
26
- sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ")
47
+ statements = o.columns.map { |c| accept c }
48
+ statements << accept(o.primary_keys) if o.primary_keys
49
+
50
+ if supports_indexes_in_create?
51
+ statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
27
52
  end
28
53
 
29
- def visit_ColumnDefinition(o)
30
- o.sql_type = type_to_sql(o.type, **o.options)
31
- column_sql = +"#{quote_column_name(o.name)} #{o.sql_type}"
32
- add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
33
- column_sql
54
+ if supports_foreign_keys?
55
+ statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
34
56
  end
35
57
 
36
- def visit_AddColumnDefinition(o)
37
- +"ADD #{accept(o.column)}"
58
+ if supports_check_constraints?
59
+ statements.concat(o.check_constraints.map { |expression, options| check_constraint_in_create(o.name, expression, options) })
38
60
  end
39
61
 
40
- def visit_TableDefinition(o)
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)} "
62
+ create_sql << "(#{statements.join(', ')})" if statements.present?
63
+ add_table_options!(create_sql, o)
64
+ create_sql << " AS #{to_sql(o.as)}" if o.as
65
+ create_sql
66
+ end
44
67
 
45
- statements = o.columns.map { |c| accept c }
46
- statements << accept(o.primary_keys) if o.primary_keys
68
+ def visit_PrimaryKeyDefinition(o)
69
+ "PRIMARY KEY (#{o.name.map { |name| quote_column_name(name) }.join(', ')})"
70
+ end
47
71
 
48
- if supports_indexes_in_create?
49
- statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
50
- end
72
+ def visit_ForeignKeyDefinition(o)
73
+ sql = +<<~SQL
74
+ CONSTRAINT #{quote_column_name(o.name)}
75
+ FOREIGN KEY (#{quote_column_name(o.column)})
76
+ REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
77
+ SQL
78
+ sql << " #{action_sql('DELETE', o.on_delete)}" if o.on_delete
79
+ sql << " #{action_sql('UPDATE', o.on_update)}" if o.on_update
80
+ sql
81
+ end
51
82
 
52
- if supports_foreign_keys?
53
- statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
54
- end
83
+ def visit_AddForeignKey(o)
84
+ "ADD #{accept(o)}"
85
+ end
55
86
 
56
- create_sql << "(#{statements.join(', ')})" if statements.present?
57
- add_table_options!(create_sql, table_options(o))
58
- create_sql << " AS #{to_sql(o.as)}" if o.as
59
- create_sql
60
- end
87
+ def visit_DropForeignKey(name)
88
+ "DROP CONSTRAINT #{quote_column_name(name)}"
89
+ end
61
90
 
62
- def visit_PrimaryKeyDefinition(o)
63
- "PRIMARY KEY (#{o.name.map { |name| quote_column_name(name) }.join(', ')})"
64
- end
91
+ def visit_CreateIndexDefinition(o)
92
+ index = o.index
93
+
94
+ sql = ["CREATE"]
95
+ sql << "UNIQUE" if index.unique
96
+ sql << "INDEX"
97
+ sql << o.algorithm if o.algorithm
98
+ sql << "IF NOT EXISTS" if o.if_not_exists
99
+ sql << index.type if index.type
100
+ sql << "#{quote_column_name(index.name)} ON #{quote_table_name(index.table)}"
101
+ sql << "USING #{index.using}" if supports_index_using? && index.using
102
+ sql << "(#{quoted_columns(index)})"
103
+ sql << "WHERE #{index.where}" if supports_partial_index? && index.where
104
+
105
+ sql.join(" ")
106
+ end
65
107
 
66
- def visit_ForeignKeyDefinition(o)
67
- sql = +<<~SQL
68
- CONSTRAINT #{quote_column_name(o.name)}
69
- FOREIGN KEY (#{quote_column_name(o.column)})
70
- REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
71
- SQL
72
- sql << " #{action_sql('DELETE', o.on_delete)}" if o.on_delete
73
- sql << " #{action_sql('UPDATE', o.on_update)}" if o.on_update
74
- sql
75
- end
108
+ def visit_CheckConstraintDefinition(o)
109
+ "CONSTRAINT #{o.name} CHECK (#{o.expression})"
110
+ end
76
111
 
77
- def visit_AddForeignKey(o)
78
- "ADD #{accept(o)}"
79
- end
112
+ def visit_AddCheckConstraint(o)
113
+ "ADD #{accept(o)}"
114
+ end
80
115
 
81
- def visit_DropForeignKey(name)
82
- "DROP CONSTRAINT #{quote_column_name(name)}"
83
- end
116
+ def visit_DropCheckConstraint(name)
117
+ "DROP CONSTRAINT #{quote_column_name(name)}"
118
+ end
84
119
 
85
- def table_options(o)
86
- table_options = {}
87
- table_options[:comment] = o.comment
88
- table_options[:options] = o.options
89
- table_options
90
- end
120
+ def quoted_columns(o)
121
+ String === o.columns ? o.columns : quoted_columns_for_index(o.columns, o.column_options)
122
+ end
91
123
 
92
- def add_table_options!(create_sql, options)
93
- if options_sql = options[:options]
94
- create_sql << " #{options_sql}"
95
- end
96
- create_sql
97
- end
124
+ def supports_index_using?
125
+ true
126
+ end
98
127
 
99
- def column_options(o)
100
- o.options.merge(column: o)
101
- end
128
+ def add_table_options!(create_sql, o)
129
+ create_sql << " #{o.options}" if o.options
130
+ create_sql
131
+ end
102
132
 
103
- def add_column_options!(sql, options)
104
- sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
105
- # must explicitly check for :null to allow change_column to work on migrations
106
- if options[:null] == false
107
- sql << " NOT NULL"
108
- end
109
- if options[:auto_increment] == true
110
- sql << " AUTO_INCREMENT"
111
- end
112
- if options[:primary_key] == true
113
- sql << " PRIMARY KEY"
114
- end
115
- sql
116
- end
133
+ def column_options(o)
134
+ o.options.merge(column: o)
135
+ end
117
136
 
118
- def to_sql(sql)
119
- sql = sql.to_sql if sql.respond_to?(:to_sql)
120
- sql
137
+ def add_column_options!(sql, options)
138
+ sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
139
+ # must explicitly check for :null to allow change_column to work on migrations
140
+ if options[:null] == false
141
+ sql << " NOT NULL"
121
142
  end
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
143
+ if options[:auto_increment] == true
144
+ sql << " AUTO_INCREMENT"
126
145
  end
127
-
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}"
132
- options = foreign_key_options(from_table, to_table, options)
133
- accept ForeignKeyDefinition.new(from_table, to_table, options)
146
+ if options[:primary_key] == true
147
+ sql << " PRIMARY KEY"
134
148
  end
149
+ sql
150
+ end
135
151
 
136
- def action_sql(action, dependency)
137
- case dependency
138
- when :nullify then "ON #{action} SET NULL"
139
- when :cascade then "ON #{action} CASCADE"
140
- when :restrict then "ON #{action} RESTRICT"
141
- else
142
- raise ArgumentError, <<~MSG
143
- '#{dependency}' is not supported for :on_update or :on_delete.
144
- Supported values are: :nullify, :cascade, :restrict
145
- MSG
146
- end
152
+ def to_sql(sql)
153
+ sql = sql.to_sql if sql.respond_to?(:to_sql)
154
+ sql
155
+ end
156
+
157
+ # Returns any SQL string to go between CREATE and TABLE. May be nil.
158
+ def table_modifier_in_create(o)
159
+ " TEMPORARY" if o.temporary
160
+ end
161
+
162
+ def foreign_key_in_create(from_table, to_table, options)
163
+ prefix = ActiveRecord::Base.table_name_prefix
164
+ suffix = ActiveRecord::Base.table_name_suffix
165
+ to_table = "#{prefix}#{to_table}#{suffix}"
166
+ options = foreign_key_options(from_table, to_table, options)
167
+ accept ForeignKeyDefinition.new(from_table, to_table, options)
168
+ end
169
+
170
+ def check_constraint_in_create(table_name, expression, options)
171
+ options = check_constraint_options(table_name, expression, options)
172
+ accept CheckConstraintDefinition.new(table_name, expression, options)
173
+ end
174
+
175
+ def action_sql(action, dependency)
176
+ case dependency
177
+ when :nullify then "ON #{action} SET NULL"
178
+ when :cascade then "ON #{action} CASCADE"
179
+ when :restrict then "ON #{action} RESTRICT"
180
+ else
181
+ raise ArgumentError, <<~MSG
182
+ '#{dependency}' is not supported for :on_update or :on_delete.
183
+ Supported values are: :nullify, :cascade, :restrict
184
+ MSG
147
185
  end
148
- end
186
+ end
149
187
  end
150
- SchemaCreation = AbstractAdapter::SchemaCreation # :nodoc:
151
188
  end
152
189
  end
@@ -33,6 +33,14 @@ module ActiveRecord
33
33
  @comment = comment
34
34
  end
35
35
 
36
+ def column_options
37
+ {
38
+ length: lengths,
39
+ order: orders,
40
+ opclass: opclasses,
41
+ }
42
+ end
43
+
36
44
  private
37
45
  def concise_options(options)
38
46
  if columns.size == options.size && options.values.uniq.size == 1
@@ -73,6 +81,8 @@ module ActiveRecord
73
81
 
74
82
  ChangeColumnDefinition = Struct.new(:column, :name) #:nodoc:
75
83
 
84
+ CreateIndexDefinition = Struct.new(:index, :algorithm, :if_not_exists) # :nodoc:
85
+
76
86
  PrimaryKeyDefinition = Struct.new(:name) # :nodoc:
77
87
 
78
88
  ForeignKeyDefinition = Struct.new(:from_table, :to_table, :options) do #:nodoc:
@@ -121,6 +131,21 @@ module ActiveRecord
121
131
  end
122
132
  end
123
133
 
134
+ CheckConstraintDefinition = Struct.new(:table_name, :expression, :options) do
135
+ def name
136
+ options[:name]
137
+ end
138
+
139
+ def validate?
140
+ options.fetch(:validate, true)
141
+ end
142
+ alias validated? validate?
143
+
144
+ def export_name_on_schema_dump?
145
+ !ActiveRecord::SchemaDumper.chk_ignore_pattern.match?(name) if name
146
+ end
147
+ end
148
+
124
149
  class ReferenceDefinition # :nodoc:
125
150
  def initialize(
126
151
  name,
@@ -143,13 +168,12 @@ module ActiveRecord
143
168
  end
144
169
 
145
170
  def add_to(table)
146
- columns.each do |column_options|
147
- kwargs = column_options.extract_options!
148
- table.column(*column_options, **kwargs)
171
+ columns.each do |name, type, options|
172
+ table.column(name, type, **options)
149
173
  end
150
174
 
151
175
  if index
152
- table.index(column_names, index_options)
176
+ table.index(column_names, **index_options(table.name))
153
177
  end
154
178
 
155
179
  if foreign_key
@@ -168,8 +192,18 @@ module ActiveRecord
168
192
  as_options(polymorphic).merge(options.slice(:null, :first, :after))
169
193
  end
170
194
 
171
- def index_options
172
- as_options(index)
195
+ def polymorphic_index_name(table_name)
196
+ "index_#{table_name}_on_#{name}"
197
+ end
198
+
199
+ def index_options(table_name)
200
+ index_options = as_options(index)
201
+
202
+ # legacy reference index names are used on versions 6.0 and earlier
203
+ return index_options if options[:_uses_legacy_reference_index_name]
204
+
205
+ index_options[:name] ||= polymorphic_index_name(table_name) if polymorphic
206
+ index_options
173
207
  end
174
208
 
175
209
  def foreign_key_options
@@ -227,7 +261,7 @@ module ActiveRecord
227
261
  end
228
262
 
229
263
  class_methods do
230
- private def define_column_methods(*column_types) # :nodoc:
264
+ def define_column_methods(*column_types) # :nodoc:
231
265
  column_types.each do |column_type|
232
266
  module_eval <<-RUBY, __FILE__, __LINE__ + 1
233
267
  def #{column_type}(*names, **options)
@@ -237,6 +271,7 @@ module ActiveRecord
237
271
  RUBY
238
272
  end
239
273
  end
274
+ private :define_column_methods
240
275
  end
241
276
  end
242
277
 
@@ -246,7 +281,7 @@ module ActiveRecord
246
281
  # Inside migration files, the +t+ object in {create_table}[rdoc-ref:SchemaStatements#create_table]
247
282
  # is actually of this type:
248
283
  #
249
- # class SomeMigration < ActiveRecord::Migration[5.0]
284
+ # class SomeMigration < ActiveRecord::Migration[6.0]
250
285
  # def up
251
286
  # create_table :foo do |t|
252
287
  # puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
@@ -261,7 +296,7 @@ module ActiveRecord
261
296
  class TableDefinition
262
297
  include ColumnMethods
263
298
 
264
- attr_reader :name, :temporary, :if_not_exists, :options, :as, :comment, :indexes, :foreign_keys
299
+ attr_reader :name, :temporary, :if_not_exists, :options, :as, :comment, :indexes, :foreign_keys, :check_constraints
265
300
 
266
301
  def initialize(
267
302
  conn,
@@ -278,6 +313,7 @@ module ActiveRecord
278
313
  @indexes = []
279
314
  @foreign_keys = []
280
315
  @primary_keys = nil
316
+ @check_constraints = []
281
317
  @temporary = temporary
282
318
  @if_not_exists = if_not_exists
283
319
  @options = options
@@ -366,7 +402,7 @@ module ActiveRecord
366
402
  # t.references :tagger, polymorphic: true
367
403
  # t.references :taggable, polymorphic: { default: 'Photo' }, index: false
368
404
  # end
369
- def column(name, type, **options)
405
+ def column(name, type, index: nil, **options)
370
406
  name = name.to_s
371
407
  type = type.to_sym if type
372
408
 
@@ -378,9 +414,13 @@ module ActiveRecord
378
414
  end
379
415
  end
380
416
 
381
- index_options = options.delete(:index)
382
- index(name, index_options.is_a?(Hash) ? index_options : {}) if index_options
383
417
  @columns_hash[name] = new_column_definition(name, type, **options)
418
+
419
+ if index
420
+ index_options = index.is_a?(Hash) ? index : {}
421
+ index(name, **index_options)
422
+ end
423
+
384
424
  self
385
425
  end
386
426
 
@@ -394,7 +434,7 @@ module ActiveRecord
394
434
  # This is primarily used to track indexes that need to be created after the table
395
435
  #
396
436
  # index(:account_id, name: 'index_projects_on_account_id')
397
- def index(column_name, options = {})
437
+ def index(column_name, **options)
398
438
  indexes << [column_name, options]
399
439
  end
400
440
 
@@ -402,6 +442,10 @@ module ActiveRecord
402
442
  foreign_keys << [table_name, options]
403
443
  end
404
444
 
445
+ def check_constraint(expression, **options)
446
+ check_constraints << [expression, options]
447
+ end
448
+
405
449
  # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
406
450
  # <tt>:updated_at</tt> to the table. See {connection.add_timestamps}[rdoc-ref:SchemaStatements#add_timestamps]
407
451
  #
@@ -461,14 +505,16 @@ module ActiveRecord
461
505
 
462
506
  class AlterTable # :nodoc:
463
507
  attr_reader :adds
464
- attr_reader :foreign_key_adds
465
- attr_reader :foreign_key_drops
508
+ attr_reader :foreign_key_adds, :foreign_key_drops
509
+ attr_reader :check_constraint_adds, :check_constraint_drops
466
510
 
467
511
  def initialize(td)
468
512
  @td = td
469
513
  @adds = []
470
514
  @foreign_key_adds = []
471
515
  @foreign_key_drops = []
516
+ @check_constraint_adds = []
517
+ @check_constraint_drops = []
472
518
  end
473
519
 
474
520
  def name; @td.name; end
@@ -481,6 +527,14 @@ module ActiveRecord
481
527
  @foreign_key_drops << name
482
528
  end
483
529
 
530
+ def add_check_constraint(expression, options)
531
+ @check_constraint_adds << CheckConstraintDefinition.new(name, expression, options)
532
+ end
533
+
534
+ def drop_check_constraint(constraint_name)
535
+ @check_constraint_drops << constraint_name
536
+ end
537
+
484
538
  def add_column(name, type, **options)
485
539
  name = name.to_s
486
540
  type = type.to_sym
@@ -501,9 +555,11 @@ module ActiveRecord
501
555
  # t.timestamps
502
556
  # t.change
503
557
  # t.change_default
558
+ # t.change_null
504
559
  # t.rename
505
560
  # t.references
506
561
  # t.belongs_to
562
+ # t.check_constraint
507
563
  # t.string
508
564
  # t.text
509
565
  # t.integer
@@ -525,6 +581,7 @@ module ActiveRecord
525
581
  # t.remove_references
526
582
  # t.remove_belongs_to
527
583
  # t.remove_index
584
+ # t.remove_check_constraint
528
585
  # t.remove_timestamps
529
586
  # end
530
587
  #
@@ -543,10 +600,12 @@ module ActiveRecord
543
600
  # t.column(:name, :string)
544
601
  #
545
602
  # See TableDefinition#column for details of the options you can use.
546
- def column(column_name, type, **options)
547
- index_options = options.delete(:index)
603
+ def column(column_name, type, index: nil, **options)
548
604
  @base.add_column(name, column_name, type, **options)
549
- index(column_name, index_options.is_a?(Hash) ? index_options : {}) if index_options
605
+ if index
606
+ index_options = index.is_a?(Hash) ? index : {}
607
+ index(column_name, **index_options)
608
+ end
550
609
  end
551
610
 
552
611
  # Checks to see if a column exists.
@@ -566,8 +625,8 @@ module ActiveRecord
566
625
  # t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party')
567
626
  #
568
627
  # See {connection.add_index}[rdoc-ref:SchemaStatements#add_index] for details of the options you can use.
569
- def index(column_name, options = {})
570
- @base.add_index(name, column_name, options)
628
+ def index(column_name, **options)
629
+ @base.add_index(name, column_name, **options)
571
630
  end
572
631
 
573
632
  # Checks to see if an index exists.
@@ -605,8 +664,8 @@ module ActiveRecord
605
664
  # t.change(:description, :text)
606
665
  #
607
666
  # See TableDefinition#column for details of the options you can use.
608
- def change(column_name, type, options = {})
609
- @base.change_column(name, column_name, type, options)
667
+ def change(column_name, type, **options)
668
+ @base.change_column(name, column_name, type, **options)
610
669
  end
611
670
 
612
671
  # Sets a new default value for a column.
@@ -620,14 +679,24 @@ module ActiveRecord
620
679
  @base.change_column_default(name, column_name, default_or_changes)
621
680
  end
622
681
 
682
+ # Sets or removes a NOT NULL constraint on a column.
683
+ #
684
+ # t.change_null(:qualification, true)
685
+ # t.change_null(:qualification, false, 0)
686
+ #
687
+ # See {connection.change_column_null}[rdoc-ref:SchemaStatements#change_column_null]
688
+ def change_null(column_name, null, default = nil)
689
+ @base.change_column_null(name, column_name, null, default)
690
+ end
691
+
623
692
  # Removes the column(s) from the table definition.
624
693
  #
625
694
  # t.remove(:qualification)
626
695
  # t.remove(:qualification, :experience)
627
696
  #
628
697
  # See {connection.remove_columns}[rdoc-ref:SchemaStatements#remove_columns]
629
- def remove(*column_names)
630
- @base.remove_columns(name, *column_names)
698
+ def remove(*column_names, **options)
699
+ @base.remove_columns(name, *column_names, **options)
631
700
  end
632
701
 
633
702
  # Removes the given index from the table.
@@ -635,10 +704,11 @@ module ActiveRecord
635
704
  # t.remove_index(:branch_id)
636
705
  # t.remove_index(column: [:branch_id, :party_id])
637
706
  # t.remove_index(name: :by_branch_party)
707
+ # t.remove_index(:branch_id, name: :by_branch_party)
638
708
  #
639
709
  # See {connection.remove_index}[rdoc-ref:SchemaStatements#remove_index]
640
- def remove_index(options = {})
641
- @base.remove_index(name, options)
710
+ def remove_index(column_name = nil, **options)
711
+ @base.remove_index(name, column_name, **options)
642
712
  end
643
713
 
644
714
  # Removes the timestamp columns (+created_at+ and +updated_at+) from the table.
@@ -713,6 +783,24 @@ module ActiveRecord
713
783
  def foreign_key_exists?(*args, **options)
714
784
  @base.foreign_key_exists?(name, *args, **options)
715
785
  end
786
+
787
+ # Adds a check constraint.
788
+ #
789
+ # t.check_constraint("price > 0", name: "price_check")
790
+ #
791
+ # See {connection.add_check_constraint}[rdoc-ref:SchemaStatements#add_check_constraint]
792
+ def check_constraint(*args)
793
+ @base.add_check_constraint(name, *args)
794
+ end
795
+
796
+ # Removes the given check constraint from the table.
797
+ #
798
+ # t.remove_check_constraint(name: "price_check")
799
+ #
800
+ # See {connection.remove_check_constraint}[rdoc-ref:SchemaStatements#remove_check_constraint]
801
+ def remove_check_constraint(*args)
802
+ @base.remove_check_constraint(name, *args)
803
+ end
716
804
  end
717
805
  end
718
806
  end
@@ -13,9 +13,9 @@ module ActiveRecord
13
13
  end
14
14
 
15
15
  def column_spec_for_primary_key(column)
16
- return {} if default_primary_key?(column)
17
- spec = { id: schema_type(column).inspect }
18
- spec.merge!(prepare_column_options(column).except!(:null, :comment))
16
+ spec = {}
17
+ spec[:id] = schema_type(column).inspect unless default_primary_key?(column)
18
+ spec.merge!(prepare_column_options(column).except!(:null))
19
19
  spec[:default] ||= "nil" if explicit_primary_key_default?(column)
20
20
  spec
21
21
  end