activerecord 4.2.0 → 5.0.0

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 (249) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1537 -789
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -8
  5. data/examples/performance.rb +2 -3
  6. data/examples/simple.rb +0 -1
  7. data/lib/active_record/aggregations.rb +37 -23
  8. data/lib/active_record/association_relation.rb +16 -3
  9. data/lib/active_record/associations/alias_tracker.rb +19 -16
  10. data/lib/active_record/associations/association.rb +23 -9
  11. data/lib/active_record/associations/association_scope.rb +74 -102
  12. data/lib/active_record/associations/belongs_to_association.rb +26 -29
  13. data/lib/active_record/associations/builder/association.rb +28 -34
  14. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  15. data/lib/active_record/associations/builder/collection_association.rb +12 -20
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +22 -15
  17. data/lib/active_record/associations/builder/has_many.rb +4 -4
  18. data/lib/active_record/associations/builder/has_one.rb +11 -6
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -10
  20. data/lib/active_record/associations/collection_association.rb +61 -33
  21. data/lib/active_record/associations/collection_proxy.rb +81 -35
  22. data/lib/active_record/associations/foreign_association.rb +11 -0
  23. data/lib/active_record/associations/has_many_association.rb +21 -57
  24. data/lib/active_record/associations/has_many_through_association.rb +15 -45
  25. data/lib/active_record/associations/has_one_association.rb +13 -5
  26. data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
  27. data/lib/active_record/associations/join_dependency.rb +37 -21
  28. data/lib/active_record/associations/preloader/association.rb +51 -53
  29. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  30. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  31. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  32. data/lib/active_record/associations/preloader/through_association.rb +27 -14
  33. data/lib/active_record/associations/preloader.rb +18 -8
  34. data/lib/active_record/associations/singular_association.rb +8 -8
  35. data/lib/active_record/associations/through_association.rb +22 -9
  36. data/lib/active_record/associations.rb +321 -212
  37. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  38. data/lib/active_record/attribute.rb +79 -15
  39. data/lib/active_record/attribute_assignment.rb +20 -141
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +6 -1
  42. data/lib/active_record/attribute_methods/dirty.rb +51 -81
  43. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  44. data/lib/active_record/attribute_methods/query.rb +2 -2
  45. data/lib/active_record/attribute_methods/read.rb +31 -59
  46. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -14
  48. data/lib/active_record/attribute_methods/write.rb +14 -38
  49. data/lib/active_record/attribute_methods.rb +70 -45
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set/builder.rb +37 -15
  52. data/lib/active_record/attribute_set.rb +34 -3
  53. data/lib/active_record/attributes.rb +199 -73
  54. data/lib/active_record/autosave_association.rb +73 -25
  55. data/lib/active_record/base.rb +35 -27
  56. data/lib/active_record/callbacks.rb +39 -43
  57. data/lib/active_record/coders/json.rb +1 -1
  58. data/lib/active_record/coders/yaml_column.rb +20 -8
  59. data/lib/active_record/collection_cache_key.rb +40 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +457 -181
  61. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  62. data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -59
  63. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -3
  64. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
  65. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -4
  66. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  67. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +246 -185
  68. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  69. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +438 -136
  70. data/lib/active_record/connection_adapters/abstract/transaction.rb +53 -40
  71. data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -66
  72. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +429 -335
  73. data/lib/active_record/connection_adapters/column.rb +28 -43
  74. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  75. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  76. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  77. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  78. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  79. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  81. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  82. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  83. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  84. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -177
  85. data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
  86. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +11 -73
  87. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -56
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -13
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  95. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  98. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  99. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  101. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
  102. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  103. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  106. data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
  107. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  108. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  109. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +248 -154
  111. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  112. data/lib/active_record/connection_adapters/postgresql_adapter.rb +258 -170
  113. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  114. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  115. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  116. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  117. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +150 -209
  119. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  120. data/lib/active_record/connection_handling.rb +38 -15
  121. data/lib/active_record/core.rb +109 -114
  122. data/lib/active_record/counter_cache.rb +14 -25
  123. data/lib/active_record/dynamic_matchers.rb +1 -20
  124. data/lib/active_record/enum.rb +115 -79
  125. data/lib/active_record/errors.rb +88 -48
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +2 -2
  128. data/lib/active_record/fixture_set/file.rb +26 -5
  129. data/lib/active_record/fixtures.rb +84 -46
  130. data/lib/active_record/gem_version.rb +2 -2
  131. data/lib/active_record/inheritance.rb +32 -40
  132. data/lib/active_record/integration.rb +4 -4
  133. data/lib/active_record/internal_metadata.rb +56 -0
  134. data/lib/active_record/legacy_yaml_adapter.rb +46 -0
  135. data/lib/active_record/locale/en.yml +3 -2
  136. data/lib/active_record/locking/optimistic.rb +27 -25
  137. data/lib/active_record/locking/pessimistic.rb +1 -1
  138. data/lib/active_record/log_subscriber.rb +43 -21
  139. data/lib/active_record/migration/command_recorder.rb +59 -18
  140. data/lib/active_record/migration/compatibility.rb +126 -0
  141. data/lib/active_record/migration.rb +372 -114
  142. data/lib/active_record/model_schema.rb +128 -38
  143. data/lib/active_record/nested_attributes.rb +71 -32
  144. data/lib/active_record/no_touching.rb +1 -1
  145. data/lib/active_record/null_relation.rb +16 -8
  146. data/lib/active_record/persistence.rb +124 -80
  147. data/lib/active_record/query_cache.rb +15 -18
  148. data/lib/active_record/querying.rb +10 -9
  149. data/lib/active_record/railtie.rb +28 -19
  150. data/lib/active_record/railties/controller_runtime.rb +1 -1
  151. data/lib/active_record/railties/databases.rake +67 -51
  152. data/lib/active_record/readonly_attributes.rb +1 -1
  153. data/lib/active_record/reflection.rb +318 -139
  154. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  155. data/lib/active_record/relation/batches.rb +139 -34
  156. data/lib/active_record/relation/calculations.rb +80 -102
  157. data/lib/active_record/relation/delegation.rb +7 -20
  158. data/lib/active_record/relation/finder_methods.rb +167 -97
  159. data/lib/active_record/relation/from_clause.rb +32 -0
  160. data/lib/active_record/relation/merger.rb +38 -41
  161. data/lib/active_record/relation/predicate_builder/array_handler.rb +12 -16
  162. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  163. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  164. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  165. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  166. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  167. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  168. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  169. data/lib/active_record/relation/predicate_builder.rb +124 -82
  170. data/lib/active_record/relation/query_attribute.rb +19 -0
  171. data/lib/active_record/relation/query_methods.rb +323 -257
  172. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  173. data/lib/active_record/relation/spawn_methods.rb +11 -10
  174. data/lib/active_record/relation/where_clause.rb +174 -0
  175. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  176. data/lib/active_record/relation.rb +176 -115
  177. data/lib/active_record/result.rb +4 -3
  178. data/lib/active_record/runtime_registry.rb +1 -1
  179. data/lib/active_record/sanitization.rb +95 -66
  180. data/lib/active_record/schema.rb +26 -22
  181. data/lib/active_record/schema_dumper.rb +62 -38
  182. data/lib/active_record/schema_migration.rb +11 -17
  183. data/lib/active_record/scoping/default.rb +24 -9
  184. data/lib/active_record/scoping/named.rb +49 -28
  185. data/lib/active_record/scoping.rb +32 -15
  186. data/lib/active_record/secure_token.rb +38 -0
  187. data/lib/active_record/serialization.rb +2 -4
  188. data/lib/active_record/statement_cache.rb +16 -14
  189. data/lib/active_record/store.rb +8 -3
  190. data/lib/active_record/suppressor.rb +58 -0
  191. data/lib/active_record/table_metadata.rb +68 -0
  192. data/lib/active_record/tasks/database_tasks.rb +59 -42
  193. data/lib/active_record/tasks/mysql_database_tasks.rb +32 -26
  194. data/lib/active_record/tasks/postgresql_database_tasks.rb +29 -9
  195. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  196. data/lib/active_record/timestamp.rb +20 -9
  197. data/lib/active_record/touch_later.rb +58 -0
  198. data/lib/active_record/transactions.rb +159 -67
  199. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  200. data/lib/active_record/type/date.rb +2 -41
  201. data/lib/active_record/type/date_time.rb +2 -38
  202. data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
  203. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  204. data/lib/active_record/type/internal/timezone.rb +15 -0
  205. data/lib/active_record/type/serialized.rb +21 -14
  206. data/lib/active_record/type/time.rb +10 -16
  207. data/lib/active_record/type/type_map.rb +4 -4
  208. data/lib/active_record/type.rb +66 -17
  209. data/lib/active_record/type_caster/connection.rb +29 -0
  210. data/lib/active_record/type_caster/map.rb +19 -0
  211. data/lib/active_record/type_caster.rb +7 -0
  212. data/lib/active_record/validations/absence.rb +23 -0
  213. data/lib/active_record/validations/associated.rb +10 -3
  214. data/lib/active_record/validations/length.rb +24 -0
  215. data/lib/active_record/validations/presence.rb +11 -12
  216. data/lib/active_record/validations/uniqueness.rb +29 -18
  217. data/lib/active_record/validations.rb +33 -32
  218. data/lib/active_record.rb +9 -2
  219. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  220. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -6
  221. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -7
  222. data/lib/rails/generators/active_record/migration.rb +7 -0
  223. data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
  224. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  225. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  226. metadata +60 -34
  227. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  228. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  229. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  230. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  231. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  232. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  233. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  234. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  235. data/lib/active_record/type/big_integer.rb +0 -13
  236. data/lib/active_record/type/binary.rb +0 -50
  237. data/lib/active_record/type/boolean.rb +0 -30
  238. data/lib/active_record/type/decimal.rb +0 -40
  239. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  240. data/lib/active_record/type/decorator.rb +0 -14
  241. data/lib/active_record/type/float.rb +0 -19
  242. data/lib/active_record/type/integer.rb +0 -55
  243. data/lib/active_record/type/mutable.rb +0 -16
  244. data/lib/active_record/type/numeric.rb +0 -36
  245. data/lib/active_record/type/string.rb +0 -36
  246. data/lib/active_record/type/text.rb +0 -11
  247. data/lib/active_record/type/time_value.rb +0 -38
  248. data/lib/active_record/type/unsigned_integer.rb +0 -15
  249. data/lib/active_record/type/value.rb +0 -101
@@ -1,28 +1,29 @@
1
- require 'date'
2
- require 'set'
3
- require 'bigdecimal'
4
- require 'bigdecimal/util'
5
-
6
1
  module ActiveRecord
7
2
  module ConnectionAdapters #:nodoc:
8
3
  # Abstract representation of an index definition on a table. Instances of
9
4
  # this type are typically created and returned by methods in database
10
5
  # adapters. e.g. ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#indexes
11
- class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :type, :using) #:nodoc:
6
+ class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :type, :using, :comment) #:nodoc:
12
7
  end
13
8
 
14
9
  # Abstract representation of a column definition. Instances of this type
15
10
  # are typically created by methods in TableDefinition, and added to the
16
11
  # +columns+ attribute of said TableDefinition object, in order to be used
17
12
  # for generating a number of table creation or table changing SQL statements.
18
- class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key, :sql_type, :cast_type) #:nodoc:
13
+ class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :auto_increment, :primary_key, :collation, :sql_type, :comment) #:nodoc:
19
14
 
20
15
  def primary_key?
21
16
  primary_key || type.to_sym == :primary_key
22
17
  end
23
18
  end
24
19
 
25
- class ChangeColumnDefinition < Struct.new(:column, :type, :options) #:nodoc:
20
+ class AddColumnDefinition < Struct.new(:column) # :nodoc:
21
+ end
22
+
23
+ class ChangeColumnDefinition < Struct.new(:column, :name) #:nodoc:
24
+ end
25
+
26
+ class PrimaryKeyDefinition < Struct.new(:name) # :nodoc:
26
27
  end
27
28
 
28
29
  class ForeignKeyDefinition < Struct.new(:from_table, :to_table, :options) #:nodoc:
@@ -50,31 +51,147 @@ module ActiveRecord
50
51
  options[:primary_key] != default_primary_key
51
52
  end
52
53
 
54
+ def defined_for?(options_or_to_table = {})
55
+ if options_or_to_table.is_a?(Hash)
56
+ options_or_to_table.all? {|key, value| options[key].to_s == value.to_s }
57
+ else
58
+ to_table == options_or_to_table.to_s
59
+ end
60
+ end
61
+
53
62
  private
54
63
  def default_primary_key
55
64
  "id"
56
65
  end
57
66
  end
58
67
 
59
- module TimestampDefaultDeprecation # :nodoc:
60
- def emit_warning_if_null_unspecified(options)
61
- return if options.key?(:null)
68
+ class ReferenceDefinition # :nodoc:
69
+ def initialize(
70
+ name,
71
+ polymorphic: false,
72
+ index: true,
73
+ foreign_key: false,
74
+ type: :integer,
75
+ **options
76
+ )
77
+ @name = name
78
+ @polymorphic = polymorphic
79
+ @index = index
80
+ @foreign_key = foreign_key
81
+ @type = type
82
+ @options = options
83
+
84
+ if polymorphic && foreign_key
85
+ raise ArgumentError, "Cannot add a foreign key to a polymorphic relation"
86
+ end
87
+ end
88
+
89
+ def add_to(table)
90
+ columns.each do |column_options|
91
+ table.column(*column_options)
92
+ end
93
+
94
+ if index
95
+ table.index(column_names, index_options)
96
+ end
97
+
98
+ if foreign_key
99
+ table.foreign_key(foreign_table_name, foreign_key_options)
100
+ end
101
+ end
102
+
103
+ protected
62
104
 
63
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
64
- `#timestamp` was called without specifying an option for `null`. In Rails 5,
65
- this behavior will change to `null: false`. You should manually specify
66
- `null: true` to prevent the behavior of your existing migrations from changing.
67
- MSG
105
+ attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options
106
+
107
+ private
108
+
109
+ def as_options(value, default = {})
110
+ if value.is_a?(Hash)
111
+ value
112
+ else
113
+ default
114
+ end
115
+ end
116
+
117
+ def polymorphic_options
118
+ as_options(polymorphic, options)
119
+ end
120
+
121
+ def index_options
122
+ as_options(index)
123
+ end
124
+
125
+ def foreign_key_options
126
+ as_options(foreign_key).merge(column: column_name)
127
+ end
128
+
129
+ def columns
130
+ result = [[column_name, type, options]]
131
+ if polymorphic
132
+ result.unshift(["#{name}_type", :string, polymorphic_options])
133
+ end
134
+ result
135
+ end
136
+
137
+ def column_name
138
+ "#{name}_id"
139
+ end
140
+
141
+ def column_names
142
+ columns.map(&:first)
143
+ end
144
+
145
+ def foreign_table_name
146
+ foreign_key_options.fetch(:to_table) do
147
+ Base.pluralize_table_names ? name.to_s.pluralize : name
148
+ end
68
149
  end
69
150
  end
70
151
 
152
+ module ColumnMethods
153
+ # Appends a primary key definition to the table definition.
154
+ # Can be called multiple times, but this is probably not a good idea.
155
+ def primary_key(name, type = :primary_key, **options)
156
+ column(name, type, options.merge(primary_key: true))
157
+ end
158
+
159
+ # Appends a column or columns of a specified type.
160
+ #
161
+ # t.string(:goat)
162
+ # t.string(:goat, :sheep)
163
+ #
164
+ # See TableDefinition#column
165
+ [
166
+ :bigint,
167
+ :binary,
168
+ :boolean,
169
+ :date,
170
+ :datetime,
171
+ :decimal,
172
+ :float,
173
+ :integer,
174
+ :string,
175
+ :text,
176
+ :time,
177
+ :timestamp,
178
+ ].each do |column_type|
179
+ module_eval <<-CODE, __FILE__, __LINE__ + 1
180
+ def #{column_type}(*args, **options)
181
+ args.each { |name| column(name, :#{column_type}, options) }
182
+ end
183
+ CODE
184
+ end
185
+ alias_method :numeric, :decimal
186
+ end
187
+
71
188
  # Represents the schema of an SQL table in an abstract way. This class
72
189
  # provides methods for manipulating the schema representation.
73
190
  #
74
- # Inside migration files, the +t+ object in +create_table+
191
+ # Inside migration files, the +t+ object in {create_table}[rdoc-ref:SchemaStatements#create_table]
75
192
  # is actually of this type:
76
193
  #
77
- # class SomeMigration < ActiveRecord::Migration
194
+ # class SomeMigration < ActiveRecord::Migration[5.0]
78
195
  # def up
79
196
  # create_table :foo do |t|
80
197
  # puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
@@ -86,124 +203,55 @@ module ActiveRecord
86
203
  # end
87
204
  # end
88
205
  #
89
- # The table definitions
90
- # The Columns are stored as a ColumnDefinition in the +columns+ attribute.
91
206
  class TableDefinition
92
- include TimestampDefaultDeprecation
207
+ include ColumnMethods
93
208
 
94
- # An array of ColumnDefinition objects, representing the column changes
95
- # that have been defined.
96
209
  attr_accessor :indexes
97
- attr_reader :name, :temporary, :options, :as
210
+ attr_reader :name, :temporary, :options, :as, :foreign_keys, :comment
98
211
 
99
- def initialize(types, name, temporary, options, as = nil)
212
+ def initialize(name, temporary = false, options = nil, as = nil, comment: nil)
100
213
  @columns_hash = {}
101
214
  @indexes = {}
102
- @native = types
215
+ @foreign_keys = []
216
+ @primary_keys = nil
103
217
  @temporary = temporary
104
218
  @options = options
105
219
  @as = as
106
220
  @name = name
221
+ @comment = comment
107
222
  end
108
223
 
109
- def columns; @columns_hash.values; end
110
-
111
- # Appends a primary key definition to the table definition.
112
- # Can be called multiple times, but this is probably not a good idea.
113
- def primary_key(name, type = :primary_key, options = {})
114
- column(name, type, options.merge(:primary_key => true))
224
+ def primary_keys(name = nil) # :nodoc:
225
+ @primary_keys = PrimaryKeyDefinition.new(name) if name
226
+ @primary_keys
115
227
  end
116
228
 
229
+ # Returns an array of ColumnDefinition objects for the columns of the table.
230
+ def columns; @columns_hash.values; end
231
+
117
232
  # Returns a ColumnDefinition for the column with name +name+.
118
233
  def [](name)
119
234
  @columns_hash[name.to_s]
120
235
  end
121
236
 
122
237
  # Instantiates a new column for the table.
123
- # The +type+ parameter is normally one of the migrations native types,
124
- # which is one of the following:
125
- # <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
126
- # <tt>:integer</tt>, <tt>:float</tt>, <tt>:decimal</tt>,
127
- # <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
128
- # <tt>:binary</tt>, <tt>:boolean</tt>.
129
- #
130
- # You may use a type not in this list as long as it is supported by your
131
- # database (for example, "polygon" in MySQL), but this will not be database
132
- # agnostic and should usually be avoided.
133
- #
134
- # Available options are (none of these exists by default):
135
- # * <tt>:limit</tt> -
136
- # Requests a maximum column length. This is number of characters for <tt>:string</tt> and
137
- # <tt>:text</tt> columns and number of bytes for <tt>:binary</tt> and <tt>:integer</tt> columns.
138
- # * <tt>:default</tt> -
139
- # The column's default value. Use nil for NULL.
140
- # * <tt>:null</tt> -
141
- # Allows or disallows +NULL+ values in the column. This option could
142
- # have been named <tt>:null_allowed</tt>.
143
- # * <tt>:precision</tt> -
144
- # Specifies the precision for a <tt>:decimal</tt> column.
145
- # * <tt>:scale</tt> -
146
- # Specifies the scale for a <tt>:decimal</tt> column.
238
+ # See {connection.add_column}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_column]
239
+ # for available options.
240
+ #
241
+ # Additional options are:
147
242
  # * <tt>:index</tt> -
148
243
  # Create an index for the column. Can be either <tt>true</tt> or an options hash.
149
244
  #
150
- # Note: The precision is the total number of significant digits
151
- # and the scale is the number of digits that can be stored following
152
- # the decimal point. For example, the number 123.45 has a precision of 5
153
- # and a scale of 2. A decimal with a precision of 5 and a scale of 2 can
154
- # range from -999.99 to 999.99.
155
- #
156
- # Please be aware of different RDBMS implementations behavior with
157
- # <tt>:decimal</tt> columns:
158
- # * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
159
- # <tt>:precision</tt>, and makes no comments about the requirements of
160
- # <tt>:precision</tt>.
161
- # * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
162
- # Default is (10,0).
163
- # * PostgreSQL: <tt>:precision</tt> [1..infinity],
164
- # <tt>:scale</tt> [0..infinity]. No default.
165
- # * SQLite2: Any <tt>:precision</tt> and <tt>:scale</tt> may be used.
166
- # Internal storage as strings. No default.
167
- # * SQLite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>,
168
- # but the maximum supported <tt>:precision</tt> is 16. No default.
169
- # * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
170
- # Default is (38,0).
171
- # * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
172
- # Default unknown.
173
- # * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
174
- # Default (38,0).
175
- #
176
245
  # This method returns <tt>self</tt>.
177
246
  #
178
247
  # == Examples
179
- # # Assuming +td+ is an instance of TableDefinition
180
- # td.column(:granted, :boolean)
181
- # # granted BOOLEAN
182
248
  #
183
- # td.column(:picture, :binary, limit: 2.megabytes)
184
- # # => picture BLOB(2097152)
185
- #
186
- # td.column(:sales_stage, :string, limit: 20, default: 'new', null: false)
187
- # # => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
188
- #
189
- # td.column(:bill_gates_money, :decimal, precision: 15, scale: 2)
190
- # # => bill_gates_money DECIMAL(15,2)
191
- #
192
- # td.column(:sensor_reading, :decimal, precision: 30, scale: 20)
193
- # # => sensor_reading DECIMAL(30,20)
194
- #
195
- # # While <tt>:scale</tt> defaults to zero on most databases, it
196
- # # probably wouldn't hurt to include it.
197
- # td.column(:huge_integer, :decimal, precision: 30)
198
- # # => huge_integer DECIMAL(30)
199
- #
200
- # # Defines a column with a database-specific type.
201
- # td.column(:foo, 'polygon')
202
- # # => foo polygon
249
+ # # Assuming +td+ is an instance of TableDefinition
250
+ # td.column(:granted, :boolean, index: true)
203
251
  #
204
252
  # == Short-hand examples
205
253
  #
206
- # Instead of calling +column+ directly, you can also work with the short-hand definitions for the default types.
254
+ # Instead of calling #column directly, you can also work with the short-hand definitions for the default types.
207
255
  # They use the type as the method name instead of as a parameter and allow for multiple columns to be defined
208
256
  # in a single statement.
209
257
  #
@@ -235,7 +283,8 @@ module ActiveRecord
235
283
  # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type
236
284
  # column if the <tt>:polymorphic</tt> option is supplied. If <tt>:polymorphic</tt> is a hash of
237
285
  # options, these will be used when creating the <tt>_type</tt> column. The <tt>:index</tt> option
238
- # will also create an index, similar to calling <tt>add_index</tt>. So what can be written like this:
286
+ # will also create an index, similar to calling {add_index}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_index].
287
+ # So what can be written like this:
239
288
  #
240
289
  # create_table :taggings do |t|
241
290
  # t.integer :tag_id, :tagger_id, :taggable_id
@@ -255,6 +304,7 @@ module ActiveRecord
255
304
  def column(name, type, options = {})
256
305
  name = name.to_s
257
306
  type = type.to_sym
307
+ options = options.dup
258
308
 
259
309
  if @columns_hash[name] && @columns_hash[name].primary_key?
260
310
  raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
@@ -266,18 +316,12 @@ module ActiveRecord
266
316
  self
267
317
  end
268
318
 
319
+ # remove the column +name+ from the table.
320
+ # remove_column(:account_id)
269
321
  def remove_column(name)
270
322
  @columns_hash.delete name.to_s
271
323
  end
272
324
 
273
- [:string, :text, :integer, :bigint, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type|
274
- define_method column_type do |*args|
275
- options = args.extract_options!
276
- column_names = args
277
- column_names.each { |name| column(name, column_type, options) }
278
- end
279
- end
280
-
281
325
  # Adds index options to the indexes hash, keyed by column name
282
326
  # This is primarily used to track indexes that need to be created after the table
283
327
  #
@@ -286,35 +330,35 @@ module ActiveRecord
286
330
  indexes[column_name] = options
287
331
  end
288
332
 
333
+ def foreign_key(table_name, options = {}) # :nodoc:
334
+ table_name_prefix = ActiveRecord::Base.table_name_prefix
335
+ table_name_suffix = ActiveRecord::Base.table_name_suffix
336
+ table_name = "#{table_name_prefix}#{table_name}#{table_name_suffix}"
337
+ foreign_keys.push([table_name, options])
338
+ end
339
+
289
340
  # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
290
- # <tt>:updated_at</tt> to the table. See SchemaStatements#add_timestamps
341
+ # <tt>:updated_at</tt> to the table. See {connection.add_timestamps}[rdoc-ref:SchemaStatements#add_timestamps]
291
342
  #
292
343
  # t.timestamps null: false
293
344
  def timestamps(*args)
294
345
  options = args.extract_options!
295
- emit_warning_if_null_unspecified(options)
346
+
347
+ options[:null] = false if options[:null].nil?
348
+
296
349
  column(:created_at, :datetime, options)
297
350
  column(:updated_at, :datetime, options)
298
351
  end
299
352
 
300
- # Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
301
- # <tt>references</tt> and <tt>belongs_to</tt> are acceptable. The reference column will be an +integer+
302
- # by default, the <tt>:type</tt> option can be used to specify a different type.
353
+ # Adds a reference.
303
354
  #
304
355
  # t.references(:user)
305
- # t.references(:user, type: "string")
306
- # t.belongs_to(:supplier, polymorphic: true)
356
+ # t.belongs_to(:supplier, foreign_key: true)
307
357
  #
308
- # See SchemaStatements#add_reference
309
- def references(*args)
310
- options = args.extract_options!
311
- polymorphic = options.delete(:polymorphic)
312
- index_options = options.delete(:index)
313
- type = options.delete(:type) || :integer
358
+ # See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
359
+ def references(*args, **options)
314
360
  args.each do |col|
315
- column("#{col}_id", type, options)
316
- column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
317
- index(polymorphic ? %w(type id).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
361
+ ReferenceDefinition.new(col, **options).add_to(self)
318
362
  end
319
363
  end
320
364
  alias :belongs_to :references
@@ -322,18 +366,18 @@ module ActiveRecord
322
366
  def new_column_definition(name, type, options) # :nodoc:
323
367
  type = aliased_types(type.to_s, type)
324
368
  column = create_column_definition name, type
325
- limit = options.fetch(:limit) do
326
- native[type][:limit] if native[type].is_a?(Hash)
327
- end
328
369
 
329
- column.limit = limit
370
+ column.limit = options[:limit]
330
371
  column.precision = options[:precision]
331
372
  column.scale = options[:scale]
332
373
  column.default = options[:default]
333
374
  column.null = options[:null]
334
375
  column.first = options[:first]
335
376
  column.after = options[:after]
377
+ column.auto_increment = options[:auto_increment]
336
378
  column.primary_key = type == :primary_key || options[:primary_key]
379
+ column.collation = options[:collation]
380
+ column.comment = options[:comment]
337
381
  column
338
382
  end
339
383
 
@@ -342,10 +386,6 @@ module ActiveRecord
342
386
  ColumnDefinition.new name, type
343
387
  end
344
388
 
345
- def native
346
- @native
347
- end
348
-
349
389
  def aliased_types(name, fallback)
350
390
  'timestamp' == name ? :datetime : fallback
351
391
  end
@@ -376,16 +416,17 @@ module ActiveRecord
376
416
  def add_column(name, type, options)
377
417
  name = name.to_s
378
418
  type = type.to_sym
379
- @adds << @td.new_column_definition(name, type, options)
419
+ @adds << AddColumnDefinition.new(@td.new_column_definition(name, type, options))
380
420
  end
381
421
  end
382
422
 
383
423
  # Represents an SQL table in an abstract way for updating a table.
384
- # Also see TableDefinition and SchemaStatements#create_table
424
+ # Also see TableDefinition and {connection.create_table}[rdoc-ref:SchemaStatements#create_table]
385
425
  #
386
426
  # Available transformations are:
387
427
  #
388
428
  # change_table :table do |t|
429
+ # t.primary_key
389
430
  # t.column
390
431
  # t.index
391
432
  # t.rename_index
@@ -398,8 +439,10 @@ module ActiveRecord
398
439
  # t.string
399
440
  # t.text
400
441
  # t.integer
442
+ # t.bigint
401
443
  # t.float
402
444
  # t.decimal
445
+ # t.numeric
403
446
  # t.datetime
404
447
  # t.timestamp
405
448
  # t.time
@@ -414,6 +457,8 @@ module ActiveRecord
414
457
  # end
415
458
  #
416
459
  class Table
460
+ include ColumnMethods
461
+
417
462
  attr_reader :name
418
463
 
419
464
  def initialize(table_name, base)
@@ -422,33 +467,42 @@ module ActiveRecord
422
467
  end
423
468
 
424
469
  # Adds a new column to the named table.
425
- # See TableDefinition#column for details of the options you can use.
426
470
  #
427
- # ====== Creating a simple column
428
471
  # t.column(:name, :string)
472
+ #
473
+ # See TableDefinition#column for details of the options you can use.
429
474
  def column(column_name, type, options = {})
430
475
  @base.add_column(name, column_name, type, options)
431
476
  end
432
477
 
433
- # Checks to see if a column exists. See SchemaStatements#column_exists?
478
+ # Checks to see if a column exists.
479
+ #
480
+ # t.string(:name) unless t.column_exists?(:name, :string)
481
+ #
482
+ # See {connection.column_exists?}[rdoc-ref:SchemaStatements#column_exists?]
434
483
  def column_exists?(column_name, type = nil, options = {})
435
484
  @base.column_exists?(name, column_name, type, options)
436
485
  end
437
486
 
438
487
  # Adds a new index to the table. +column_name+ can be a single Symbol, or
439
- # an Array of Symbols. See SchemaStatements#add_index
488
+ # an Array of Symbols.
440
489
  #
441
- # ====== Creating a simple index
442
490
  # t.index(:name)
443
- # ====== Creating a unique index
444
491
  # t.index([:branch_id, :party_id], unique: true)
445
- # ====== Creating a named index
446
492
  # t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party')
493
+ #
494
+ # See {connection.add_index}[rdoc-ref:SchemaStatements#add_index] for details of the options you can use.
447
495
  def index(column_name, options = {})
448
496
  @base.add_index(name, column_name, options)
449
497
  end
450
498
 
451
- # Checks to see if an index exists. See SchemaStatements#index_exists?
499
+ # Checks to see if an index exists.
500
+ #
501
+ # unless t.index_exists?(:branch_id)
502
+ # t.index(:branch_id)
503
+ # end
504
+ #
505
+ # See {connection.index_exists?}[rdoc-ref:SchemaStatements#index_exists?]
452
506
  def index_exists?(column_name, options = {})
453
507
  @base.index_exists?(name, column_name, options)
454
508
  end
@@ -456,52 +510,59 @@ module ActiveRecord
456
510
  # Renames the given index on the table.
457
511
  #
458
512
  # t.rename_index(:user_id, :account_id)
513
+ #
514
+ # See {connection.rename_index}[rdoc-ref:SchemaStatements#rename_index]
459
515
  def rename_index(index_name, new_index_name)
460
516
  @base.rename_index(name, index_name, new_index_name)
461
517
  end
462
518
 
463
- # Adds timestamps (+created_at+ and +updated_at+) columns to the table. See SchemaStatements#add_timestamps
519
+ # Adds timestamps (+created_at+ and +updated_at+) columns to the table.
520
+ #
521
+ # t.timestamps(null: false)
464
522
  #
465
- # t.timestamps null: false
523
+ # See {connection.add_timestamps}[rdoc-ref:SchemaStatements#add_timestamps]
466
524
  def timestamps(options = {})
467
525
  @base.add_timestamps(name, options)
468
526
  end
469
527
 
470
528
  # Changes the column's definition according to the new options.
471
- # See TableDefinition#column for details of the options you can use.
472
529
  #
473
530
  # t.change(:name, :string, limit: 80)
474
531
  # t.change(:description, :text)
532
+ #
533
+ # See TableDefinition#column for details of the options you can use.
475
534
  def change(column_name, type, options = {})
476
535
  @base.change_column(name, column_name, type, options)
477
536
  end
478
537
 
479
- # Sets a new default value for a column. See SchemaStatements#change_column_default
538
+ # Sets a new default value for a column.
480
539
  #
481
540
  # t.change_default(:qualification, 'new')
482
541
  # t.change_default(:authorized, 1)
483
- def change_default(column_name, default)
484
- @base.change_column_default(name, column_name, default)
542
+ # t.change_default(:status, from: nil, to: "draft")
543
+ #
544
+ # See {connection.change_column_default}[rdoc-ref:SchemaStatements#change_column_default]
545
+ def change_default(column_name, default_or_changes)
546
+ @base.change_column_default(name, column_name, default_or_changes)
485
547
  end
486
548
 
487
549
  # Removes the column(s) from the table definition.
488
550
  #
489
551
  # t.remove(:qualification)
490
552
  # t.remove(:qualification, :experience)
553
+ #
554
+ # See {connection.remove_columns}[rdoc-ref:SchemaStatements#remove_columns]
491
555
  def remove(*column_names)
492
556
  @base.remove_columns(name, *column_names)
493
557
  end
494
558
 
495
559
  # Removes the given index from the table.
496
560
  #
497
- # ====== Remove the index_table_name_on_column in the table_name table
498
- # t.remove_index :column
499
- # ====== Remove the index named index_table_name_on_branch_id in the table_name table
500
- # t.remove_index column: :branch_id
501
- # ====== Remove the index named index_table_name_on_branch_id_and_party_id in the table_name table
502
- # t.remove_index column: [:branch_id, :party_id]
503
- # ====== Remove the index named by_branch_party in the table_name table
504
- # t.remove_index name: :by_branch_party
561
+ # t.remove_index(:branch_id)
562
+ # t.remove_index(column: [:branch_id, :party_id])
563
+ # t.remove_index(name: :by_branch_party)
564
+ #
565
+ # See {connection.remove_index}[rdoc-ref:SchemaStatements#remove_index]
505
566
  def remove_index(options = {})
506
567
  @base.remove_index(name, options)
507
568
  end
@@ -509,6 +570,8 @@ module ActiveRecord
509
570
  # Removes the timestamp columns (+created_at+ and +updated_at+) from the table.
510
571
  #
511
572
  # t.remove_timestamps
573
+ #
574
+ # See {connection.remove_timestamps}[rdoc-ref:SchemaStatements#remove_timestamps]
512
575
  def remove_timestamps(options = {})
513
576
  @base.remove_timestamps(name, options)
514
577
  end
@@ -516,19 +579,18 @@ module ActiveRecord
516
579
  # Renames a column.
517
580
  #
518
581
  # t.rename(:description, :name)
582
+ #
583
+ # See {connection.rename_column}[rdoc-ref:SchemaStatements#rename_column]
519
584
  def rename(column_name, new_column_name)
520
585
  @base.rename_column(name, column_name, new_column_name)
521
586
  end
522
587
 
523
- # Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
524
- # <tt>references</tt> and <tt>belongs_to</tt> are acceptable. The reference column will be an +integer+
525
- # by default, the <tt>:type</tt> option can be used to specify a different type.
588
+ # Adds a reference.
526
589
  #
527
590
  # t.references(:user)
528
- # t.references(:user, type: "string")
529
- # t.belongs_to(:supplier, polymorphic: true)
591
+ # t.belongs_to(:supplier, foreign_key: true)
530
592
  #
531
- # See SchemaStatements#add_reference
593
+ # See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
532
594
  def references(*args)
533
595
  options = args.extract_options!
534
596
  args.each do |ref_name|
@@ -538,12 +600,11 @@ module ActiveRecord
538
600
  alias :belongs_to :references
539
601
 
540
602
  # Removes a reference. Optionally removes a +type+ column.
541
- # <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
542
603
  #
543
604
  # t.remove_references(:user)
544
605
  # t.remove_belongs_to(:supplier, polymorphic: true)
545
606
  #
546
- # See SchemaStatements#remove_reference
607
+ # See {connection.remove_reference}[rdoc-ref:SchemaStatements#remove_reference]
547
608
  def remove_references(*args)
548
609
  options = args.extract_options!
549
610
  args.each do |ref_name|
@@ -552,23 +613,23 @@ module ActiveRecord
552
613
  end
553
614
  alias :remove_belongs_to :remove_references
554
615
 
555
- # Adds a column or columns of a specified type
616
+ # Adds a foreign key.
556
617
  #
557
- # t.string(:goat)
558
- # t.string(:goat, :sheep)
559
- [:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type|
560
- define_method column_type do |*args|
561
- options = args.extract_options!
562
- args.each do |column_name|
563
- @base.add_column(name, column_name, column_type, options)
564
- end
565
- end
618
+ # t.foreign_key(:authors)
619
+ #
620
+ # See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
621
+ def foreign_key(*args) # :nodoc:
622
+ @base.add_foreign_key(name, *args)
566
623
  end
567
624
 
568
- private
569
- def native
570
- @base.native_database_types
571
- end
625
+ # Checks to see if a foreign key exists.
626
+ #
627
+ # t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
628
+ #
629
+ # See {connection.foreign_key_exists?}[rdoc-ref:SchemaStatements#foreign_key_exists?]
630
+ def foreign_key_exists?(*args) # :nodoc:
631
+ @base.foreign_key_exists?(name, *args)
632
+ end
572
633
  end
573
634
  end
574
635
  end