activerecord 5.0.0 → 5.0.7.2
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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +431 -2
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/association_relation.rb +4 -1
- data/lib/active_record/associations/association.rb +11 -1
- data/lib/active_record/associations/association_scope.rb +1 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +4 -2
- data/lib/active_record/associations/builder/singular_association.rb +10 -1
- data/lib/active_record/associations/collection_association.rb +56 -48
- data/lib/active_record/associations/collection_proxy.rb +38 -20
- data/lib/active_record/associations/has_many_association.rb +1 -7
- data/lib/active_record/associations/has_many_through_association.rb +2 -4
- data/lib/active_record/associations/join_dependency/join_association.rb +6 -11
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/join_dependency.rb +10 -4
- data/lib/active_record/associations/preloader/association.rb +24 -37
- data/lib/active_record/associations/preloader/collection_association.rb +0 -1
- data/lib/active_record/associations/preloader/singular_association.rb +0 -1
- data/lib/active_record/associations/preloader/through_association.rb +10 -4
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +38 -17
- data/lib/active_record/attribute.rb +3 -3
- data/lib/active_record/attribute_methods/primary_key.rb +14 -1
- data/lib/active_record/attribute_methods/read.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -2
- data/lib/active_record/attribute_methods.rb +3 -7
- data/lib/active_record/attribute_set/builder.rb +37 -13
- data/lib/active_record/attribute_set.rb +2 -0
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +15 -11
- data/lib/active_record/base.rb +1 -1
- data/lib/active_record/collection_cache_key.rb +16 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +41 -33
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +37 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +11 -14
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +68 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +36 -12
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +63 -60
- data/lib/active_record/connection_adapters/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +8 -25
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +2 -6
- data/lib/active_record/connection_adapters/postgresql/column.rb +28 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +12 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +32 -3
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +18 -8
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +25 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +4 -4
- data/lib/active_record/core.rb +6 -4
- data/lib/active_record/enum.rb +8 -5
- data/lib/active_record/explain.rb +20 -9
- data/lib/active_record/fixtures.rb +5 -5
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/integration.rb +13 -10
- data/lib/active_record/log_subscriber.rb +19 -17
- data/lib/active_record/migration.rb +35 -14
- data/lib/active_record/model_schema.rb +161 -52
- data/lib/active_record/no_touching.rb +4 -0
- data/lib/active_record/persistence.rb +41 -20
- data/lib/active_record/query_cache.rb +15 -17
- data/lib/active_record/querying.rb +3 -3
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +9 -21
- data/lib/active_record/reflection.rb +20 -0
- data/lib/active_record/relation/batches.rb +10 -10
- data/lib/active_record/relation/calculations.rb +16 -12
- data/lib/active_record/relation/delegation.rb +2 -1
- data/lib/active_record/relation/finder_methods.rb +13 -11
- data/lib/active_record/relation/query_methods.rb +3 -3
- data/lib/active_record/relation.rb +12 -5
- data/lib/active_record/result.rb +7 -1
- data/lib/active_record/sanitization.rb +11 -1
- data/lib/active_record/schema_dumper.rb +10 -17
- data/lib/active_record/scoping/default.rb +5 -1
- data/lib/active_record/scoping/named.rb +18 -6
- data/lib/active_record/scoping.rb +4 -3
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/table_metadata.rb +4 -3
- data/lib/active_record/tasks/database_tasks.rb +14 -11
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/touch_later.rb +6 -1
- data/lib/active_record/transactions.rb +1 -1
- data/lib/active_record/type/internal/abstract_json.rb +5 -1
- data/lib/active_record/validations/uniqueness.rb +3 -4
- data/lib/active_record.rb +3 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
- data/lib/rails/generators/active_record/migration.rb +8 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- metadata +7 -8
@@ -230,7 +230,7 @@ module ActiveRecord
|
|
230
230
|
type_metadata = fetch_type_metadata(column_name, type, oid, fmod)
|
231
231
|
default_value = extract_value_from_default(default)
|
232
232
|
default_function = extract_default_function(default_value, default)
|
233
|
-
new_column(column_name, default_value, type_metadata, !notnull, table_name, default_function, collation, comment: comment.presence)
|
233
|
+
new_column(column_name, default_value, type_metadata, !notnull, table_name, default_function, collation, comment: comment.presence, max_identifier_length: max_identifier_length)
|
234
234
|
end
|
235
235
|
end
|
236
236
|
|
@@ -238,6 +238,12 @@ module ActiveRecord
|
|
238
238
|
PostgreSQLColumn.new(*args)
|
239
239
|
end
|
240
240
|
|
241
|
+
def table_options(table_name) # :nodoc:
|
242
|
+
if comment = table_comment(table_name)
|
243
|
+
{ comment: comment }
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
241
247
|
# Returns a comment stored in database for given table
|
242
248
|
def table_comment(table_name) # :nodoc:
|
243
249
|
name = Utils.extract_schema_qualified_name(table_name.to_s)
|
@@ -369,9 +375,17 @@ module ActiveRecord
|
|
369
375
|
|
370
376
|
if pk && sequence
|
371
377
|
quoted_sequence = quote_table_name(sequence)
|
378
|
+
max_pk = select_value("select MAX(#{quote_column_name pk}) from #{quote_table_name(table)}")
|
379
|
+
if max_pk.nil?
|
380
|
+
if postgresql_version >= 100000
|
381
|
+
minvalue = select_value("SELECT seqmin from pg_sequence where seqrelid = '#{quoted_sequence}'::regclass")
|
382
|
+
else
|
383
|
+
minvalue = select_value("SELECT min_value FROM #{quoted_sequence}")
|
384
|
+
end
|
385
|
+
end
|
372
386
|
|
373
|
-
select_value(<<-end_sql,
|
374
|
-
SELECT setval('#{quoted_sequence}',
|
387
|
+
select_value(<<-end_sql, "SCHEMA")
|
388
|
+
SELECT setval('#{quoted_sequence}', #{max_pk ? max_pk : minvalue}, #{max_pk ? true : false})
|
375
389
|
end_sql
|
376
390
|
end
|
377
391
|
end
|
@@ -579,7 +593,7 @@ module ActiveRecord
|
|
579
593
|
end
|
580
594
|
|
581
595
|
def foreign_keys(table_name)
|
582
|
-
fk_info = select_all
|
596
|
+
fk_info = select_all(<<-SQL.strip_heredoc, 'SCHEMA')
|
583
597
|
SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
|
584
598
|
FROM pg_constraint c
|
585
599
|
JOIN pg_class t1 ON c.conrelid = t1.oid
|
@@ -615,10 +629,6 @@ module ActiveRecord
|
|
615
629
|
end
|
616
630
|
end
|
617
631
|
|
618
|
-
def index_name_length
|
619
|
-
63
|
620
|
-
end
|
621
|
-
|
622
632
|
# Maps logical Rails types to PostgreSQL-specific data types.
|
623
633
|
def type_to_sql(type, limit = nil, precision = nil, scale = nil, array = nil)
|
624
634
|
sql = case type.to_s
|
@@ -19,9 +19,9 @@ module ActiveRecord
|
|
19
19
|
|
20
20
|
def quoted
|
21
21
|
if schema
|
22
|
-
|
22
|
+
PG::Connection.quote_ident(schema) << SEPARATOR << PG::Connection.quote_ident(identifier)
|
23
23
|
else
|
24
|
-
|
24
|
+
PG::Connection.quote_ident(identifier)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# Make sure we're using pg high enough for type casts and Ruby 2.2+ compatibility
|
2
|
-
gem
|
2
|
+
gem "pg", ">= 0.18", "< 2.0"
|
3
3
|
require 'pg'
|
4
4
|
|
5
5
|
require "active_record/connection_adapters/abstract_adapter"
|
@@ -28,11 +28,11 @@ module ActiveRecord
|
|
28
28
|
conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
|
29
29
|
conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
|
30
30
|
|
31
|
-
# Forward only valid config params to
|
32
|
-
valid_conn_param_keys =
|
31
|
+
# Forward only valid config params to PG::Connection.connect.
|
32
|
+
valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
|
33
33
|
conn_params.slice!(*valid_conn_param_keys)
|
34
34
|
|
35
|
-
# The postgres drivers don't allow the creation of an unconnected
|
35
|
+
# The postgres drivers don't allow the creation of an unconnected PG::Connection object,
|
36
36
|
# so just pass a nil connection object for the time being.
|
37
37
|
ConnectionAdapters::PostgreSQLAdapter.new(nil, logger, conn_params, config)
|
38
38
|
end
|
@@ -198,8 +198,8 @@ module ActiveRecord
|
|
198
198
|
end
|
199
199
|
|
200
200
|
def connection_active?
|
201
|
-
@connection.status ==
|
202
|
-
rescue
|
201
|
+
@connection.status == PG::CONNECTION_OK
|
202
|
+
rescue PG::Error
|
203
203
|
false
|
204
204
|
end
|
205
205
|
end
|
@@ -212,7 +212,7 @@ module ActiveRecord
|
|
212
212
|
|
213
213
|
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
|
214
214
|
@local_tz = nil
|
215
|
-
@
|
215
|
+
@max_identifier_length = nil
|
216
216
|
|
217
217
|
connect
|
218
218
|
add_pg_encoders
|
@@ -244,7 +244,7 @@ module ActiveRecord
|
|
244
244
|
def active?
|
245
245
|
@connection.query 'SELECT 1'
|
246
246
|
true
|
247
|
-
rescue
|
247
|
+
rescue PG::Error
|
248
248
|
false
|
249
249
|
end
|
250
250
|
|
@@ -358,9 +358,11 @@ module ActiveRecord
|
|
358
358
|
end
|
359
359
|
|
360
360
|
# Returns the configured supported identifier length supported by PostgreSQL
|
361
|
-
def
|
362
|
-
@
|
361
|
+
def max_identifier_length
|
362
|
+
@max_identifier_length ||= query('SHOW max_identifier_length', 'SCHEMA')[0][0].to_i
|
363
363
|
end
|
364
|
+
alias table_alias_length max_identifier_length
|
365
|
+
alias index_name_length max_identifier_length
|
364
366
|
|
365
367
|
# Set the authorized user for this session
|
366
368
|
def session_auth=(user)
|
@@ -410,7 +412,7 @@ module ActiveRecord
|
|
410
412
|
def translate_exception(exception, message)
|
411
413
|
return exception unless exception.respond_to?(:result)
|
412
414
|
|
413
|
-
case exception.result.try(:error_field,
|
415
|
+
case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
|
414
416
|
when UNIQUE_VIOLATION
|
415
417
|
RecordNotUnique.new(message)
|
416
418
|
when FOREIGN_KEY_VIOLATION
|
@@ -594,15 +596,15 @@ module ActiveRecord
|
|
594
596
|
end
|
595
597
|
|
596
598
|
def exec_no_cache(sql, name, binds)
|
597
|
-
type_casted_binds = binds
|
598
|
-
log(sql, name, binds) { @connection.async_exec(sql, type_casted_binds) }
|
599
|
+
type_casted_binds = type_casted_binds(binds)
|
600
|
+
log(sql, name, binds, type_casted_binds) { @connection.async_exec(sql, type_casted_binds) }
|
599
601
|
end
|
600
602
|
|
601
603
|
def exec_cache(sql, name, binds)
|
602
604
|
stmt_key = prepare_statement(sql)
|
603
|
-
type_casted_binds = binds
|
605
|
+
type_casted_binds = type_casted_binds(binds)
|
604
606
|
|
605
|
-
log(sql, name, binds, stmt_key) do
|
607
|
+
log(sql, name, binds, type_casted_binds, stmt_key) do
|
606
608
|
@connection.exec_prepared(stmt_key, type_casted_binds)
|
607
609
|
end
|
608
610
|
rescue ActiveRecord::StatementInvalid => e
|
@@ -631,7 +633,7 @@ module ActiveRecord
|
|
631
633
|
CACHED_PLAN_HEURISTIC = 'cached plan must not change result type'.freeze
|
632
634
|
def is_cached_plan_failure?(e)
|
633
635
|
pgerror = e.cause
|
634
|
-
code = pgerror.result.result_error_field(
|
636
|
+
code = pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE)
|
635
637
|
code == FEATURE_NOT_SUPPORTED && pgerror.message.include?(CACHED_PLAN_HEURISTIC)
|
636
638
|
rescue
|
637
639
|
false
|
@@ -668,7 +670,7 @@ module ActiveRecord
|
|
668
670
|
# Connects to a PostgreSQL server and sets up the adapter depending on the
|
669
671
|
# connected server's characteristics.
|
670
672
|
def connect
|
671
|
-
@connection =
|
673
|
+
@connection = PG.connect(@connection_parameters)
|
672
674
|
configure_connection
|
673
675
|
rescue ::PG::Error => error
|
674
676
|
if error.message.include?("does not exist")
|
@@ -764,11 +766,15 @@ module ActiveRecord
|
|
764
766
|
@case_insensitive_cache[column.sql_type] ||= begin
|
765
767
|
sql = <<-end_sql
|
766
768
|
SELECT exists(
|
769
|
+
SELECT * FROM pg_proc
|
770
|
+
WHERE proname = 'lower'
|
771
|
+
AND proargtypes = ARRAY[#{quote column.sql_type}::regtype]::oidvector
|
772
|
+
) OR exists(
|
767
773
|
SELECT * FROM pg_proc
|
768
774
|
INNER JOIN pg_cast
|
769
|
-
ON casttarget::
|
775
|
+
ON ARRAY[casttarget]::oidvector = proargtypes
|
770
776
|
WHERE proname = 'lower'
|
771
|
-
AND castsource =
|
777
|
+
AND castsource = #{quote column.sql_type}::regtype
|
772
778
|
)
|
773
779
|
end_sql
|
774
780
|
execute_and_clear(sql, "SCHEMA", []) do |result|
|
@@ -188,9 +188,9 @@ module ActiveRecord
|
|
188
188
|
end
|
189
189
|
|
190
190
|
def exec_query(sql, name = nil, binds = [], prepare: false)
|
191
|
-
type_casted_binds = binds
|
191
|
+
type_casted_binds = type_casted_binds(binds)
|
192
192
|
|
193
|
-
log(sql, name, binds) do
|
193
|
+
log(sql, name, binds, type_casted_binds) do
|
194
194
|
# Don't cache statements if they are not prepared
|
195
195
|
unless prepare
|
196
196
|
stmt = @connection.prepare(sql)
|
@@ -203,7 +203,6 @@ module ActiveRecord
|
|
203
203
|
ensure
|
204
204
|
stmt.close
|
205
205
|
end
|
206
|
-
stmt = records
|
207
206
|
else
|
208
207
|
cache = @statements[sql] ||= {
|
209
208
|
:stmt => @connection.prepare(sql)
|
@@ -212,9 +211,10 @@ module ActiveRecord
|
|
212
211
|
cols = cache[:cols] ||= stmt.columns
|
213
212
|
stmt.reset!
|
214
213
|
stmt.bind_params(type_casted_binds)
|
214
|
+
records = stmt.to_a
|
215
215
|
end
|
216
216
|
|
217
|
-
ActiveRecord::Result.new(cols,
|
217
|
+
ActiveRecord::Result.new(cols, records)
|
218
218
|
end
|
219
219
|
end
|
220
220
|
|
data/lib/active_record/core.rb
CHANGED
@@ -180,12 +180,12 @@ module ActiveRecord
|
|
180
180
|
end
|
181
181
|
|
182
182
|
def find_by(*args) # :nodoc:
|
183
|
-
return super if scope_attributes? ||
|
183
|
+
return super if scope_attributes? || reflect_on_all_aggregations.any?
|
184
184
|
|
185
185
|
hash = args.first
|
186
186
|
|
187
|
-
return super if hash.values.any? { |v|
|
188
|
-
v.nil? || Array === v || Hash === v || Relation === v
|
187
|
+
return super if !(Hash === hash) || hash.values.any? { |v|
|
188
|
+
v.nil? || Array === v || Hash === v || Relation === v || Base === v
|
189
189
|
}
|
190
190
|
|
191
191
|
# We can't cache Post.find_by(author: david) ...yet
|
@@ -310,8 +310,8 @@ module ActiveRecord
|
|
310
310
|
# # Instantiates a single new object
|
311
311
|
# User.new(first_name: 'Jamie')
|
312
312
|
def initialize(attributes = nil)
|
313
|
-
@attributes = self.class._default_attributes.deep_dup
|
314
313
|
self.class.define_attribute_methods
|
314
|
+
@attributes = self.class._default_attributes.deep_dup
|
315
315
|
|
316
316
|
init_internals
|
317
317
|
initialize_internals_callback
|
@@ -346,6 +346,8 @@ module ActiveRecord
|
|
346
346
|
|
347
347
|
self.class.define_attribute_methods
|
348
348
|
|
349
|
+
yield self if block_given?
|
350
|
+
|
349
351
|
_run_find_callbacks
|
350
352
|
_run_initialize_callbacks
|
351
353
|
|
data/lib/active_record/enum.rb
CHANGED
@@ -105,6 +105,8 @@ module ActiveRecord
|
|
105
105
|
end
|
106
106
|
|
107
107
|
class EnumType < Type::Value # :nodoc:
|
108
|
+
delegate :type, to: :subtype
|
109
|
+
|
108
110
|
def initialize(name, mapping, subtype)
|
109
111
|
@name = name
|
110
112
|
@mapping = mapping
|
@@ -159,8 +161,9 @@ module ActiveRecord
|
|
159
161
|
detect_enum_conflict!(name, name)
|
160
162
|
detect_enum_conflict!(name, "#{name}=")
|
161
163
|
|
162
|
-
|
163
|
-
|
164
|
+
attr = attribute_alias?(name) ? attribute_alias(name) : name
|
165
|
+
decorate_attribute_type(attr, :enum) do |subtype|
|
166
|
+
EnumType.new(attr, enum_values, subtype)
|
164
167
|
end
|
165
168
|
|
166
169
|
_enum_methods_module.module_eval do
|
@@ -182,15 +185,15 @@ module ActiveRecord
|
|
182
185
|
|
183
186
|
# def active?() status == 0 end
|
184
187
|
klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
|
185
|
-
define_method("#{value_method_name}?") { self[
|
188
|
+
define_method("#{value_method_name}?") { self[attr] == value.to_s }
|
186
189
|
|
187
190
|
# def active!() update! status: :active end
|
188
191
|
klass.send(:detect_enum_conflict!, name, "#{value_method_name}!")
|
189
|
-
define_method("#{value_method_name}!") { update!
|
192
|
+
define_method("#{value_method_name}!") { update!(attr => value) }
|
190
193
|
|
191
194
|
# scope :active, -> { where status: 0 }
|
192
195
|
klass.send(:detect_enum_conflict!, name, value_method_name, true)
|
193
|
-
klass.scope value_method_name, -> { where(
|
196
|
+
klass.scope value_method_name, -> { where(attr => value) }
|
194
197
|
end
|
195
198
|
end
|
196
199
|
defined_enums[name.to_s] = enum_values
|
@@ -16,15 +16,14 @@ module ActiveRecord
|
|
16
16
|
# Makes the adapter execute EXPLAIN for the tuples of queries and bindings.
|
17
17
|
# Returns a formatted string ready to be logged.
|
18
18
|
def exec_explain(queries) # :nodoc:
|
19
|
-
str = queries.map do |sql,
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end.join("\n")
|
19
|
+
str = queries.map do |sql, binds|
|
20
|
+
msg = "EXPLAIN for: #{sql}"
|
21
|
+
unless binds.empty?
|
22
|
+
msg << " "
|
23
|
+
msg << binds.map { |attr| render_bind(attr) }.inspect
|
24
|
+
end
|
25
|
+
msg << "\n"
|
26
|
+
msg << connection.explain(sql, binds)
|
28
27
|
end.join("\n")
|
29
28
|
|
30
29
|
# Overriding inspect to be more human readable, especially in the console.
|
@@ -34,5 +33,17 @@ module ActiveRecord
|
|
34
33
|
|
35
34
|
str
|
36
35
|
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def render_bind(attr)
|
40
|
+
value = if attr.type.binary? && attr.value
|
41
|
+
"<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
|
42
|
+
else
|
43
|
+
connection.type_cast(attr.value_for_database)
|
44
|
+
end
|
45
|
+
|
46
|
+
[attr.name, value]
|
47
|
+
end
|
37
48
|
end
|
38
49
|
end
|
@@ -535,17 +535,17 @@ module ActiveRecord
|
|
535
535
|
|
536
536
|
update_all_loaded_fixtures fixtures_map
|
537
537
|
|
538
|
-
connection.transaction(:
|
539
|
-
deleted_tables = Set.new
|
538
|
+
connection.transaction(requires_new: true) do
|
539
|
+
deleted_tables = Hash.new { |h, k| h[k] = Set.new }
|
540
540
|
fixture_sets.each do |fs|
|
541
541
|
conn = fs.model_class.respond_to?(:connection) ? fs.model_class.connection : connection
|
542
542
|
table_rows = fs.table_rows
|
543
543
|
|
544
544
|
table_rows.each_key do |table|
|
545
|
-
unless deleted_tables.include? table
|
546
|
-
conn.delete "DELETE FROM #{conn.quote_table_name(table)}",
|
545
|
+
unless deleted_tables[conn].include? table
|
546
|
+
conn.delete "DELETE FROM #{conn.quote_table_name(table)}", "Fixture Delete"
|
547
547
|
end
|
548
|
-
deleted_tables << table
|
548
|
+
deleted_tables[conn] << table
|
549
549
|
end
|
550
550
|
|
551
551
|
table_rows.each do |fixture_set_name, rows|
|
@@ -53,18 +53,21 @@ module ActiveRecord
|
|
53
53
|
#
|
54
54
|
# Person.find(5).cache_key(:updated_at, :last_reviewed_at)
|
55
55
|
def cache_key(*timestamp_names)
|
56
|
-
|
57
|
-
when new_record?
|
56
|
+
if new_record?
|
58
57
|
"#{model_name.cache_key}/new"
|
59
|
-
when timestamp_names.any?
|
60
|
-
timestamp = max_updated_column_timestamp(timestamp_names)
|
61
|
-
timestamp = timestamp.utc.to_s(cache_timestamp_format)
|
62
|
-
"#{model_name.cache_key}/#{id}-#{timestamp}"
|
63
|
-
when timestamp = max_updated_column_timestamp
|
64
|
-
timestamp = timestamp.utc.to_s(cache_timestamp_format)
|
65
|
-
"#{model_name.cache_key}/#{id}-#{timestamp}"
|
66
58
|
else
|
67
|
-
|
59
|
+
timestamp = if timestamp_names.any?
|
60
|
+
max_updated_column_timestamp(timestamp_names)
|
61
|
+
else
|
62
|
+
max_updated_column_timestamp
|
63
|
+
end
|
64
|
+
|
65
|
+
if timestamp
|
66
|
+
timestamp = timestamp.utc.to_s(cache_timestamp_format)
|
67
|
+
"#{model_name.cache_key}/#{id}-#{timestamp}"
|
68
|
+
else
|
69
|
+
"#{model_name.cache_key}/#{id}"
|
70
|
+
end
|
68
71
|
end
|
69
72
|
end
|
70
73
|
|
@@ -20,24 +20,9 @@ module ActiveRecord
|
|
20
20
|
@odd = false
|
21
21
|
end
|
22
22
|
|
23
|
-
def render_bind(attribute)
|
24
|
-
value = if attribute.type.binary? && attribute.value
|
25
|
-
if attribute.value.is_a?(Hash)
|
26
|
-
"<#{attribute.value_for_database.to_s.bytesize} bytes of binary data>"
|
27
|
-
else
|
28
|
-
"<#{attribute.value.bytesize} bytes of binary data>"
|
29
|
-
end
|
30
|
-
else
|
31
|
-
attribute.value_for_database
|
32
|
-
end
|
33
|
-
|
34
|
-
[attribute.name, value]
|
35
|
-
end
|
36
|
-
|
37
23
|
def sql(event)
|
38
|
-
return unless logger.debug?
|
39
|
-
|
40
24
|
self.class.runtime += event.duration
|
25
|
+
return unless logger.debug?
|
41
26
|
|
42
27
|
payload = event.payload
|
43
28
|
|
@@ -48,7 +33,10 @@ module ActiveRecord
|
|
48
33
|
binds = nil
|
49
34
|
|
50
35
|
unless (payload[:binds] || []).empty?
|
51
|
-
|
36
|
+
casted_params = type_casted_binds(payload[:type_casted_binds])
|
37
|
+
binds = " " + payload[:binds].zip(casted_params).map { |attr, value|
|
38
|
+
render_bind(attr, value)
|
39
|
+
}.inspect
|
52
40
|
end
|
53
41
|
|
54
42
|
name = colorize_payload_name(name, payload[:name])
|
@@ -59,6 +47,20 @@ module ActiveRecord
|
|
59
47
|
|
60
48
|
private
|
61
49
|
|
50
|
+
def type_casted_binds(casted_binds)
|
51
|
+
casted_binds.respond_to?(:call) ? casted_binds.call : casted_binds
|
52
|
+
end
|
53
|
+
|
54
|
+
def render_bind(attr, value)
|
55
|
+
if attr.is_a?(Array)
|
56
|
+
attr = attr.first
|
57
|
+
elsif attr.type.binary? && attr.value
|
58
|
+
value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
|
59
|
+
end
|
60
|
+
|
61
|
+
[attr && attr.name, value]
|
62
|
+
end
|
63
|
+
|
62
64
|
def colorize_payload_name(name, payload_name)
|
63
65
|
if payload_name.blank? || payload_name == "SQL" # SQL vs Model Load/Exists
|
64
66
|
color(name, MAGENTA, true)
|
@@ -1,5 +1,6 @@
|
|
1
|
+
require "set"
|
2
|
+
require "zlib"
|
1
3
|
require "active_support/core_ext/module/attribute_accessors"
|
2
|
-
require 'set'
|
3
4
|
|
4
5
|
module ActiveRecord
|
5
6
|
class MigrationError < ActiveRecordError#:nodoc:
|
@@ -126,9 +127,9 @@ module ActiveRecord
|
|
126
127
|
class PendingMigrationError < MigrationError#:nodoc:
|
127
128
|
def initialize(message = nil)
|
128
129
|
if !message && defined?(Rails.env)
|
129
|
-
super("Migrations are pending. To resolve this issue, run:\n\n
|
130
|
+
super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate RAILS_ENV=#{::Rails.env}")
|
130
131
|
elsif !message
|
131
|
-
super("Migrations are pending. To resolve this issue, run:\n\n
|
132
|
+
super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate")
|
132
133
|
else
|
133
134
|
super
|
134
135
|
end
|
@@ -145,7 +146,7 @@ module ActiveRecord
|
|
145
146
|
|
146
147
|
class NoEnvironmentInSchemaError < MigrationError #:nodoc:
|
147
148
|
def initialize
|
148
|
-
msg = "Environment data not found in the schema. To resolve this issue, run: \n\n
|
149
|
+
msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
|
149
150
|
if defined?(Rails.env)
|
150
151
|
super("#{msg} RAILS_ENV=#{::Rails.env}")
|
151
152
|
else
|
@@ -168,7 +169,7 @@ module ActiveRecord
|
|
168
169
|
msg = "You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
|
169
170
|
msg << "You are running in `#{ current }` environment. "
|
170
171
|
msg << "If you are sure you want to continue, first set the environment using:\n\n"
|
171
|
-
msg << "
|
172
|
+
msg << " bin/rails db:environment:set"
|
172
173
|
if defined?(Rails.env)
|
173
174
|
super("#{msg} RAILS_ENV=#{::Rails.env}\n\n")
|
174
175
|
else
|
@@ -1056,10 +1057,6 @@ module ActiveRecord
|
|
1056
1057
|
Array(@migrations_paths)
|
1057
1058
|
end
|
1058
1059
|
|
1059
|
-
def match_to_migration_filename?(filename) # :nodoc:
|
1060
|
-
File.basename(filename) =~ Migration::MigrationFilenameRegexp
|
1061
|
-
end
|
1062
|
-
|
1063
1060
|
def parse_migration_filename(filename) # :nodoc:
|
1064
1061
|
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
|
1065
1062
|
end
|
@@ -1067,9 +1064,7 @@ module ActiveRecord
|
|
1067
1064
|
def migrations(paths)
|
1068
1065
|
paths = Array(paths)
|
1069
1066
|
|
1070
|
-
|
1071
|
-
|
1072
|
-
migrations = files.map do |file|
|
1067
|
+
migrations = migration_files(paths).map do |file|
|
1073
1068
|
version, name, scope = parse_migration_filename(file)
|
1074
1069
|
raise IllegalMigrationNameError.new(file) unless version
|
1075
1070
|
version = version.to_i
|
@@ -1081,6 +1076,30 @@ module ActiveRecord
|
|
1081
1076
|
migrations.sort_by(&:version)
|
1082
1077
|
end
|
1083
1078
|
|
1079
|
+
def migrations_status(paths)
|
1080
|
+
paths = Array(paths)
|
1081
|
+
|
1082
|
+
db_list = ActiveRecord::SchemaMigration.normalized_versions
|
1083
|
+
|
1084
|
+
file_list = migration_files(paths).map do |file|
|
1085
|
+
version, name, scope = parse_migration_filename(file)
|
1086
|
+
raise IllegalMigrationNameError.new(file) unless version
|
1087
|
+
version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
|
1088
|
+
status = db_list.delete(version) ? "up" : "down"
|
1089
|
+
[status, version, (name + scope).humanize]
|
1090
|
+
end.compact
|
1091
|
+
|
1092
|
+
db_list.map! do |version|
|
1093
|
+
["up", version, "********** NO FILE **********"]
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
(db_list + file_list).sort_by { |_, version, _| version }
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
def migration_files(paths)
|
1100
|
+
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
|
1101
|
+
end
|
1102
|
+
|
1084
1103
|
private
|
1085
1104
|
|
1086
1105
|
def move(direction, migrations_paths, steps)
|
@@ -1168,9 +1187,10 @@ module ActiveRecord
|
|
1168
1187
|
def run_without_lock
|
1169
1188
|
migration = migrations.detect { |m| m.version == @target_version }
|
1170
1189
|
raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
|
1171
|
-
execute_migration_in_transaction(migration, @direction)
|
1190
|
+
result = execute_migration_in_transaction(migration, @direction)
|
1172
1191
|
|
1173
1192
|
record_environment
|
1193
|
+
result
|
1174
1194
|
end
|
1175
1195
|
|
1176
1196
|
# Used for running multiple migrations up to or down to a certain value.
|
@@ -1179,11 +1199,12 @@ module ActiveRecord
|
|
1179
1199
|
raise UnknownMigrationVersionError.new(@target_version)
|
1180
1200
|
end
|
1181
1201
|
|
1182
|
-
runnable.each do |migration|
|
1202
|
+
result = runnable.each do |migration|
|
1183
1203
|
execute_migration_in_transaction(migration, @direction)
|
1184
1204
|
end
|
1185
1205
|
|
1186
1206
|
record_environment
|
1207
|
+
result
|
1187
1208
|
end
|
1188
1209
|
|
1189
1210
|
# Stores the current environment in the database.
|