activerecord 6.1.7.4 → 7.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1449 -1014
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +0 -10
- data/lib/active_record/associations/association.rb +33 -17
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +15 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +8 -2
- data/lib/active_record/associations/builder/belongs_to.rb +19 -6
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +19 -21
- data/lib/active_record/associations/collection_proxy.rb +10 -5
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +8 -5
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/associations/has_one_association.rb +14 -7
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +23 -15
- data/lib/active_record/associations/preloader/association.rb +186 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -14
- data/lib/active_record/associations/preloader.rb +39 -113
- data/lib/active_record/associations/singular_association.rb +15 -7
- data/lib/active_record/associations/through_association.rb +3 -3
- data/lib/active_record/associations.rb +138 -100
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +49 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +8 -6
- data/lib/active_record/attribute_methods/serialization.rb +57 -19
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +19 -22
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +17 -28
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +14 -16
- data/lib/active_record/coders/yaml_column.rb +4 -8
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +52 -23
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +82 -25
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
- data/lib/active_record/connection_adapters/abstract_adapter.rb +153 -74
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +112 -84
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -24
- data/lib/active_record/connection_adapters/mysql/quoting.rb +45 -21
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +4 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +19 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -17
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +71 -71
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +40 -21
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -106
- data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +28 -16
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +17 -15
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +97 -32
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +49 -55
- data/lib/active_record/core.rb +123 -148
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +12 -9
- data/lib/active_record/database_configurations/hash_config.rb +63 -5
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +15 -32
- data/lib/active_record/delegated_type.rb +53 -12
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +67 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +206 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +90 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +50 -43
- data/lib/active_record/errors.rb +67 -4
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +41 -6
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +20 -23
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +5 -5
- data/lib/active_record/inheritance.rb +55 -17
- data/lib/active_record/insert_all.rb +80 -14
- data/lib/active_record/integration.rb +4 -3
- data/lib/active_record/internal_metadata.rb +1 -5
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +36 -21
- data/lib/active_record/locking/pessimistic.rb +10 -4
- data/lib/active_record/log_subscriber.rb +23 -7
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +18 -6
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +8 -9
- data/lib/active_record/migration/compatibility.rb +91 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +115 -84
- data/lib/active_record/model_schema.rb +58 -59
- data/lib/active_record/nested_attributes.rb +13 -12
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +228 -60
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +149 -0
- data/lib/active_record/querying.rb +16 -6
- data/lib/active_record/railtie.rb +136 -22
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +78 -136
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +80 -49
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +6 -6
- data/lib/active_record/relation/calculations.rb +92 -60
- data/lib/active_record/relation/delegation.rb +7 -7
- data/lib/active_record/relation/finder_methods.rb +31 -35
- data/lib/active_record/relation/merger.rb +20 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -1
- data/lib/active_record/relation/predicate_builder.rb +2 -6
- data/lib/active_record/relation/query_attribute.rb +5 -11
- data/lib/active_record/relation/query_methods.rb +285 -68
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +189 -88
- data/lib/active_record/result.rb +23 -11
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +17 -12
- data/lib/active_record/schema.rb +38 -23
- data/lib/active_record/schema_dumper.rb +29 -19
- data/lib/active_record/schema_migration.rb +4 -4
- data/lib/active_record/scoping/default.rb +60 -13
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +64 -34
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +3 -3
- data/lib/active_record/store.rb +2 -2
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/table_metadata.rb +5 -1
- data/lib/active_record/tasks/database_tasks.rb +127 -60
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +9 -6
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +9 -14
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -7
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +5 -5
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/associated.rb +4 -4
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +4 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +225 -27
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +11 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +0 -1
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +8 -2
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +58 -2
- data/lib/arel.rb +2 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +58 -14
@@ -5,13 +5,27 @@ module ActiveRecord
|
|
5
5
|
class BatchEnumerator
|
6
6
|
include Enumerable
|
7
7
|
|
8
|
-
def initialize(of: 1000, start: nil, finish: nil, relation:)
|
8
|
+
def initialize(of: 1000, start: nil, finish: nil, relation:) # :nodoc:
|
9
9
|
@of = of
|
10
10
|
@relation = relation
|
11
11
|
@start = start
|
12
12
|
@finish = finish
|
13
13
|
end
|
14
14
|
|
15
|
+
# The primary key value from which the BatchEnumerator starts, inclusive of the value.
|
16
|
+
attr_reader :start
|
17
|
+
|
18
|
+
# The primary key value at which the BatchEnumerator ends, inclusive of the value.
|
19
|
+
attr_reader :finish
|
20
|
+
|
21
|
+
# The relation from which the BatchEnumerator yields batches.
|
22
|
+
attr_reader :relation
|
23
|
+
|
24
|
+
# The size of the batches yielded by the BatchEnumerator.
|
25
|
+
def batch_size
|
26
|
+
@of
|
27
|
+
end
|
28
|
+
|
15
29
|
# Looping through a collection of records from the database (using the
|
16
30
|
# +all+ method, for example) is very inefficient since it will try to
|
17
31
|
# instantiate all the objects at once.
|
@@ -33,11 +47,11 @@ module ActiveRecord
|
|
33
47
|
# Person.in_batches.each_record.with_index do |person, index|
|
34
48
|
# person.award_trophy(index + 1)
|
35
49
|
# end
|
36
|
-
def each_record
|
50
|
+
def each_record(&block)
|
37
51
|
return to_enum(:each_record) unless block_given?
|
38
52
|
|
39
53
|
@relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: true).each do |relation|
|
40
|
-
relation.records.each
|
54
|
+
relation.records.each(&block)
|
41
55
|
end
|
42
56
|
end
|
43
57
|
|
@@ -75,9 +89,9 @@ module ActiveRecord
|
|
75
89
|
# Person.in_batches.each do |relation|
|
76
90
|
# relation.update_all(awesome: true)
|
77
91
|
# end
|
78
|
-
def each
|
92
|
+
def each(&block)
|
79
93
|
enum = @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: false)
|
80
|
-
return enum.each
|
94
|
+
return enum.each(&block) if block_given?
|
81
95
|
enum
|
82
96
|
end
|
83
97
|
end
|
@@ -37,7 +37,7 @@ module ActiveRecord
|
|
37
37
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
38
38
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
39
39
|
# an order is present in the relation.
|
40
|
-
# * <tt>:order</tt> - Specifies the primary key order (can be
|
40
|
+
# * <tt>:order</tt> - Specifies the primary key order (can be +:asc+ or +:desc+). Defaults to +:asc+.
|
41
41
|
#
|
42
42
|
# Limits are honored, and if present there is no requirement for the batch
|
43
43
|
# size: it can be less than, equal to, or greater than the limit.
|
@@ -65,10 +65,10 @@ module ActiveRecord
|
|
65
65
|
#
|
66
66
|
# NOTE: By its nature, batch processing is subject to race conditions if
|
67
67
|
# other processes are modifying the database.
|
68
|
-
def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc)
|
68
|
+
def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc, &block)
|
69
69
|
if block_given?
|
70
70
|
find_in_batches(start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do |records|
|
71
|
-
records.each
|
71
|
+
records.each(&block)
|
72
72
|
end
|
73
73
|
else
|
74
74
|
enum_for(:find_each, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do
|
@@ -102,7 +102,7 @@ module ActiveRecord
|
|
102
102
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
103
103
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
104
104
|
# an order is present in the relation.
|
105
|
-
# * <tt>:order</tt> - Specifies the primary key order (can be
|
105
|
+
# * <tt>:order</tt> - Specifies the primary key order (can be +:asc+ or +:desc+). Defaults to +:asc+.
|
106
106
|
#
|
107
107
|
# Limits are honored, and if present there is no requirement for the batch
|
108
108
|
# size: it can be less than, equal to, or greater than the limit.
|
@@ -167,7 +167,7 @@ module ActiveRecord
|
|
167
167
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
168
168
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
169
169
|
# an order is present in the relation.
|
170
|
-
# * <tt>:order</tt> - Specifies the primary key order (can be
|
170
|
+
# * <tt>:order</tt> - Specifies the primary key order (can be +:asc+ or +:desc+). Defaults to +:asc+.
|
171
171
|
#
|
172
172
|
# Limits are honored, and if present there is no requirement for the batch
|
173
173
|
# size, it can be less than, equal, or greater than the limit.
|
@@ -284,7 +284,7 @@ module ActiveRecord
|
|
284
284
|
end
|
285
285
|
|
286
286
|
def act_on_ignored_order(error_on_ignore)
|
287
|
-
raise_error = (error_on_ignore.nil? ?
|
287
|
+
raise_error = (error_on_ignore.nil? ? ActiveRecord.error_on_ignored_order : error_on_ignore)
|
288
288
|
|
289
289
|
if raise_error
|
290
290
|
raise ArgumentError.new(ORDER_IGNORE_MESSAGE)
|
@@ -4,6 +4,47 @@ require "active_support/core_ext/enumerable"
|
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
6
|
module Calculations
|
7
|
+
class ColumnAliasTracker # :nodoc:
|
8
|
+
def initialize(connection)
|
9
|
+
@connection = connection
|
10
|
+
@aliases = Hash.new(0)
|
11
|
+
end
|
12
|
+
|
13
|
+
def alias_for(field)
|
14
|
+
aliased_name = column_alias_for(field)
|
15
|
+
|
16
|
+
if @aliases[aliased_name] == 0
|
17
|
+
@aliases[aliased_name] = 1
|
18
|
+
aliased_name
|
19
|
+
else
|
20
|
+
# Update the count
|
21
|
+
count = @aliases[aliased_name] += 1
|
22
|
+
"#{truncate(aliased_name)}_#{count}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
# Converts the given field to the value that the database adapter returns as
|
28
|
+
# a usable column name:
|
29
|
+
#
|
30
|
+
# column_alias_for("users.id") # => "users_id"
|
31
|
+
# column_alias_for("sum(id)") # => "sum_id"
|
32
|
+
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
|
33
|
+
# column_alias_for("count(*)") # => "count_all"
|
34
|
+
def column_alias_for(field)
|
35
|
+
column_alias = +field
|
36
|
+
column_alias.gsub!(/\*/, "all")
|
37
|
+
column_alias.gsub!(/\W+/, " ")
|
38
|
+
column_alias.strip!
|
39
|
+
column_alias.gsub!(/ +/, "_")
|
40
|
+
@connection.table_alias_for(column_alias)
|
41
|
+
end
|
42
|
+
|
43
|
+
def truncate(name)
|
44
|
+
name.slice(0, @connection.table_alias_length - 2)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
7
48
|
# Count the records.
|
8
49
|
#
|
9
50
|
# Person.count
|
@@ -31,7 +72,7 @@ module ActiveRecord
|
|
31
72
|
#
|
32
73
|
# Article.group(:status, :category).count
|
33
74
|
# # => {["draft", "business"]=>10, ["draft", "technology"]=>4,
|
34
|
-
#
|
75
|
+
# # ["published", "business"]=>0, ["published", "technology"]=>2}
|
35
76
|
#
|
36
77
|
# If #count is used with {Relation#select}[rdoc-ref:QueryMethods#select], it will count the selected columns:
|
37
78
|
#
|
@@ -83,15 +124,24 @@ module ActiveRecord
|
|
83
124
|
# #calculate for examples with options.
|
84
125
|
#
|
85
126
|
# Person.sum(:age) # => 4562
|
86
|
-
def sum(
|
127
|
+
def sum(identity_or_column = nil, &block)
|
87
128
|
if block_given?
|
88
|
-
|
89
|
-
|
129
|
+
values = map(&block)
|
130
|
+
if identity_or_column.nil? && (values.first.is_a?(Numeric) || values.first(1) == [] || values.first.respond_to?(:coerce))
|
131
|
+
identity_or_column = 0
|
90
132
|
end
|
91
133
|
|
92
|
-
|
134
|
+
if identity_or_column.nil?
|
135
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
136
|
+
Rails 7.0 has deprecated Enumerable.sum in favor of Ruby's native implementation available since 2.4.
|
137
|
+
Sum of non-numeric elements requires an initial argument.
|
138
|
+
MSG
|
139
|
+
values.inject(:+) || 0
|
140
|
+
else
|
141
|
+
values.sum(identity_or_column)
|
142
|
+
end
|
93
143
|
else
|
94
|
-
calculate(:sum,
|
144
|
+
calculate(:sum, identity_or_column)
|
95
145
|
end
|
96
146
|
end
|
97
147
|
|
@@ -146,7 +196,7 @@ module ActiveRecord
|
|
146
196
|
end
|
147
197
|
|
148
198
|
# Use #pluck as a shortcut to select one or more attributes without
|
149
|
-
# loading
|
199
|
+
# loading an entire record object per row.
|
150
200
|
#
|
151
201
|
# Person.pluck(:name)
|
152
202
|
#
|
@@ -195,9 +245,9 @@ module ActiveRecord
|
|
195
245
|
relation.select_values = columns
|
196
246
|
result = skip_query_cache_if_necessary do
|
197
247
|
if where_clause.contradiction?
|
198
|
-
ActiveRecord::Result.
|
248
|
+
ActiveRecord::Result.empty
|
199
249
|
else
|
200
|
-
klass.connection.select_all(relation.arel,
|
250
|
+
klass.connection.select_all(relation.arel, "#{klass.name} Pluck")
|
201
251
|
end
|
202
252
|
end
|
203
253
|
type_cast_pluck_values(result, columns)
|
@@ -286,7 +336,7 @@ module ActiveRecord
|
|
286
336
|
operation == "count" ? column.count(distinct) : column.public_send(operation)
|
287
337
|
end
|
288
338
|
|
289
|
-
def execute_simple_calculation(operation, column_name, distinct)
|
339
|
+
def execute_simple_calculation(operation, column_name, distinct) # :nodoc:
|
290
340
|
if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
|
291
341
|
# Shortcut when limit is zero.
|
292
342
|
return 0 if limit_value == 0
|
@@ -305,29 +355,21 @@ module ActiveRecord
|
|
305
355
|
query_builder = relation.arel
|
306
356
|
end
|
307
357
|
|
308
|
-
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder) }
|
358
|
+
result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder, "#{@klass.name} #{operation.capitalize}") }
|
309
359
|
|
310
|
-
|
360
|
+
if operation != "count"
|
311
361
|
type = column.try(:type_caster) ||
|
312
362
|
lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
|
313
363
|
type = type.subtype if Enum::EnumType === type
|
314
|
-
type.deserialize(value)
|
315
364
|
end
|
365
|
+
|
366
|
+
type_cast_calculated_value(result.cast_values.first, operation, type)
|
316
367
|
end
|
317
368
|
|
318
|
-
def execute_grouped_calculation(operation, column_name, distinct)
|
369
|
+
def execute_grouped_calculation(operation, column_name, distinct) # :nodoc:
|
319
370
|
group_fields = group_values
|
320
371
|
group_fields = group_fields.uniq if group_fields.size > 1
|
321
372
|
|
322
|
-
unless group_fields == group_values
|
323
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
324
|
-
`#{operation}` with group by duplicated fields does no longer affect to result in Rails 7.0.
|
325
|
-
To migrate to Rails 7.0's behavior, use `uniq!(:group)` to deduplicate group fields
|
326
|
-
(`#{klass.name&.tableize || klass.table_name}.uniq!(:group).#{operation}(#{column_name.inspect})`).
|
327
|
-
MSG
|
328
|
-
group_fields = group_values
|
329
|
-
end
|
330
|
-
|
331
373
|
if group_fields.size == 1 && group_fields.first.respond_to?(:to_sym)
|
332
374
|
association = klass._reflect_on_association(group_fields.first)
|
333
375
|
associated = association && association.belongs_to? # only count belongs_to associations
|
@@ -335,21 +377,24 @@ module ActiveRecord
|
|
335
377
|
end
|
336
378
|
group_fields = arel_columns(group_fields)
|
337
379
|
|
380
|
+
column_alias_tracker = ColumnAliasTracker.new(connection)
|
381
|
+
|
338
382
|
group_aliases = group_fields.map { |field|
|
339
383
|
field = connection.visitor.compile(field) if Arel.arel_node?(field)
|
340
|
-
|
384
|
+
column_alias_tracker.alias_for(field.to_s.downcase)
|
341
385
|
}
|
342
386
|
group_columns = group_aliases.zip(group_fields)
|
343
387
|
|
344
388
|
column = aggregate_column(column_name)
|
345
|
-
column_alias =
|
389
|
+
column_alias = column_alias_tracker.alias_for("#{operation} #{column_name.to_s.downcase}")
|
346
390
|
select_value = operation_over_aggregate_column(column, operation, distinct)
|
347
|
-
select_value.as(column_alias)
|
391
|
+
select_value.as(connection.quote_column_name(column_alias))
|
348
392
|
|
349
393
|
select_values = [select_value]
|
350
394
|
select_values += self.select_values unless having_clause.empty?
|
351
395
|
|
352
396
|
select_values.concat group_columns.map { |aliaz, field|
|
397
|
+
aliaz = connection.quote_column_name(aliaz)
|
353
398
|
if field.respond_to?(:as)
|
354
399
|
field.as(aliaz)
|
355
400
|
else
|
@@ -361,7 +406,7 @@ module ActiveRecord
|
|
361
406
|
relation.group_values = group_fields
|
362
407
|
relation.select_values = select_values
|
363
408
|
|
364
|
-
calculated_data = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel,
|
409
|
+
calculated_data = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, "#{@klass.name} #{operation.capitalize}") }
|
365
410
|
|
366
411
|
if association
|
367
412
|
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
@@ -370,9 +415,10 @@ module ActiveRecord
|
|
370
415
|
end
|
371
416
|
|
372
417
|
key_types = group_columns.each_with_object({}) do |(aliaz, col_name), types|
|
373
|
-
types[aliaz] =
|
374
|
-
|
375
|
-
|
418
|
+
types[aliaz] = col_name.try(:type_caster) ||
|
419
|
+
type_for(col_name) do
|
420
|
+
calculated_data.column_types.fetch(aliaz, Type.default_value)
|
421
|
+
end
|
376
422
|
end
|
377
423
|
|
378
424
|
hash_rows = calculated_data.cast_values(key_types).map! do |row|
|
@@ -381,40 +427,21 @@ module ActiveRecord
|
|
381
427
|
end
|
382
428
|
end
|
383
429
|
|
384
|
-
|
430
|
+
if operation != "count"
|
431
|
+
type = column.try(:type_caster) ||
|
432
|
+
lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
|
433
|
+
type = type.subtype if Enum::EnumType === type
|
434
|
+
end
|
435
|
+
|
385
436
|
hash_rows.each_with_object({}) do |row, result|
|
386
437
|
key = group_aliases.map { |aliaz| row[aliaz] }
|
387
438
|
key = key.first if key.size == 1
|
388
439
|
key = key_records[key] if associated
|
389
440
|
|
390
|
-
result[key] = type_cast_calculated_value(row[column_alias], operation)
|
391
|
-
unless type
|
392
|
-
type = column.try(:type_caster) ||
|
393
|
-
lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
|
394
|
-
type = type.subtype if Enum::EnumType === type
|
395
|
-
end
|
396
|
-
type.deserialize(value)
|
397
|
-
end
|
441
|
+
result[key] = type_cast_calculated_value(row[column_alias], operation, type)
|
398
442
|
end
|
399
443
|
end
|
400
444
|
|
401
|
-
# Converts the given field to the value that the database adapter returns as
|
402
|
-
# a usable column name:
|
403
|
-
#
|
404
|
-
# column_alias_for("users.id") # => "users_id"
|
405
|
-
# column_alias_for("sum(id)") # => "sum_id"
|
406
|
-
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
|
407
|
-
# column_alias_for("count(*)") # => "count_all"
|
408
|
-
def column_alias_for(field)
|
409
|
-
column_alias = +field
|
410
|
-
column_alias.gsub!(/\*/, "all")
|
411
|
-
column_alias.gsub!(/\W+/, " ")
|
412
|
-
column_alias.strip!
|
413
|
-
column_alias.gsub!(/ +/, "_")
|
414
|
-
|
415
|
-
connection.table_alias_for(column_alias)
|
416
|
-
end
|
417
|
-
|
418
445
|
def type_for(field, &block)
|
419
446
|
field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split(".").last
|
420
447
|
@klass.type_for_attribute(field_name, &block)
|
@@ -445,16 +472,21 @@ module ActiveRecord
|
|
445
472
|
result.cast_values(cast_types)
|
446
473
|
end
|
447
474
|
|
448
|
-
def type_cast_calculated_value(value, operation)
|
475
|
+
def type_cast_calculated_value(value, operation, type)
|
449
476
|
case operation
|
450
477
|
when "count"
|
451
478
|
value.to_i
|
452
479
|
when "sum"
|
453
|
-
|
480
|
+
type.deserialize(value || 0)
|
454
481
|
when "average"
|
455
|
-
|
482
|
+
case type.type
|
483
|
+
when :integer, :decimal
|
484
|
+
value&.to_d
|
485
|
+
else
|
486
|
+
type.deserialize(value)
|
487
|
+
end
|
456
488
|
else # "minimum", "maximum"
|
457
|
-
|
489
|
+
type.deserialize(value)
|
458
490
|
end
|
459
491
|
end
|
460
492
|
|
@@ -15,7 +15,8 @@ module ActiveRecord
|
|
15
15
|
[
|
16
16
|
ActiveRecord::Relation,
|
17
17
|
ActiveRecord::Associations::CollectionProxy,
|
18
|
-
ActiveRecord::AssociationRelation
|
18
|
+
ActiveRecord::AssociationRelation,
|
19
|
+
ActiveRecord::DisableJoinsAssociationRelation
|
19
20
|
].each do |klass|
|
20
21
|
delegate = Class.new(klass) {
|
21
22
|
include ClassSpecificRelation
|
@@ -61,17 +62,16 @@ module ActiveRecord
|
|
61
62
|
return if method_defined?(method)
|
62
63
|
|
63
64
|
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method) && !DELEGATION_RESERVED_METHOD_NAMES.include?(method.to_s)
|
64
|
-
definition = RUBY_VERSION >= "2.7" ? "..." : "*args, &block"
|
65
65
|
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
66
|
-
def #{method}(
|
67
|
-
scoping { klass.#{method}(
|
66
|
+
def #{method}(...)
|
67
|
+
scoping { klass.#{method}(...) }
|
68
68
|
end
|
69
69
|
RUBY
|
70
70
|
else
|
71
71
|
define_method(method) do |*args, &block|
|
72
72
|
scoping { klass.public_send(method, *args, &block) }
|
73
73
|
end
|
74
|
-
ruby2_keywords(method)
|
74
|
+
ruby2_keywords(method)
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
@@ -87,7 +87,7 @@ module ActiveRecord
|
|
87
87
|
|
88
88
|
delegate :to_xml, :encode_with, :length, :each, :join,
|
89
89
|
:[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
|
90
|
-
:to_sentence, :to_formatted_s, :as_json,
|
90
|
+
:to_sentence, :to_fs, :to_formatted_s, :as_json,
|
91
91
|
:shuffle, :split, :slice, :index, :rindex, to: :records
|
92
92
|
|
93
93
|
delegate :primary_key, :connection, to: :klass
|
@@ -110,7 +110,7 @@ module ActiveRecord
|
|
110
110
|
super
|
111
111
|
end
|
112
112
|
end
|
113
|
-
ruby2_keywords(:method_missing)
|
113
|
+
ruby2_keywords(:method_missing)
|
114
114
|
end
|
115
115
|
|
116
116
|
module ClassMethods # :nodoc:
|
@@ -104,6 +104,32 @@ module ActiveRecord
|
|
104
104
|
take || raise_record_not_found_exception!
|
105
105
|
end
|
106
106
|
|
107
|
+
# Finds the sole matching record. Raises ActiveRecord::RecordNotFound if no
|
108
|
+
# record is found. Raises ActiveRecord::SoleRecordExceeded if more than one
|
109
|
+
# record is found.
|
110
|
+
#
|
111
|
+
# Product.where(["price = %?", price]).sole
|
112
|
+
def sole
|
113
|
+
found, undesired = first(2)
|
114
|
+
|
115
|
+
if found.nil?
|
116
|
+
raise_record_not_found_exception!
|
117
|
+
elsif undesired.present?
|
118
|
+
raise ActiveRecord::SoleRecordExceeded.new(self)
|
119
|
+
else
|
120
|
+
found
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Finds the sole matching record. Raises ActiveRecord::RecordNotFound if no
|
125
|
+
# record is found. Raises ActiveRecord::SoleRecordExceeded if more than one
|
126
|
+
# record is found.
|
127
|
+
#
|
128
|
+
# Product.find_sole_by(["price = %?", price])
|
129
|
+
def find_sole_by(arg, *args)
|
130
|
+
where(arg, *args).sole
|
131
|
+
end
|
132
|
+
|
107
133
|
# Find the first record (or first N records if a parameter is supplied).
|
108
134
|
# If no order is defined it will order by primary key.
|
109
135
|
#
|
@@ -114,8 +140,6 @@ module ActiveRecord
|
|
114
140
|
# Person.first(3) # returns the first three objects fetched by SELECT * FROM people ORDER BY people.id LIMIT 3
|
115
141
|
#
|
116
142
|
def first(limit = nil)
|
117
|
-
check_reorder_deprecation unless loaded?
|
118
|
-
|
119
143
|
if limit
|
120
144
|
find_nth_with_limit(0, limit)
|
121
145
|
else
|
@@ -364,17 +388,6 @@ module ActiveRecord
|
|
364
388
|
end
|
365
389
|
|
366
390
|
private
|
367
|
-
def check_reorder_deprecation
|
368
|
-
if !order_values.empty? && order_values.all?(&:blank?)
|
369
|
-
blank_value = order_values.first
|
370
|
-
ActiveSupport::Deprecation.warn(<<~MSG.squish)
|
371
|
-
`.reorder(#{blank_value.inspect})` with `.first` / `.first!` no longer
|
372
|
-
takes non-deterministic result in Rails 7.0.
|
373
|
-
To continue taking non-deterministic result, use `.take` / `.take!` instead.
|
374
|
-
MSG
|
375
|
-
end
|
376
|
-
end
|
377
|
-
|
378
391
|
def construct_relation_for_exists(conditions)
|
379
392
|
conditions = sanitize_forbidden_attributes(conditions)
|
380
393
|
|
@@ -400,7 +413,7 @@ module ActiveRecord
|
|
400
413
|
)
|
401
414
|
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
402
415
|
|
403
|
-
if eager_loading && !(
|
416
|
+
if eager_loading && has_limit_or_offset? && !(
|
404
417
|
using_limitable_reflections?(join_dependency.reflections) &&
|
405
418
|
using_limitable_reflections?(
|
406
419
|
construct_join_dependency(
|
@@ -409,12 +422,10 @@ module ActiveRecord
|
|
409
422
|
), nil
|
410
423
|
).reflections
|
411
424
|
)
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
425
|
+
)
|
426
|
+
relation = skip_query_cache_if_necessary do
|
427
|
+
klass.connection.distinct_relation_for_primary_key(relation)
|
416
428
|
end
|
417
|
-
relation.limit_value = relation.offset_value = nil
|
418
429
|
end
|
419
430
|
|
420
431
|
if block_given?
|
@@ -424,18 +435,6 @@ module ActiveRecord
|
|
424
435
|
end
|
425
436
|
end
|
426
437
|
|
427
|
-
def limited_ids_for(relation)
|
428
|
-
values = @klass.connection.columns_for_distinct(
|
429
|
-
connection.visitor.compile(table[primary_key]),
|
430
|
-
relation.order_values
|
431
|
-
)
|
432
|
-
|
433
|
-
relation = relation.except(:select).select(values).distinct!
|
434
|
-
|
435
|
-
id_rows = skip_query_cache_if_necessary { @klass.connection.select_rows(relation.arel, "SQL") }
|
436
|
-
id_rows.map(&:last)
|
437
|
-
end
|
438
|
-
|
439
438
|
def using_limitable_reflections?(reflections)
|
440
439
|
reflections.none?(&:collection?)
|
441
440
|
end
|
@@ -508,10 +507,7 @@ module ActiveRecord
|
|
508
507
|
result = except(:limit, :offset).where(primary_key => ids).records
|
509
508
|
|
510
509
|
if result.size == ids.size
|
511
|
-
|
512
|
-
|
513
|
-
records_by_id = result.index_by(&:id)
|
514
|
-
ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
|
510
|
+
result.in_order_of(:id, ids.map { |id| @klass.type_for_attribute(primary_key).cast(id) })
|
515
511
|
else
|
516
512
|
raise_record_not_found_exception!(ids, result.size, ids.size)
|
517
513
|
end
|
@@ -51,30 +51,25 @@ module ActiveRecord
|
|
51
51
|
@rewhere = rewhere
|
52
52
|
end
|
53
53
|
|
54
|
-
NORMAL_VALUES = Relation::VALUE_METHODS -
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
NORMAL_VALUES
|
60
|
-
end
|
54
|
+
NORMAL_VALUES = Relation::VALUE_METHODS - Relation::CLAUSE_METHODS -
|
55
|
+
[
|
56
|
+
:select, :includes, :preload, :joins, :left_outer_joins,
|
57
|
+
:order, :reverse_order, :lock, :create_with, :reordering
|
58
|
+
]
|
61
59
|
|
62
60
|
def merge
|
63
|
-
|
61
|
+
NORMAL_VALUES.each do |name|
|
64
62
|
value = values[name]
|
65
63
|
# The unless clause is here mostly for performance reasons (since the `send` call might be moderately
|
66
64
|
# expensive), most of the time the value is going to be `nil` or `.blank?`, the only catch is that
|
67
65
|
# `false.blank?` returns `true`, so there needs to be an extra check so that explicit `false` values
|
68
66
|
# don't fall through the cracks.
|
69
67
|
unless value.nil? || (value.blank? && false != value)
|
70
|
-
|
71
|
-
relation._select!(*value)
|
72
|
-
else
|
73
|
-
relation.public_send("#{name}!", *value)
|
74
|
-
end
|
68
|
+
relation.public_send(:"#{name}!", *value)
|
75
69
|
end
|
76
70
|
end
|
77
71
|
|
72
|
+
merge_select_values
|
78
73
|
merge_multi_values
|
79
74
|
merge_single_values
|
80
75
|
merge_clauses
|
@@ -86,6 +81,18 @@ module ActiveRecord
|
|
86
81
|
end
|
87
82
|
|
88
83
|
private
|
84
|
+
def merge_select_values
|
85
|
+
return if other.select_values.empty?
|
86
|
+
|
87
|
+
if other.klass == relation.klass
|
88
|
+
relation.select_values |= other.select_values
|
89
|
+
else
|
90
|
+
relation.select_values |= other.instance_eval do
|
91
|
+
arel_columns(select_values)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
89
96
|
def merge_preloads
|
90
97
|
return if other.preload_values.empty? && other.includes_values.empty?
|
91
98
|
|
@@ -18,7 +18,10 @@ module ActiveRecord
|
|
18
18
|
def ids
|
19
19
|
case value
|
20
20
|
when Relation
|
21
|
-
|
21
|
+
relation = value
|
22
|
+
relation = relation.select(primary_key) if select_clause?
|
23
|
+
relation = relation.where(primary_type => polymorphic_name) if polymorphic_clause?
|
24
|
+
relation
|
22
25
|
when Array
|
23
26
|
value.map { |v| convert_to_id(v) }
|
24
27
|
else
|
@@ -30,6 +33,22 @@ module ActiveRecord
|
|
30
33
|
associated_table.join_primary_key
|
31
34
|
end
|
32
35
|
|
36
|
+
def primary_type
|
37
|
+
associated_table.join_primary_type
|
38
|
+
end
|
39
|
+
|
40
|
+
def polymorphic_name
|
41
|
+
associated_table.polymorphic_name_association
|
42
|
+
end
|
43
|
+
|
44
|
+
def select_clause?
|
45
|
+
value.select_values.empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
def polymorphic_clause?
|
49
|
+
primary_type && !value.where_values_hash.has_key?(primary_type)
|
50
|
+
end
|
51
|
+
|
33
52
|
def convert_to_id(value)
|
34
53
|
if value.respond_to?(primary_key)
|
35
54
|
value.public_send(primary_key)
|
@@ -9,10 +9,6 @@ module ActiveRecord
|
|
9
9
|
require "active_record/relation/predicate_builder/association_query_value"
|
10
10
|
require "active_record/relation/predicate_builder/polymorphic_array_value"
|
11
11
|
|
12
|
-
# No-op BaseHandler to work Mashal.load(File.read("legacy_relation.dump")).
|
13
|
-
# TODO: Remove the constant alias once Rails 6.1 has released.
|
14
|
-
BaseHandler = BasicObjectHandler
|
15
|
-
|
16
12
|
def initialize(table)
|
17
13
|
@table = table
|
18
14
|
@handlers = []
|
@@ -69,8 +65,8 @@ module ActiveRecord
|
|
69
65
|
end
|
70
66
|
|
71
67
|
def build_bind_attribute(column_name, value)
|
72
|
-
|
73
|
-
|
68
|
+
type = table.type(column_name)
|
69
|
+
Relation::QueryAttribute.new(column_name, type.immutable_value(value), type)
|
74
70
|
end
|
75
71
|
|
76
72
|
def resolve_arel_attribute(table_name, column_name, &block)
|