activerecord 5.0.7 → 5.1.7

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.

Potentially problematic release.


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

Files changed (219) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +657 -2080
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/examples/performance.rb +28 -28
  6. data/examples/simple.rb +3 -3
  7. data/lib/active_record/aggregations.rb +244 -244
  8. data/lib/active_record/association_relation.rb +5 -5
  9. data/lib/active_record/associations/alias_tracker.rb +10 -11
  10. data/lib/active_record/associations/association.rb +23 -5
  11. data/lib/active_record/associations/association_scope.rb +95 -81
  12. data/lib/active_record/associations/belongs_to_association.rb +7 -4
  13. data/lib/active_record/associations/builder/belongs_to.rb +30 -16
  14. data/lib/active_record/associations/builder/collection_association.rb +1 -2
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
  16. data/lib/active_record/associations/collection_association.rb +36 -205
  17. data/lib/active_record/associations/collection_proxy.rb +132 -63
  18. data/lib/active_record/associations/has_many_association.rb +10 -19
  19. data/lib/active_record/associations/has_many_through_association.rb +12 -4
  20. data/lib/active_record/associations/has_one_association.rb +24 -28
  21. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  22. data/lib/active_record/associations/join_dependency/join_association.rb +4 -28
  23. data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
  24. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  25. data/lib/active_record/associations/join_dependency.rb +121 -118
  26. data/lib/active_record/associations/preloader/association.rb +64 -64
  27. data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
  28. data/lib/active_record/associations/preloader/collection_association.rb +6 -6
  29. data/lib/active_record/associations/preloader/has_many.rb +0 -2
  30. data/lib/active_record/associations/preloader/singular_association.rb +6 -8
  31. data/lib/active_record/associations/preloader/through_association.rb +41 -41
  32. data/lib/active_record/associations/preloader.rb +94 -94
  33. data/lib/active_record/associations/singular_association.rb +8 -25
  34. data/lib/active_record/associations/through_association.rb +2 -5
  35. data/lib/active_record/associations.rb +1591 -1562
  36. data/lib/active_record/attribute/user_provided_default.rb +4 -2
  37. data/lib/active_record/attribute.rb +98 -71
  38. data/lib/active_record/attribute_assignment.rb +61 -61
  39. data/lib/active_record/attribute_decorators.rb +35 -13
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
  41. data/lib/active_record/attribute_methods/dirty.rb +229 -46
  42. data/lib/active_record/attribute_methods/primary_key.rb +74 -73
  43. data/lib/active_record/attribute_methods/read.rb +39 -35
  44. data/lib/active_record/attribute_methods/serialization.rb +7 -7
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
  46. data/lib/active_record/attribute_methods/write.rb +30 -33
  47. data/lib/active_record/attribute_methods.rb +56 -65
  48. data/lib/active_record/attribute_mutation_tracker.rb +63 -11
  49. data/lib/active_record/attribute_set/builder.rb +27 -33
  50. data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
  51. data/lib/active_record/attribute_set.rb +9 -6
  52. data/lib/active_record/attributes.rb +22 -22
  53. data/lib/active_record/autosave_association.rb +18 -13
  54. data/lib/active_record/base.rb +24 -22
  55. data/lib/active_record/callbacks.rb +56 -14
  56. data/lib/active_record/coders/yaml_column.rb +9 -11
  57. data/lib/active_record/collection_cache_key.rb +3 -4
  58. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +330 -284
  59. data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
  60. data/lib/active_record/connection_adapters/abstract/database_statements.rb +39 -37
  61. data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -27
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -51
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +10 -20
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +74 -79
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +120 -100
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +49 -43
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -135
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +404 -424
  70. data/lib/active_record/connection_adapters/column.rb +26 -4
  71. data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
  72. data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -49
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -28
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +7 -6
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +23 -27
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +32 -53
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +19 -9
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
  90. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
  91. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +0 -10
  92. data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
  93. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
  96. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +32 -30
  97. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
  99. data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
  100. data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -35
  101. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
  102. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
  103. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
  104. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +182 -222
  105. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +6 -4
  106. data/lib/active_record/connection_adapters/postgresql/utils.rb +7 -5
  107. data/lib/active_record/connection_adapters/postgresql_adapter.rb +198 -167
  108. data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
  109. data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
  110. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
  111. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -19
  112. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
  113. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
  114. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
  115. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +32 -0
  116. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +184 -167
  117. data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
  118. data/lib/active_record/connection_handling.rb +14 -26
  119. data/lib/active_record/core.rb +109 -93
  120. data/lib/active_record/counter_cache.rb +60 -13
  121. data/lib/active_record/define_callbacks.rb +20 -0
  122. data/lib/active_record/dynamic_matchers.rb +80 -79
  123. data/lib/active_record/enum.rb +8 -6
  124. data/lib/active_record/errors.rb +64 -15
  125. data/lib/active_record/explain.rb +1 -2
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +7 -4
  128. data/lib/active_record/fixture_set/file.rb +11 -8
  129. data/lib/active_record/fixtures.rb +66 -53
  130. data/lib/active_record/gem_version.rb +1 -1
  131. data/lib/active_record/inheritance.rb +93 -79
  132. data/lib/active_record/integration.rb +7 -7
  133. data/lib/active_record/internal_metadata.rb +3 -16
  134. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  135. data/lib/active_record/locking/optimistic.rb +69 -74
  136. data/lib/active_record/locking/pessimistic.rb +10 -1
  137. data/lib/active_record/log_subscriber.rb +23 -28
  138. data/lib/active_record/migration/command_recorder.rb +94 -94
  139. data/lib/active_record/migration/compatibility.rb +100 -47
  140. data/lib/active_record/migration/join_table.rb +6 -6
  141. data/lib/active_record/migration.rb +153 -155
  142. data/lib/active_record/model_schema.rb +94 -107
  143. data/lib/active_record/nested_attributes.rb +200 -199
  144. data/lib/active_record/null_relation.rb +11 -34
  145. data/lib/active_record/persistence.rb +65 -50
  146. data/lib/active_record/query_cache.rb +2 -6
  147. data/lib/active_record/querying.rb +3 -4
  148. data/lib/active_record/railtie.rb +16 -17
  149. data/lib/active_record/railties/controller_runtime.rb +6 -2
  150. data/lib/active_record/railties/databases.rake +105 -133
  151. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  152. data/lib/active_record/readonly_attributes.rb +2 -2
  153. data/lib/active_record/reflection.rb +154 -108
  154. data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
  155. data/lib/active_record/relation/batches.rb +80 -51
  156. data/lib/active_record/relation/calculations.rb +169 -162
  157. data/lib/active_record/relation/delegation.rb +32 -31
  158. data/lib/active_record/relation/finder_methods.rb +197 -231
  159. data/lib/active_record/relation/merger.rb +58 -62
  160. data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
  161. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
  162. data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
  163. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
  164. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
  165. data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
  166. data/lib/active_record/relation/predicate_builder.rb +92 -89
  167. data/lib/active_record/relation/query_attribute.rb +1 -1
  168. data/lib/active_record/relation/query_methods.rb +255 -293
  169. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  170. data/lib/active_record/relation/spawn_methods.rb +4 -5
  171. data/lib/active_record/relation/where_clause.rb +80 -65
  172. data/lib/active_record/relation/where_clause_factory.rb +47 -8
  173. data/lib/active_record/relation.rb +93 -119
  174. data/lib/active_record/result.rb +41 -32
  175. data/lib/active_record/runtime_registry.rb +3 -3
  176. data/lib/active_record/sanitization.rb +176 -192
  177. data/lib/active_record/schema.rb +3 -3
  178. data/lib/active_record/schema_dumper.rb +15 -38
  179. data/lib/active_record/schema_migration.rb +8 -4
  180. data/lib/active_record/scoping/default.rb +90 -90
  181. data/lib/active_record/scoping/named.rb +11 -11
  182. data/lib/active_record/scoping.rb +6 -6
  183. data/lib/active_record/secure_token.rb +2 -2
  184. data/lib/active_record/statement_cache.rb +13 -15
  185. data/lib/active_record/store.rb +31 -32
  186. data/lib/active_record/suppressor.rb +2 -1
  187. data/lib/active_record/table_metadata.rb +9 -5
  188. data/lib/active_record/tasks/database_tasks.rb +65 -55
  189. data/lib/active_record/tasks/mysql_database_tasks.rb +76 -73
  190. data/lib/active_record/tasks/postgresql_database_tasks.rb +72 -47
  191. data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
  192. data/lib/active_record/timestamp.rb +46 -25
  193. data/lib/active_record/touch_later.rb +1 -2
  194. data/lib/active_record/transactions.rb +97 -109
  195. data/lib/active_record/type/adapter_specific_registry.rb +46 -42
  196. data/lib/active_record/type/decimal_without_scale.rb +13 -0
  197. data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
  198. data/lib/active_record/type/internal/abstract_json.rb +4 -0
  199. data/lib/active_record/type/serialized.rb +14 -8
  200. data/lib/active_record/type/text.rb +9 -0
  201. data/lib/active_record/type/time.rb +0 -1
  202. data/lib/active_record/type/type_map.rb +11 -15
  203. data/lib/active_record/type/unsigned_integer.rb +15 -0
  204. data/lib/active_record/type.rb +17 -13
  205. data/lib/active_record/type_caster/connection.rb +8 -6
  206. data/lib/active_record/type_caster/map.rb +3 -1
  207. data/lib/active_record/type_caster.rb +2 -2
  208. data/lib/active_record/validations/associated.rb +1 -1
  209. data/lib/active_record/validations/presence.rb +2 -2
  210. data/lib/active_record/validations/uniqueness.rb +8 -39
  211. data/lib/active_record/validations.rb +4 -4
  212. data/lib/active_record/version.rb +1 -1
  213. data/lib/active_record.rb +20 -20
  214. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
  215. data/lib/rails/generators/active_record/migration.rb +1 -1
  216. data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
  217. data/lib/rails/generators/active_record.rb +4 -4
  218. metadata +24 -13
  219. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -1,5 +1,3 @@
1
- require 'active_support/core_ext/string/filters'
2
-
3
1
  module ActiveRecord
4
2
  module Tasks # :nodoc:
5
3
  class DatabaseAlreadyExists < StandardError; end # :nodoc:
@@ -35,15 +33,25 @@ module ActiveRecord
35
33
  #
36
34
  # DatabaseTasks.create_current('production')
37
35
  module DatabaseTasks
36
+ ##
37
+ # :singleton-method:
38
+ # Extra flags passed to database CLI tool (mysqldump/pg_dump) when calling db:structure:dump
39
+ mattr_accessor :structure_dump_flags, instance_accessor: false
40
+
41
+ ##
42
+ # :singleton-method:
43
+ # Extra flags passed to database CLI tool when calling db:structure:load
44
+ mattr_accessor :structure_load_flags, instance_accessor: false
45
+
38
46
  extend self
39
47
 
40
48
  attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader
41
49
  attr_accessor :database_configuration
42
50
 
43
- LOCAL_HOSTS = ['127.0.0.1', 'localhost']
51
+ LOCAL_HOSTS = ["127.0.0.1", "localhost"]
44
52
 
45
53
  def check_protected_environments!
46
- unless ENV['DISABLE_DATABASE_ENVIRONMENT_CHECK']
54
+ unless ENV["DISABLE_DATABASE_ENVIRONMENT_CHECK"]
47
55
  current = ActiveRecord::Migrator.current_environment
48
56
  stored = ActiveRecord::Migrator.last_stored_environment
49
57
 
@@ -72,15 +80,15 @@ module ActiveRecord
72
80
  end
73
81
 
74
82
  def migrations_paths
75
- @migrations_paths ||= Rails.application.paths['db/migrate'].to_a
83
+ @migrations_paths ||= Rails.application.paths["db/migrate"].to_a
76
84
  end
77
85
 
78
86
  def fixtures_path
79
- @fixtures_path ||= if ENV['FIXTURES_PATH']
80
- File.join(root, ENV['FIXTURES_PATH'])
81
- else
82
- File.join(root, 'test', 'fixtures')
83
- end
87
+ @fixtures_path ||= if ENV["FIXTURES_PATH"]
88
+ File.join(root, ENV["FIXTURES_PATH"])
89
+ else
90
+ File.join(root, "test", "fixtures")
91
+ end
84
92
  end
85
93
 
86
94
  def root
@@ -96,7 +104,7 @@ module ActiveRecord
96
104
  end
97
105
 
98
106
  def current_config(options = {})
99
- options.reverse_merge! :env => env
107
+ options.reverse_merge! env: env
100
108
  if options.has_key?(:config)
101
109
  @current_config = options[:config]
102
110
  else
@@ -106,13 +114,13 @@ module ActiveRecord
106
114
 
107
115
  def create(*arguments)
108
116
  configuration = arguments.first
109
- class_for_adapter(configuration['adapter']).new(*arguments).create
117
+ class_for_adapter(configuration["adapter"]).new(*arguments).create
110
118
  $stdout.puts "Created database '#{configuration['database']}'"
111
119
  rescue DatabaseAlreadyExists
112
120
  $stderr.puts "Database '#{configuration['database']}' already exists"
113
121
  rescue Exception => error
114
122
  $stderr.puts error
115
- $stderr.puts "Couldn't create database for #{configuration.inspect}"
123
+ $stderr.puts "Couldn't create '#{configuration['database']}' database. Please check your configuration."
116
124
  raise
117
125
  end
118
126
 
@@ -120,7 +128,7 @@ module ActiveRecord
120
128
  old_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(ActiveRecord::Base.connection_specification_name)
121
129
  each_local_configuration { |configuration| create configuration }
122
130
  if old_pool
123
- ActiveRecord::Base.connection_handler.establish_connection(old_pool.spec)
131
+ ActiveRecord::Base.connection_handler.establish_connection(old_pool.spec.to_hash)
124
132
  end
125
133
  end
126
134
 
@@ -133,7 +141,7 @@ module ActiveRecord
133
141
 
134
142
  def drop(*arguments)
135
143
  configuration = arguments.first
136
- class_for_adapter(configuration['adapter']).new(*arguments).drop
144
+ class_for_adapter(configuration["adapter"]).new(*arguments).drop
137
145
  $stdout.puts "Dropped database '#{configuration['database']}'"
138
146
  rescue ActiveRecord::NoDatabaseError
139
147
  $stderr.puts "Database '#{configuration['database']}' does not exist"
@@ -158,7 +166,7 @@ module ActiveRecord
158
166
 
159
167
  verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
160
168
  version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
161
- scope = ENV['SCOPE']
169
+ scope = ENV["SCOPE"]
162
170
  verbose_was, Migration.verbose = Migration.verbose, verbose
163
171
  Migrator.migrate(migrations_paths, version) do |migration|
164
172
  scope.blank? || scope == migration.scope
@@ -174,7 +182,7 @@ module ActiveRecord
174
182
 
175
183
  def charset(*arguments)
176
184
  configuration = arguments.first
177
- class_for_adapter(configuration['adapter']).new(*arguments).charset
185
+ class_for_adapter(configuration["adapter"]).new(*arguments).charset
178
186
  end
179
187
 
180
188
  def collation_current(environment = env)
@@ -183,11 +191,11 @@ module ActiveRecord
183
191
 
184
192
  def collation(*arguments)
185
193
  configuration = arguments.first
186
- class_for_adapter(configuration['adapter']).new(*arguments).collation
194
+ class_for_adapter(configuration["adapter"]).new(*arguments).collation
187
195
  end
188
196
 
189
197
  def purge(configuration)
190
- class_for_adapter(configuration['adapter']).new(configuration).purge
198
+ class_for_adapter(configuration["adapter"]).new(configuration).purge
191
199
  end
192
200
 
193
201
  def purge_all
@@ -206,13 +214,13 @@ module ActiveRecord
206
214
  def structure_dump(*arguments)
207
215
  configuration = arguments.first
208
216
  filename = arguments.delete_at 1
209
- class_for_adapter(configuration['adapter']).new(*arguments).structure_dump(filename)
217
+ class_for_adapter(configuration["adapter"]).new(*arguments).structure_dump(filename, structure_dump_flags)
210
218
  end
211
219
 
212
220
  def structure_load(*arguments)
213
221
  configuration = arguments.first
214
222
  filename = arguments.delete_at 1
215
- class_for_adapter(configuration['adapter']).new(*arguments).structure_load(filename)
223
+ class_for_adapter(configuration["adapter"]).new(*arguments).structure_load(filename, structure_load_flags)
216
224
  end
217
225
 
218
226
  def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = env) # :nodoc:
@@ -233,14 +241,6 @@ module ActiveRecord
233
241
  ActiveRecord::InternalMetadata[:environment] = environment
234
242
  end
235
243
 
236
- def load_schema_for(*args)
237
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
238
- This method was renamed to `#load_schema` and will be removed in the future.
239
- Use `#load_schema` instead.
240
- MSG
241
- load_schema(*args)
242
- end
243
-
244
244
  def schema_file(format = ActiveRecord::Base.schema_format)
245
245
  case format
246
246
  when :ruby
@@ -269,48 +269,58 @@ module ActiveRecord
269
269
  if seed_loader
270
270
  seed_loader.load_seed
271
271
  else
272
- raise "You tried to load seed data, but no seed loader is specified. Please specify seed " +
273
- "loader with ActiveRecord::Tasks::DatabaseTasks.seed_loader = your_seed_loader\n" +
272
+ raise "You tried to load seed data, but no seed loader is specified. Please specify seed " \
273
+ "loader with ActiveRecord::Tasks::DatabaseTasks.seed_loader = your_seed_loader\n" \
274
274
  "Seed loader should respond to load_seed method"
275
275
  end
276
276
  end
277
277
 
278
+ # Dumps the schema cache in YAML format for the connection into the file
279
+ #
280
+ # ==== Examples:
281
+ # ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(ActiveRecord::Base.connection, "tmp/schema_dump.yaml")
282
+ def dump_schema_cache(conn, filename)
283
+ conn.schema_cache.clear!
284
+ conn.data_sources.each { |table| conn.schema_cache.add(table) }
285
+ open(filename, "wb") { |f| f.write(YAML.dump(conn.schema_cache)) }
286
+ end
287
+
278
288
  private
279
289
 
280
- def class_for_adapter(adapter)
281
- key = @tasks.keys.detect { |pattern| adapter[pattern] }
282
- unless key
283
- raise DatabaseNotSupported, "Rake tasks not supported by '#{adapter}' adapter"
290
+ def class_for_adapter(adapter)
291
+ key = @tasks.keys.detect { |pattern| adapter[pattern] }
292
+ unless key
293
+ raise DatabaseNotSupported, "Rake tasks not supported by '#{adapter}' adapter"
294
+ end
295
+ @tasks[key]
284
296
  end
285
- @tasks[key]
286
- end
287
297
 
288
- def each_current_configuration(environment)
289
- environments = [environment]
290
- environments << 'test' if environment == 'development'
298
+ def each_current_configuration(environment)
299
+ environments = [environment]
300
+ environments << "test" if environment == "development"
291
301
 
292
- ActiveRecord::Base.configurations.slice(*environments).each do |configuration_environment, configuration|
293
- next unless configuration["database"]
302
+ ActiveRecord::Base.configurations.slice(*environments).each do |configuration_environment, configuration|
303
+ next unless configuration["database"]
294
304
 
295
- yield configuration, configuration_environment
305
+ yield configuration, configuration_environment
306
+ end
296
307
  end
297
- end
298
308
 
299
- def each_local_configuration
300
- ActiveRecord::Base.configurations.each_value do |configuration|
301
- next unless configuration['database']
309
+ def each_local_configuration
310
+ ActiveRecord::Base.configurations.each_value do |configuration|
311
+ next unless configuration["database"]
302
312
 
303
- if local_database?(configuration)
304
- yield configuration
305
- else
306
- $stderr.puts "This task only modifies local databases. #{configuration['database']} is on a remote host."
313
+ if local_database?(configuration)
314
+ yield configuration
315
+ else
316
+ $stderr.puts "This task only modifies local databases. #{configuration['database']} is on a remote host."
317
+ end
307
318
  end
308
319
  end
309
- end
310
320
 
311
- def local_database?(configuration)
312
- configuration['host'].blank? || LOCAL_HOSTS.include?(configuration['host'])
313
- end
321
+ def local_database?(configuration)
322
+ configuration["host"].blank? || LOCAL_HOSTS.include?(configuration["host"])
323
+ end
314
324
  end
315
325
  end
316
326
  end
@@ -11,10 +11,10 @@ module ActiveRecord
11
11
 
12
12
  def create
13
13
  establish_connection configuration_without_database
14
- connection.create_database configuration['database'], creation_options
14
+ connection.create_database configuration["database"], creation_options
15
15
  establish_connection configuration
16
16
  rescue ActiveRecord::StatementInvalid => error
17
- if /database exists/ === error.message
17
+ if error.message.include?("database exists")
18
18
  raise DatabaseAlreadyExists
19
19
  else
20
20
  raise
@@ -23,26 +23,26 @@ module ActiveRecord
23
23
  if error.respond_to?(:errno) && error.errno == ACCESS_DENIED_ERROR
24
24
  $stdout.print error.message
25
25
  establish_connection root_configuration_without_database
26
- connection.create_database configuration['database'], creation_options
27
- if configuration['username'] != 'root'
28
- connection.execute grant_statement.gsub(/\s+/, ' ').strip
26
+ connection.create_database configuration["database"], creation_options
27
+ if configuration["username"] != "root"
28
+ connection.execute grant_statement.gsub(/\s+/, " ").strip
29
29
  end
30
30
  establish_connection configuration
31
31
  else
32
32
  $stderr.puts error.inspect
33
33
  $stderr.puts "Couldn't create database for #{configuration.inspect}, #{creation_options.inspect}"
34
- $stderr.puts "(If you set the charset manually, make sure you have a matching collation)" if configuration['encoding']
34
+ $stderr.puts "(If you set the charset manually, make sure you have a matching collation)" if configuration["encoding"]
35
35
  end
36
36
  end
37
37
 
38
38
  def drop
39
39
  establish_connection configuration
40
- connection.drop_database configuration['database']
40
+ connection.drop_database configuration["database"]
41
41
  end
42
42
 
43
43
  def purge
44
44
  establish_connection configuration
45
- connection.recreate_database configuration['database'], creation_options
45
+ connection.recreate_database configuration["database"], creation_options
46
46
  end
47
47
 
48
48
  def charset
@@ -53,99 +53,102 @@ module ActiveRecord
53
53
  connection.collation
54
54
  end
55
55
 
56
- def structure_dump(filename)
56
+ def structure_dump(filename, extra_flags)
57
57
  args = prepare_command_options
58
58
  args.concat(["--result-file", "#{filename}"])
59
59
  args.concat(["--no-data"])
60
60
  args.concat(["--routines"])
61
+ args.concat(["--skip-comments"])
61
62
  args.concat(["#{configuration['database']}"])
63
+ args.unshift(*extra_flags) if extra_flags
62
64
 
63
- run_cmd('mysqldump', args, 'dumping')
65
+ run_cmd("mysqldump", args, "dumping")
64
66
  end
65
67
 
66
- def structure_load(filename)
68
+ def structure_load(filename, extra_flags)
67
69
  args = prepare_command_options
68
- args.concat(['--execute', %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}])
70
+ args.concat(["--execute", %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}])
69
71
  args.concat(["--database", "#{configuration['database']}"])
72
+ args.unshift(*extra_flags) if extra_flags
70
73
 
71
- run_cmd('mysql', args, 'loading')
74
+ run_cmd("mysql", args, "loading")
72
75
  end
73
76
 
74
77
  private
75
78
 
76
- def configuration
77
- @configuration
78
- end
79
+ def configuration
80
+ @configuration
81
+ end
79
82
 
80
- def configuration_without_database
81
- configuration.merge('database' => nil)
82
- end
83
+ def configuration_without_database
84
+ configuration.merge("database" => nil)
85
+ end
83
86
 
84
- def creation_options
85
- Hash.new.tap do |options|
86
- options[:charset] = configuration['encoding'] if configuration.include? 'encoding'
87
- options[:collation] = configuration['collation'] if configuration.include? 'collation'
87
+ def creation_options
88
+ Hash.new.tap do |options|
89
+ options[:charset] = configuration["encoding"] if configuration.include? "encoding"
90
+ options[:collation] = configuration["collation"] if configuration.include? "collation"
91
+ end
88
92
  end
89
- end
90
93
 
91
- def error_class
92
- if configuration['adapter'] =~ /jdbc/
93
- require 'active_record/railties/jdbcmysql_error'
94
- ArJdbcMySQL::Error
95
- elsif defined?(Mysql2)
96
- Mysql2::Error
97
- else
98
- StandardError
94
+ def error_class
95
+ if configuration["adapter"].include?("jdbc")
96
+ require "active_record/railties/jdbcmysql_error"
97
+ ArJdbcMySQL::Error
98
+ elsif defined?(Mysql2)
99
+ Mysql2::Error
100
+ else
101
+ StandardError
102
+ end
99
103
  end
100
- end
101
104
 
102
- def grant_statement
103
- <<-SQL
104
- GRANT ALL PRIVILEGES ON #{configuration['database']}.*
105
+ def grant_statement
106
+ <<-SQL
107
+ GRANT ALL PRIVILEGES ON `#{configuration['database']}`.*
105
108
  TO '#{configuration['username']}'@'localhost'
106
109
  IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION;
107
- SQL
108
- end
110
+ SQL
111
+ end
109
112
 
110
- def root_configuration_without_database
111
- configuration_without_database.merge(
112
- 'username' => 'root',
113
- 'password' => root_password
114
- )
115
- end
113
+ def root_configuration_without_database
114
+ configuration_without_database.merge(
115
+ "username" => "root",
116
+ "password" => root_password
117
+ )
118
+ end
116
119
 
117
- def root_password
118
- $stdout.print "Please provide the root password for your MySQL installation\n>"
119
- $stdin.gets.strip
120
- end
120
+ def root_password
121
+ $stdout.print "Please provide the root password for your MySQL installation\n>"
122
+ $stdin.gets.strip
123
+ end
121
124
 
122
- def prepare_command_options
123
- args = {
124
- 'host' => '--host',
125
- 'port' => '--port',
126
- 'socket' => '--socket',
127
- 'username' => '--user',
128
- 'password' => '--password',
129
- 'encoding' => '--default-character-set',
130
- 'sslca' => '--ssl-ca',
131
- 'sslcert' => '--ssl-cert',
132
- 'sslcapath' => '--ssl-capath',
133
- 'sslcipher' => '--ssl-cipher',
134
- 'sslkey' => '--ssl-key'
135
- }.map { |opt, arg| "#{arg}=#{configuration[opt]}" if configuration[opt] }.compact
136
-
137
- args
138
- end
125
+ def prepare_command_options
126
+ args = {
127
+ "host" => "--host",
128
+ "port" => "--port",
129
+ "socket" => "--socket",
130
+ "username" => "--user",
131
+ "password" => "--password",
132
+ "encoding" => "--default-character-set",
133
+ "sslca" => "--ssl-ca",
134
+ "sslcert" => "--ssl-cert",
135
+ "sslcapath" => "--ssl-capath",
136
+ "sslcipher" => "--ssl-cipher",
137
+ "sslkey" => "--ssl-key"
138
+ }.map { |opt, arg| "#{arg}=#{configuration[opt]}" if configuration[opt] }.compact
139
+
140
+ args
141
+ end
139
142
 
140
- def run_cmd(cmd, args, action)
141
- fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
142
- end
143
+ def run_cmd(cmd, args, action)
144
+ fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
145
+ end
143
146
 
144
- def run_cmd_error(cmd, args, action)
145
- msg = "failed to execute: `#{cmd}`\n"
146
- msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
147
- msg
148
- end
147
+ def run_cmd_error(cmd, args, action)
148
+ msg = "failed to execute: `#{cmd}`\n"
149
+ msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
150
+ msg
151
+ end
149
152
  end
150
153
  end
151
154
  end
@@ -1,7 +1,11 @@
1
+ require "tempfile"
2
+
1
3
  module ActiveRecord
2
4
  module Tasks # :nodoc:
3
5
  class PostgreSQLDatabaseTasks # :nodoc:
4
- DEFAULT_ENCODING = ENV['CHARSET'] || 'utf8'
6
+ DEFAULT_ENCODING = ENV["CHARSET"] || "utf8"
7
+ ON_ERROR_STOP_1 = "ON_ERROR_STOP=1".freeze
8
+ SQL_COMMENT_BEGIN = "--".freeze
5
9
 
6
10
  delegate :connection, :establish_connection, :clear_active_connections!,
7
11
  to: ActiveRecord::Base
@@ -12,8 +16,8 @@ module ActiveRecord
12
16
 
13
17
  def create(master_established = false)
14
18
  establish_master_connection unless master_established
15
- connection.create_database configuration['database'],
16
- configuration.merge('encoding' => encoding)
19
+ connection.create_database configuration["database"],
20
+ configuration.merge("encoding" => encoding)
17
21
  establish_connection configuration
18
22
  rescue ActiveRecord::StatementInvalid => error
19
23
  if error.cause.is_a?(PG::DuplicateDatabase)
@@ -25,7 +29,7 @@ module ActiveRecord
25
29
 
26
30
  def drop
27
31
  establish_master_connection
28
- connection.drop_database configuration['database']
32
+ connection.drop_database configuration["database"]
29
33
  end
30
34
 
31
35
  def charset
@@ -42,69 +46,90 @@ module ActiveRecord
42
46
  create true
43
47
  end
44
48
 
45
- def structure_dump(filename)
49
+ def structure_dump(filename, extra_flags)
46
50
  set_psql_env
47
51
 
48
- search_path = case ActiveRecord::Base.dump_schemas
49
- when :schema_search_path
50
- configuration['schema_search_path']
51
- when :all
52
- nil
53
- when String
54
- ActiveRecord::Base.dump_schemas
55
- end
52
+ search_path = \
53
+ case ActiveRecord::Base.dump_schemas
54
+ when :schema_search_path
55
+ configuration["schema_search_path"]
56
+ when :all
57
+ nil
58
+ when String
59
+ ActiveRecord::Base.dump_schemas
60
+ end
56
61
 
57
- args = ['-s', '-x', '-O', '-f', filename]
62
+ args = ["-s", "-x", "-O", "-f", filename]
63
+ args.concat(Array(extra_flags)) if extra_flags
58
64
  unless search_path.blank?
59
- args += search_path.split(',').map do |part|
65
+ args += search_path.split(",").map do |part|
60
66
  "--schema=#{part.strip}"
61
67
  end
62
68
  end
63
- args << configuration['database']
64
- run_cmd('pg_dump', args, 'dumping')
69
+ args << configuration["database"]
70
+ run_cmd("pg_dump", args, "dumping")
71
+ remove_sql_header_comments(filename)
65
72
  File.open(filename, "a") { |f| f << "SET search_path TO #{connection.schema_search_path};\n\n" }
66
73
  end
67
74
 
68
- def structure_load(filename)
75
+ def structure_load(filename, extra_flags)
69
76
  set_psql_env
70
- args = [ '-q', '-f', filename, configuration['database'] ]
71
- run_cmd('psql', args, 'loading' )
77
+ args = ["-v", ON_ERROR_STOP_1, "-q", "-f", filename]
78
+ args.concat(Array(extra_flags)) if extra_flags
79
+ args << configuration["database"]
80
+ run_cmd("psql", args, "loading")
72
81
  end
73
82
 
74
83
  private
75
84
 
76
- def configuration
77
- @configuration
78
- end
85
+ def configuration
86
+ @configuration
87
+ end
79
88
 
80
- def encoding
81
- configuration['encoding'] || DEFAULT_ENCODING
82
- end
89
+ def encoding
90
+ configuration["encoding"] || DEFAULT_ENCODING
91
+ end
83
92
 
84
- def establish_master_connection
85
- establish_connection configuration.merge(
86
- 'database' => 'postgres',
87
- 'schema_search_path' => 'public'
88
- )
89
- end
93
+ def establish_master_connection
94
+ establish_connection configuration.merge(
95
+ "database" => "postgres",
96
+ "schema_search_path" => "public"
97
+ )
98
+ end
90
99
 
91
- def set_psql_env
92
- ENV['PGHOST'] = configuration['host'] if configuration['host']
93
- ENV['PGPORT'] = configuration['port'].to_s if configuration['port']
94
- ENV['PGPASSWORD'] = configuration['password'].to_s if configuration['password']
95
- ENV['PGUSER'] = configuration['username'].to_s if configuration['username']
96
- end
100
+ def set_psql_env
101
+ ENV["PGHOST"] = configuration["host"] if configuration["host"]
102
+ ENV["PGPORT"] = configuration["port"].to_s if configuration["port"]
103
+ ENV["PGPASSWORD"] = configuration["password"].to_s if configuration["password"]
104
+ ENV["PGUSER"] = configuration["username"].to_s if configuration["username"]
105
+ end
97
106
 
98
- def run_cmd(cmd, args, action)
99
- fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
100
- end
107
+ def run_cmd(cmd, args, action)
108
+ fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
109
+ end
101
110
 
102
- def run_cmd_error(cmd, args, action)
103
- msg = "failed to execute:\n"
104
- msg << "#{cmd} #{args.join(' ')}\n\n"
105
- msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
106
- msg
107
- end
111
+ def run_cmd_error(cmd, args, action)
112
+ msg = "failed to execute:\n"
113
+ msg << "#{cmd} #{args.join(' ')}\n\n"
114
+ msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
115
+ msg
116
+ end
117
+
118
+ def remove_sql_header_comments(filename)
119
+ removing_comments = true
120
+ tempfile = Tempfile.open("uncommented_structure.sql")
121
+ begin
122
+ File.foreach(filename) do |line|
123
+ unless removing_comments && (line.start_with?(SQL_COMMENT_BEGIN) || line.blank?)
124
+ tempfile << line
125
+ removing_comments = false
126
+ end
127
+ end
128
+ ensure
129
+ tempfile.close
130
+ end
131
+ FileUtils.mv(tempfile.path, filename)
132
+ end
108
133
  end
109
134
  end
110
135
  end