activerecord 5.2.8 → 6.0.0.beta1
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 +4 -4
- data/CHANGELOG.md +299 -788
- data/MIT-LICENSE +3 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations/association.rb +35 -19
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/belongs_to.rb +14 -50
- data/lib/active_record/associations/builder/collection_association.rb +3 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/collection_association.rb +11 -25
- data/lib/active_record/associations/collection_proxy.rb +32 -6
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +25 -18
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +11 -26
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/join_dependency.rb +15 -20
- data/lib/active_record/associations/preloader/association.rb +1 -2
- data/lib/active_record/associations/preloader.rb +32 -29
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/associations.rb +16 -12
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods/dirty.rb +64 -26
- data/lib/active_record/attribute_methods/primary_key.rb +8 -7
- data/lib/active_record/attribute_methods/read.rb +16 -48
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +15 -16
- data/lib/active_record/attribute_methods.rb +34 -56
- data/lib/active_record/autosave_association.rb +7 -21
- data/lib/active_record/base.rb +2 -2
- data/lib/active_record/callbacks.rb +3 -17
- data/lib/active_record/collection_cache_key.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +13 -36
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +25 -84
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +5 -11
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -11
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +0 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +41 -27
- data/lib/active_record/connection_adapters/abstract/transaction.rb +81 -52
- data/lib/active_record/connection_adapters/abstract_adapter.rb +95 -31
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +65 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +5 -9
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -7
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +65 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -4
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +16 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +11 -36
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +9 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +38 -20
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -56
- data/lib/active_record/connection_adapters/schema_cache.rb +5 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +14 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +95 -62
- data/lib/active_record/connection_handling.rb +132 -26
- data/lib/active_record/core.rb +76 -43
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +74 -0
- data/lib/active_record/database_configurations.rb +184 -0
- data/lib/active_record/enum.rb +22 -7
- data/lib/active_record/errors.rb +24 -21
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +140 -472
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +12 -2
- data/lib/active_record/integration.rb +56 -16
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +2 -2
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/migration/command_recorder.rb +35 -5
- data/lib/active_record/migration/compatibility.rb +34 -16
- data/lib/active_record/migration.rb +38 -37
- data/lib/active_record/model_schema.rb +30 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +18 -7
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +19 -11
- data/lib/active_record/railtie.rb +71 -42
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +94 -43
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +38 -28
- data/lib/active_record/relation/delegation.rb +4 -13
- data/lib/active_record/relation/finder_methods.rb +12 -25
- data/lib/active_record/relation/merger.rb +2 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- data/lib/active_record/relation/query_attribute.rb +15 -12
- data/lib/active_record/relation/query_methods.rb +29 -52
- data/lib/active_record/relation/where_clause.rb +4 -0
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/relation.rb +150 -69
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +2 -39
- data/lib/active_record/schema.rb +1 -10
- data/lib/active_record/schema_dumper.rb +12 -6
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping/default.rb +10 -3
- data/lib/active_record/scoping/named.rb +10 -14
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/statement_cache.rb +32 -5
- data/lib/active_record/store.rb +39 -8
- data/lib/active_record/table_metadata.rb +1 -4
- data/lib/active_record/tasks/database_tasks.rb +89 -23
- data/lib/active_record/tasks/mysql_database_tasks.rb +2 -4
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +38 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/transactions.rb +3 -22
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type_caster/connection.rb +1 -6
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/uniqueness.rb +13 -25
- data/lib/active_record.rb +2 -1
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +63 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values.rb +16 -0
- data/lib/arel/nodes/values_list.rb +24 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +67 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +199 -0
- data/lib/arel/visitors/dot.rb +292 -0
- data/lib/arel/visitors/ibm_db.rb +21 -0
- data/lib/arel/visitors/informix.rb +56 -0
- data/lib/arel/visitors/mssql.rb +143 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +67 -0
- data/lib/arel/visitors/postgresql.rb +116 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +913 -0
- data/lib/arel/visitors/visitor.rb +42 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +44 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- metadata +104 -26
@@ -0,0 +1,224 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module TestFixtures
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
def before_setup # :nodoc:
|
8
|
+
setup_fixtures
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def after_teardown # :nodoc:
|
13
|
+
super
|
14
|
+
teardown_fixtures
|
15
|
+
end
|
16
|
+
|
17
|
+
included do
|
18
|
+
class_attribute :fixture_path, instance_writer: false
|
19
|
+
class_attribute :fixture_table_names, default: []
|
20
|
+
class_attribute :fixture_class_names, default: {}
|
21
|
+
class_attribute :use_transactional_tests, default: true
|
22
|
+
class_attribute :use_instantiated_fixtures, default: false # true, false, or :no_instances
|
23
|
+
class_attribute :pre_loaded_fixtures, default: false
|
24
|
+
class_attribute :config, default: ActiveRecord::Base
|
25
|
+
class_attribute :lock_threads, default: true
|
26
|
+
end
|
27
|
+
|
28
|
+
module ClassMethods
|
29
|
+
# Sets the model class for a fixture when the class name cannot be inferred from the fixture name.
|
30
|
+
#
|
31
|
+
# Examples:
|
32
|
+
#
|
33
|
+
# set_fixture_class some_fixture: SomeModel,
|
34
|
+
# 'namespaced/fixture' => Another::Model
|
35
|
+
#
|
36
|
+
# The keys must be the fixture names, that coincide with the short paths to the fixture files.
|
37
|
+
def set_fixture_class(class_names = {})
|
38
|
+
self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys)
|
39
|
+
end
|
40
|
+
|
41
|
+
def fixtures(*fixture_set_names)
|
42
|
+
if fixture_set_names.first == :all
|
43
|
+
raise StandardError, "No fixture path found. Please set `#{self}.fixture_path`." if fixture_path.blank?
|
44
|
+
fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"].uniq
|
45
|
+
fixture_set_names.map! { |f| f[(fixture_path.to_s.size + 1)..-5] }
|
46
|
+
else
|
47
|
+
fixture_set_names = fixture_set_names.flatten.map(&:to_s)
|
48
|
+
end
|
49
|
+
|
50
|
+
self.fixture_table_names |= fixture_set_names
|
51
|
+
setup_fixture_accessors(fixture_set_names)
|
52
|
+
end
|
53
|
+
|
54
|
+
def setup_fixture_accessors(fixture_set_names = nil)
|
55
|
+
fixture_set_names = Array(fixture_set_names || fixture_table_names)
|
56
|
+
methods = Module.new do
|
57
|
+
fixture_set_names.each do |fs_name|
|
58
|
+
fs_name = fs_name.to_s
|
59
|
+
accessor_name = fs_name.tr("/", "_").to_sym
|
60
|
+
|
61
|
+
define_method(accessor_name) do |*fixture_names|
|
62
|
+
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
63
|
+
return_single_record = fixture_names.size == 1
|
64
|
+
fixture_names = @loaded_fixtures[fs_name].fixtures.keys if fixture_names.empty?
|
65
|
+
|
66
|
+
@fixture_cache[fs_name] ||= {}
|
67
|
+
|
68
|
+
instances = fixture_names.map do |f_name|
|
69
|
+
f_name = f_name.to_s if f_name.is_a?(Symbol)
|
70
|
+
@fixture_cache[fs_name].delete(f_name) if force_reload
|
71
|
+
|
72
|
+
if @loaded_fixtures[fs_name][f_name]
|
73
|
+
@fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
|
74
|
+
else
|
75
|
+
raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
return_single_record ? instances.first : instances
|
80
|
+
end
|
81
|
+
private accessor_name
|
82
|
+
end
|
83
|
+
end
|
84
|
+
include methods
|
85
|
+
end
|
86
|
+
|
87
|
+
def uses_transaction(*methods)
|
88
|
+
@uses_transaction = [] unless defined?(@uses_transaction)
|
89
|
+
@uses_transaction.concat methods.map(&:to_s)
|
90
|
+
end
|
91
|
+
|
92
|
+
def uses_transaction?(method)
|
93
|
+
@uses_transaction = [] unless defined?(@uses_transaction)
|
94
|
+
@uses_transaction.include?(method.to_s)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def run_in_transaction?
|
99
|
+
use_transactional_tests &&
|
100
|
+
!self.class.uses_transaction?(method_name)
|
101
|
+
end
|
102
|
+
|
103
|
+
def setup_fixtures(config = ActiveRecord::Base)
|
104
|
+
if pre_loaded_fixtures && !use_transactional_tests
|
105
|
+
raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
|
106
|
+
end
|
107
|
+
|
108
|
+
@fixture_cache = {}
|
109
|
+
@fixture_connections = []
|
110
|
+
@@already_loaded_fixtures ||= {}
|
111
|
+
@connection_subscriber = nil
|
112
|
+
|
113
|
+
# Load fixtures once and begin transaction.
|
114
|
+
if run_in_transaction?
|
115
|
+
if @@already_loaded_fixtures[self.class]
|
116
|
+
@loaded_fixtures = @@already_loaded_fixtures[self.class]
|
117
|
+
else
|
118
|
+
@loaded_fixtures = load_fixtures(config)
|
119
|
+
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
120
|
+
end
|
121
|
+
|
122
|
+
# Begin transactions for connections already established
|
123
|
+
@fixture_connections = enlist_fixture_connections
|
124
|
+
@fixture_connections.each do |connection|
|
125
|
+
connection.begin_transaction joinable: false
|
126
|
+
connection.pool.lock_thread = true if lock_threads
|
127
|
+
end
|
128
|
+
|
129
|
+
# When connections are established in the future, begin a transaction too
|
130
|
+
@connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
|
131
|
+
spec_name = payload[:spec_name] if payload.key?(:spec_name)
|
132
|
+
|
133
|
+
if spec_name
|
134
|
+
begin
|
135
|
+
connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name)
|
136
|
+
rescue ConnectionNotEstablished
|
137
|
+
connection = nil
|
138
|
+
end
|
139
|
+
|
140
|
+
if connection && !@fixture_connections.include?(connection)
|
141
|
+
connection.begin_transaction joinable: false
|
142
|
+
connection.pool.lock_thread = true if lock_threads
|
143
|
+
@fixture_connections << connection
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Load fixtures for every test.
|
149
|
+
else
|
150
|
+
ActiveRecord::FixtureSet.reset_cache
|
151
|
+
@@already_loaded_fixtures[self.class] = nil
|
152
|
+
@loaded_fixtures = load_fixtures(config)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Instantiate fixtures for every test if requested.
|
156
|
+
instantiate_fixtures if use_instantiated_fixtures
|
157
|
+
end
|
158
|
+
|
159
|
+
def teardown_fixtures
|
160
|
+
# Rollback changes if a transaction is active.
|
161
|
+
if run_in_transaction?
|
162
|
+
ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
|
163
|
+
@fixture_connections.each do |connection|
|
164
|
+
connection.rollback_transaction if connection.transaction_open?
|
165
|
+
connection.pool.lock_thread = false
|
166
|
+
end
|
167
|
+
@fixture_connections.clear
|
168
|
+
else
|
169
|
+
ActiveRecord::FixtureSet.reset_cache
|
170
|
+
end
|
171
|
+
|
172
|
+
ActiveRecord::Base.clear_active_connections!
|
173
|
+
end
|
174
|
+
|
175
|
+
def enlist_fixture_connections
|
176
|
+
setup_shared_connection_pool
|
177
|
+
|
178
|
+
ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
|
179
|
+
end
|
180
|
+
|
181
|
+
private
|
182
|
+
|
183
|
+
# Shares the writing connection pool with connections on
|
184
|
+
# other handlers.
|
185
|
+
#
|
186
|
+
# In an application with a primary and replica the test fixtures
|
187
|
+
# need to share a connection pool so that the reading connection
|
188
|
+
# can see data in the open transaction on the writing connection.
|
189
|
+
def setup_shared_connection_pool
|
190
|
+
writing_handler = ActiveRecord::Base.connection_handler
|
191
|
+
|
192
|
+
ActiveRecord::Base.connection_handlers.values.each do |handler|
|
193
|
+
if handler != writing_handler
|
194
|
+
handler.connection_pool_list.each do |pool|
|
195
|
+
name = pool.spec.name
|
196
|
+
writing_connection = writing_handler.retrieve_connection_pool(name)
|
197
|
+
handler.send(:owner_to_pool)[name] = writing_connection
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def load_fixtures(config)
|
204
|
+
fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config)
|
205
|
+
Hash[fixtures.map { |f| [f.name, f] }]
|
206
|
+
end
|
207
|
+
|
208
|
+
def instantiate_fixtures
|
209
|
+
if pre_loaded_fixtures
|
210
|
+
raise RuntimeError, "Load fixtures before instantiating them." if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
|
211
|
+
ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
|
212
|
+
else
|
213
|
+
raise RuntimeError, "Load fixtures before instantiating them." if @loaded_fixtures.nil?
|
214
|
+
@loaded_fixtures.each_value do |fixture_set|
|
215
|
+
ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def load_instances?
|
221
|
+
use_instantiated_fixtures != :no_instances
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
@@ -56,8 +56,7 @@ module ActiveRecord
|
|
56
56
|
def touch_attributes_with_time(*names, time: nil)
|
57
57
|
attribute_names = timestamp_attributes_for_update_in_model
|
58
58
|
attribute_names |= names.map(&:to_s)
|
59
|
-
time
|
60
|
-
attribute_names.each_with_object({}) { |attr_name, result| result[attr_name] = time }
|
59
|
+
attribute_names.index_with(time || current_time_from_proper_timezone)
|
61
60
|
end
|
62
61
|
|
63
62
|
private
|
@@ -134,11 +133,10 @@ module ActiveRecord
|
|
134
133
|
self.class.send(:current_time_from_proper_timezone)
|
135
134
|
end
|
136
135
|
|
137
|
-
def max_updated_column_timestamp
|
138
|
-
|
139
|
-
.map { |attr| self[attr] }
|
136
|
+
def max_updated_column_timestamp
|
137
|
+
timestamp_attributes_for_update_in_model
|
138
|
+
.map { |attr| self[attr]&.to_time }
|
140
139
|
.compact
|
141
|
-
.map(&:to_time)
|
142
140
|
.max
|
143
141
|
end
|
144
142
|
|
@@ -306,9 +306,7 @@ module ActiveRecord
|
|
306
306
|
end
|
307
307
|
|
308
308
|
def save(*) #:nodoc:
|
309
|
-
|
310
|
-
with_transaction_returning_status { super }
|
311
|
-
end
|
309
|
+
with_transaction_returning_status { super }
|
312
310
|
end
|
313
311
|
|
314
312
|
def save!(*) #:nodoc:
|
@@ -319,17 +317,6 @@ module ActiveRecord
|
|
319
317
|
with_transaction_returning_status { super }
|
320
318
|
end
|
321
319
|
|
322
|
-
# Reset id and @new_record if the transaction rolls back.
|
323
|
-
def rollback_active_record_state!
|
324
|
-
remember_transaction_record_state
|
325
|
-
yield
|
326
|
-
rescue Exception
|
327
|
-
restore_transaction_record_state
|
328
|
-
raise
|
329
|
-
ensure
|
330
|
-
clear_transaction_record_state
|
331
|
-
end
|
332
|
-
|
333
320
|
def before_committed! # :nodoc:
|
334
321
|
_run_before_commit_without_transaction_enrollment_callbacks
|
335
322
|
_run_before_commit_callbacks
|
@@ -340,7 +327,6 @@ module ActiveRecord
|
|
340
327
|
# Ensure that it is not called if the object was never persisted (failed create),
|
341
328
|
# but call it after the commit of a destroyed object.
|
342
329
|
def committed!(should_run_callbacks: true) #:nodoc:
|
343
|
-
force_clear_transaction_record_state
|
344
330
|
if should_run_callbacks && (destroyed? || persisted?)
|
345
331
|
@_committed_already_called = true
|
346
332
|
_run_commit_without_transaction_enrollment_callbacks
|
@@ -348,6 +334,7 @@ module ActiveRecord
|
|
348
334
|
end
|
349
335
|
ensure
|
350
336
|
@_committed_already_called = false
|
337
|
+
force_clear_transaction_record_state
|
351
338
|
end
|
352
339
|
|
353
340
|
# Call the #after_rollback callbacks. The +force_restore_state+ argument indicates if the record
|
@@ -388,16 +375,10 @@ module ActiveRecord
|
|
388
375
|
raise ActiveRecord::Rollback unless status
|
389
376
|
end
|
390
377
|
status
|
391
|
-
ensure
|
392
|
-
if @transaction_state && @transaction_state.committed?
|
393
|
-
clear_transaction_record_state
|
394
|
-
end
|
395
378
|
end
|
396
379
|
|
397
|
-
protected
|
398
|
-
attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback
|
399
|
-
|
400
380
|
private
|
381
|
+
attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback
|
401
382
|
|
402
383
|
# Save the new record state and id of a record so it can be restored later if a transaction fails.
|
403
384
|
def remember_transaction_record_state
|
@@ -52,8 +52,6 @@ module ActiveRecord
|
|
52
52
|
priority <=> other.priority
|
53
53
|
end
|
54
54
|
|
55
|
-
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
56
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
57
55
|
protected
|
58
56
|
|
59
57
|
attr_reader :name, :block, :adapter, :override
|
@@ -114,13 +112,8 @@ module ActiveRecord
|
|
114
112
|
super | 4
|
115
113
|
end
|
116
114
|
|
117
|
-
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
118
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
119
|
-
protected
|
120
|
-
|
121
|
-
attr_reader :options, :klass
|
122
|
-
|
123
115
|
private
|
116
|
+
attr_reader :options, :klass
|
124
117
|
|
125
118
|
def matches_options?(**kwargs)
|
126
119
|
options.all? do |key, value|
|
data/lib/active_record/type.rb
CHANGED
@@ -48,12 +48,11 @@ module ActiveRecord
|
|
48
48
|
|
49
49
|
private
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
51
|
+
def current_adapter_name
|
52
|
+
ActiveRecord::Base.connection.adapter_name.downcase.to_sym
|
53
|
+
end
|
54
54
|
end
|
55
55
|
|
56
|
-
Helpers = ActiveModel::Type::Helpers
|
57
56
|
BigInteger = ActiveModel::Type::BigInteger
|
58
57
|
Binary = ActiveModel::Type::Binary
|
59
58
|
Boolean = ActiveModel::Type::Boolean
|
@@ -14,15 +14,10 @@ module ActiveRecord
|
|
14
14
|
connection.type_cast_from_column(column, value)
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
19
|
-
protected
|
20
|
-
|
17
|
+
private
|
21
18
|
attr_reader :table_name
|
22
19
|
delegate :connection, to: :@klass
|
23
20
|
|
24
|
-
private
|
25
|
-
|
26
21
|
def column_for(attribute_name)
|
27
22
|
if connection.schema_cache.data_source_exists?(table_name)
|
28
23
|
connection.schema_cache.columns_hash(table_name)[attribute_name.to_s]
|
@@ -56,33 +56,21 @@ module ActiveRecord
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def build_relation(klass, attribute, value)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
59
|
+
relation = klass.unscoped
|
60
|
+
comparison = relation.bind_attribute(attribute, value) do |attr, bind|
|
61
|
+
return relation.none! if bind.unboundable?
|
62
|
+
|
63
|
+
if bind.nil?
|
64
|
+
attr.eq(bind)
|
65
|
+
elsif options[:case_sensitive]
|
66
|
+
klass.connection.case_sensitive_comparison(attr, bind)
|
67
|
+
else
|
68
|
+
# will use SQL LOWER function before comparison, unless it detects a case insensitive collation
|
69
|
+
klass.connection.case_insensitive_comparison(attr, bind)
|
70
|
+
end
|
71
71
|
end
|
72
72
|
|
73
|
-
|
74
|
-
value = klass.predicate_builder.build_bind_attribute(attribute_name, value)
|
75
|
-
|
76
|
-
table = klass.arel_table
|
77
|
-
column = klass.columns_hash[attribute_name]
|
78
|
-
|
79
|
-
comparison = if !options[:case_sensitive]
|
80
|
-
# will use SQL LOWER function before comparison, unless it detects a case insensitive collation
|
81
|
-
klass.connection.case_insensitive_comparison(table, attribute, column, value)
|
82
|
-
else
|
83
|
-
klass.connection.case_sensitive_comparison(table, attribute, column, value)
|
84
|
-
end
|
85
|
-
klass.unscoped.where!(comparison)
|
73
|
+
relation.where!(comparison)
|
86
74
|
end
|
87
75
|
|
88
76
|
def scope_relation(record, relation)
|
data/lib/active_record.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright (c) 2004-
|
4
|
+
# Copyright (c) 2004-2019 David Heinemeier Hansson
|
5
5
|
#
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining
|
7
7
|
# a copy of this software and associated documentation files (the
|
@@ -163,6 +163,7 @@ module ActiveRecord
|
|
163
163
|
"active_record/tasks/postgresql_database_tasks"
|
164
164
|
end
|
165
165
|
|
166
|
+
autoload :TestDatabases, "active_record/test_databases"
|
166
167
|
autoload :TestFixtures, "active_record/fixtures"
|
167
168
|
|
168
169
|
def self.eager_load!
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arel # :nodoc: all
|
4
|
+
module Attributes
|
5
|
+
class Attribute < Struct.new :relation, :name
|
6
|
+
include Arel::Expressions
|
7
|
+
include Arel::Predications
|
8
|
+
include Arel::AliasPredication
|
9
|
+
include Arel::OrderPredications
|
10
|
+
include Arel::Math
|
11
|
+
|
12
|
+
###
|
13
|
+
# Create a node for lowering this attribute
|
14
|
+
def lower
|
15
|
+
relation.lower self
|
16
|
+
end
|
17
|
+
|
18
|
+
def type_cast_for_database(value)
|
19
|
+
relation.type_cast_for_database(name, value)
|
20
|
+
end
|
21
|
+
|
22
|
+
def able_to_type_cast?
|
23
|
+
relation.able_to_type_cast?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class String < Attribute; end
|
28
|
+
class Time < Attribute; end
|
29
|
+
class Boolean < Attribute; end
|
30
|
+
class Decimal < Attribute; end
|
31
|
+
class Float < Attribute; end
|
32
|
+
class Integer < Attribute; end
|
33
|
+
class Undefined < Attribute; end
|
34
|
+
end
|
35
|
+
|
36
|
+
Attribute = Attributes::Attribute
|
37
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "arel/attributes/attribute"
|
4
|
+
|
5
|
+
module Arel # :nodoc: all
|
6
|
+
module Attributes
|
7
|
+
###
|
8
|
+
# Factory method to wrap a raw database +column+ to an Arel Attribute.
|
9
|
+
def self.for(column)
|
10
|
+
case column.type
|
11
|
+
when :string, :text, :binary then String
|
12
|
+
when :integer then Integer
|
13
|
+
when :float then Float
|
14
|
+
when :decimal then Decimal
|
15
|
+
when :date, :datetime, :timestamp, :time then Time
|
16
|
+
when :boolean then Boolean
|
17
|
+
else
|
18
|
+
Undefined
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arel # :nodoc: all
|
4
|
+
module Collectors
|
5
|
+
class Bind
|
6
|
+
def initialize
|
7
|
+
@binds = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def <<(str)
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_bind(bind)
|
15
|
+
@binds << bind
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def value
|
20
|
+
@binds
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arel # :nodoc: all
|
4
|
+
module Collectors
|
5
|
+
class Composite
|
6
|
+
def initialize(left, right)
|
7
|
+
@left = left
|
8
|
+
@right = right
|
9
|
+
end
|
10
|
+
|
11
|
+
def <<(str)
|
12
|
+
left << str
|
13
|
+
right << str
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_bind(bind, &block)
|
18
|
+
left.add_bind bind, &block
|
19
|
+
right.add_bind bind, &block
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def value
|
24
|
+
[left.value, right.value]
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
attr_reader :left, :right
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "arel/collectors/plain_string"
|
4
|
+
|
5
|
+
module Arel # :nodoc: all
|
6
|
+
module Collectors
|
7
|
+
class SQLString < PlainString
|
8
|
+
def initialize(*)
|
9
|
+
super
|
10
|
+
@bind_index = 1
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_bind(bind)
|
14
|
+
self << yield(@bind_index)
|
15
|
+
@bind_index += 1
|
16
|
+
self
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arel # :nodoc: all
|
4
|
+
module Collectors
|
5
|
+
class SubstituteBinds
|
6
|
+
def initialize(quoter, delegate_collector)
|
7
|
+
@quoter = quoter
|
8
|
+
@delegate = delegate_collector
|
9
|
+
end
|
10
|
+
|
11
|
+
def <<(str)
|
12
|
+
delegate << str
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_bind(bind)
|
17
|
+
self << quoter.quote(bind)
|
18
|
+
end
|
19
|
+
|
20
|
+
def value
|
21
|
+
delegate.value
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
attr_reader :quoter, :delegate
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|