activerecord 7.1.5.1 → 8.0.2
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 +369 -2484
- data/README.rdoc +15 -15
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +43 -12
- data/lib/active_record/associations/belongs_to_association.rb +21 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +7 -6
- data/lib/active_record/associations/builder/belongs_to.rb +1 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +4 -3
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +14 -3
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +92 -295
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/primary_key.rb +25 -61
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +4 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +9 -18
- data/lib/active_record/attribute_methods.rb +71 -75
- data/lib/active_record/attributes.rb +63 -49
- data/lib/active_record/autosave_association.rb +92 -57
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +48 -122
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +286 -77
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +119 -55
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +197 -76
- data/lib/active_record/connection_adapters/abstract/quoting.rb +66 -92
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +12 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +48 -12
- data/lib/active_record/connection_adapters/abstract/transaction.rb +140 -67
- data/lib/active_record/connection_adapters/abstract_adapter.rb +85 -90
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +71 -52
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +56 -45
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +92 -101
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +13 -31
- data/lib/active_record/connection_adapters/pool_config.rb +14 -13
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -41
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -11
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +36 -20
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +75 -28
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +73 -113
- data/lib/active_record/connection_adapters/schema_cache.rb +124 -131
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +81 -97
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +29 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +35 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +183 -87
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +39 -69
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
- data/lib/active_record/connection_adapters.rb +65 -0
- data/lib/active_record/connection_handling.rb +74 -37
- data/lib/active_record/core.rb +132 -51
- data/lib/active_record/counter_cache.rb +19 -10
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +23 -4
- data/lib/active_record/database_configurations/hash_config.rb +46 -34
- data/lib/active_record/database_configurations/url_config.rb +20 -1
- data/lib/active_record/database_configurations.rb +1 -1
- data/lib/active_record/delegated_type.rb +41 -17
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +7 -7
- data/lib/active_record/encryption/encrypted_attribute_type.rb +33 -4
- data/lib/active_record/encryption/encryptor.rb +28 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +8 -1
- data/lib/active_record/enum.rb +20 -16
- data/lib/active_record/errors.rb +54 -20
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixtures.rb +37 -33
- data/lib/active_record/future_result.rb +21 -13
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +19 -16
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/log_subscriber.rb +5 -32
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +33 -14
- data/lib/active_record/migration/compatibility.rb +8 -3
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +104 -98
- data/lib/active_record/model_schema.rb +32 -70
- data/lib/active_record/nested_attributes.rb +15 -9
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +127 -451
- data/lib/active_record/query_cache.rb +19 -8
- data/lib/active_record/query_logs.rb +104 -37
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +24 -12
- data/lib/active_record/railtie.rb +26 -68
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +43 -61
- data/lib/active_record/reflection.rb +112 -53
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +138 -72
- data/lib/active_record/relation/calculations.rb +122 -82
- data/lib/active_record/relation/delegation.rb +30 -22
- data/lib/active_record/relation/finder_methods.rb +32 -18
- data/lib/active_record/relation/merger.rb +12 -14
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +10 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +16 -3
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +317 -101
- data/lib/active_record/relation/spawn_methods.rb +3 -19
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +561 -119
- data/lib/active_record/result.rb +95 -46
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +31 -25
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +53 -20
- data/lib/active_record/schema_migration.rb +31 -14
- data/lib/active_record/scoping/named.rb +6 -2
- data/lib/active_record/signed_id.rb +24 -4
- data/lib/active_record/statement_cache.rb +19 -19
- data/lib/active_record/store.rb +7 -3
- data/lib/active_record/table_metadata.rb +2 -13
- data/lib/active_record/tasks/database_tasks.rb +87 -58
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -3
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +4 -3
- data/lib/active_record/test_fixtures.rb +98 -89
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +2 -2
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +72 -17
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/uniqueness.rb +23 -18
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +138 -57
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +4 -2
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +2 -2
- data/lib/arel/collectors/substitute_binds.rb +3 -3
- data/lib/arel/nodes/binary.rb +1 -7
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +5 -4
- data/lib/arel/nodes/sql_literal.rb +8 -1
- data/lib/arel/nodes.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/table.rb +3 -7
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +29 -16
- data/lib/arel.rb +7 -3
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +18 -16
- data/lib/active_record/relation/record_fetch_warning.rb +0 -49
@@ -72,14 +72,31 @@ module ActiveRecord
|
|
72
72
|
# # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
73
73
|
# # INNER JOIN "comments" ON "comments"."post_id" = "posts"."id"
|
74
74
|
# # WHERE "authors"."id" IS NOT NULL AND "comments"."id" IS NOT NULL
|
75
|
+
#
|
76
|
+
# You can define join type in the scope and +associated+ will not use `JOIN` by default.
|
77
|
+
#
|
78
|
+
# Post.left_joins(:author).where.associated(:author)
|
79
|
+
# # SELECT "posts".* FROM "posts"
|
80
|
+
# # LEFT OUTER JOIN "authors" "authors"."id" = "posts"."author_id"
|
81
|
+
# # WHERE "authors"."id" IS NOT NULL
|
82
|
+
#
|
83
|
+
# Post.left_joins(:comments).where.associated(:author)
|
84
|
+
# # SELECT "posts".* FROM "posts"
|
85
|
+
# # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
86
|
+
# # LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id"
|
87
|
+
# # WHERE "author"."id" IS NOT NULL
|
75
88
|
def associated(*associations)
|
76
89
|
associations.each do |association|
|
77
90
|
reflection = scope_association_reflection(association)
|
78
|
-
@scope.
|
91
|
+
unless @scope.joins_values.include?(reflection.name) || @scope.left_outer_joins_values.include?(reflection.name)
|
92
|
+
@scope.joins!(association)
|
93
|
+
end
|
94
|
+
|
95
|
+
association_conditions = Array(reflection.association_primary_key).index_with(nil)
|
79
96
|
if reflection.options[:class_name]
|
80
|
-
self.not(association =>
|
97
|
+
self.not(association => association_conditions)
|
81
98
|
else
|
82
|
-
self.not(reflection.table_name =>
|
99
|
+
self.not(reflection.table_name => association_conditions)
|
83
100
|
end
|
84
101
|
end
|
85
102
|
|
@@ -108,10 +125,11 @@ module ActiveRecord
|
|
108
125
|
associations.each do |association|
|
109
126
|
reflection = scope_association_reflection(association)
|
110
127
|
@scope.left_outer_joins!(association)
|
128
|
+
association_conditions = Array(reflection.association_primary_key).index_with(nil)
|
111
129
|
if reflection.options[:class_name]
|
112
|
-
@scope.where!(association =>
|
130
|
+
@scope.where!(association => association_conditions)
|
113
131
|
else
|
114
|
-
@scope.where!(reflection.table_name =>
|
132
|
+
@scope.where!(reflection.table_name => association_conditions)
|
115
133
|
end
|
116
134
|
end
|
117
135
|
|
@@ -120,9 +138,10 @@ module ActiveRecord
|
|
120
138
|
|
121
139
|
private
|
122
140
|
def scope_association_reflection(association)
|
123
|
-
|
141
|
+
model = @scope.model
|
142
|
+
reflection = model._reflect_on_association(association)
|
124
143
|
unless reflection
|
125
|
-
raise ArgumentError.new("An association named `:#{association}` does not exist on the model `#{
|
144
|
+
raise ArgumentError.new("An association named `:#{association}` does not exist on the model `#{model.name}`.")
|
126
145
|
end
|
127
146
|
reflection
|
128
147
|
end
|
@@ -157,7 +176,7 @@ module ActiveRecord
|
|
157
176
|
end # end
|
158
177
|
|
159
178
|
def #{method_name}=(value) # def includes_values=(value)
|
160
|
-
|
179
|
+
assert_modifiable! # assert_modifiable!
|
161
180
|
@values[:#{name}] = value # @values[:includes] = value
|
162
181
|
end # end
|
163
182
|
CODE
|
@@ -238,6 +257,10 @@ module ActiveRecord
|
|
238
257
|
self
|
239
258
|
end
|
240
259
|
|
260
|
+
def all # :nodoc:
|
261
|
+
spawn
|
262
|
+
end
|
263
|
+
|
241
264
|
# Specify associations +args+ to be eager loaded using a <tt>LEFT OUTER JOIN</tt>.
|
242
265
|
# Performs a single query joining all specified associations. For example:
|
243
266
|
#
|
@@ -419,6 +442,17 @@ module ActiveRecord
|
|
419
442
|
# # )
|
420
443
|
# # SELECT * FROM posts
|
421
444
|
#
|
445
|
+
# You can also pass an array of sub-queries to be joined in a +UNION ALL+.
|
446
|
+
#
|
447
|
+
# Post.with(posts_with_tags_or_comments: [Post.where("tags_count > ?", 0), Post.where("comments_count > ?", 0)])
|
448
|
+
# # => ActiveRecord::Relation
|
449
|
+
# # WITH posts_with_tags_or_comments AS (
|
450
|
+
# # (SELECT * FROM posts WHERE (tags_count > 0))
|
451
|
+
# # UNION ALL
|
452
|
+
# # (SELECT * FROM posts WHERE (comments_count > 0))
|
453
|
+
# # )
|
454
|
+
# # SELECT * FROM posts
|
455
|
+
#
|
422
456
|
# Once you define Common Table Expression you can use custom +FROM+ value or +JOIN+ to reference it.
|
423
457
|
#
|
424
458
|
# Post.with(posts_with_tags: Post.where("tags_count > ?", 0)).from("posts_with_tags AS posts")
|
@@ -457,13 +491,40 @@ module ActiveRecord
|
|
457
491
|
# .with(posts_with_comments: Post.where("comments_count > ?", 0))
|
458
492
|
# .with(posts_with_tags: Post.where("tags_count > ?", 0))
|
459
493
|
def with(*args)
|
494
|
+
raise ArgumentError, "ActiveRecord::Relation#with does not accept a block" if block_given?
|
460
495
|
check_if_method_has_arguments!(__callee__, args)
|
461
496
|
spawn.with!(*args)
|
462
497
|
end
|
463
498
|
|
464
499
|
# Like #with, but modifies relation in place.
|
465
500
|
def with!(*args) # :nodoc:
|
466
|
-
|
501
|
+
args = process_with_args(args)
|
502
|
+
self.with_values |= args
|
503
|
+
self
|
504
|
+
end
|
505
|
+
|
506
|
+
# Add a recursive Common Table Expression (CTE) that you can then reference within another SELECT statement.
|
507
|
+
#
|
508
|
+
# Post.with_recursive(post_and_replies: [Post.where(id: 42), Post.joins('JOIN post_and_replies ON posts.in_reply_to_id = post_and_replies.id')])
|
509
|
+
# # => ActiveRecord::Relation
|
510
|
+
# # WITH RECURSIVE post_and_replies AS (
|
511
|
+
# # (SELECT * FROM posts WHERE id = 42)
|
512
|
+
# # UNION ALL
|
513
|
+
# # (SELECT * FROM posts JOIN posts_and_replies ON posts.in_reply_to_id = posts_and_replies.id)
|
514
|
+
# # )
|
515
|
+
# # SELECT * FROM posts
|
516
|
+
#
|
517
|
+
# See `#with` for more information.
|
518
|
+
def with_recursive(*args)
|
519
|
+
check_if_method_has_arguments!(__callee__, args)
|
520
|
+
spawn.with_recursive!(*args)
|
521
|
+
end
|
522
|
+
|
523
|
+
# Like #with_recursive but modifies the relation in place.
|
524
|
+
def with_recursive!(*args) # :nodoc:
|
525
|
+
args = process_with_args(args)
|
526
|
+
self.with_values |= args
|
527
|
+
@with_is_recursive = true
|
467
528
|
self
|
468
529
|
end
|
469
530
|
|
@@ -606,7 +667,8 @@ module ActiveRecord
|
|
606
667
|
self
|
607
668
|
end
|
608
669
|
|
609
|
-
#
|
670
|
+
# Applies an <tt>ORDER BY</tt> clause based on a given +column+,
|
671
|
+
# ordered and filtered by a specific set of +values+.
|
610
672
|
#
|
611
673
|
# User.in_order_of(:id, [1, 5, 3])
|
612
674
|
# # SELECT "users".* FROM "users"
|
@@ -617,26 +679,65 @@ module ActiveRecord
|
|
617
679
|
# # WHEN "users"."id" = 3 THEN 3
|
618
680
|
# # END ASC
|
619
681
|
#
|
620
|
-
|
621
|
-
|
682
|
+
# +column+ can point to an enum column; the actual query generated may be different depending
|
683
|
+
# on the database adapter and the column definition.
|
684
|
+
#
|
685
|
+
# class Conversation < ActiveRecord::Base
|
686
|
+
# enum :status, [ :active, :archived ]
|
687
|
+
# end
|
688
|
+
#
|
689
|
+
# Conversation.in_order_of(:status, [:archived, :active])
|
690
|
+
# # SELECT "conversations".* FROM "conversations"
|
691
|
+
# # WHERE "conversations"."status" IN (1, 0)
|
692
|
+
# # ORDER BY CASE
|
693
|
+
# # WHEN "conversations"."status" = 1 THEN 1
|
694
|
+
# # WHEN "conversations"."status" = 0 THEN 2
|
695
|
+
# # END ASC
|
696
|
+
#
|
697
|
+
# +values+ can also include +nil+.
|
698
|
+
#
|
699
|
+
# Conversation.in_order_of(:status, [nil, :archived, :active])
|
700
|
+
# # SELECT "conversations".* FROM "conversations"
|
701
|
+
# # WHERE ("conversations"."status" IN (1, 0) OR "conversations"."status" IS NULL)
|
702
|
+
# # ORDER BY CASE
|
703
|
+
# # WHEN "conversations"."status" IS NULL THEN 1
|
704
|
+
# # WHEN "conversations"."status" = 1 THEN 2
|
705
|
+
# # WHEN "conversations"."status" = 0 THEN 3
|
706
|
+
# # END ASC
|
707
|
+
#
|
708
|
+
# +filter+ can be set to +false+ to include all results instead of only the ones specified in +values+.
|
709
|
+
#
|
710
|
+
# Conversation.in_order_of(:status, [:archived, :active], filter: false)
|
711
|
+
# # SELECT "conversations".* FROM "conversations"
|
712
|
+
# # ORDER BY CASE
|
713
|
+
# # WHEN "conversations"."status" = 1 THEN 1
|
714
|
+
# # WHEN "conversations"."status" = 0 THEN 2
|
715
|
+
# # ELSE 3
|
716
|
+
# # END ASC
|
717
|
+
def in_order_of(column, values, filter: true)
|
718
|
+
model.disallow_raw_sql!([column], permit: model.adapter_class.column_name_with_order_matcher)
|
622
719
|
return spawn.none! if values.empty?
|
623
720
|
|
624
721
|
references = column_references([column])
|
625
722
|
self.references_values |= references unless references.empty?
|
626
723
|
|
627
|
-
values = values.map { |value| type_caster.type_cast_for_database(column, value) }
|
724
|
+
values = values.map { |value| model.type_caster.type_cast_for_database(column, value) }
|
628
725
|
arel_column = column.is_a?(Arel::Nodes::SqlLiteral) ? column : order_column(column.to_s)
|
629
726
|
|
630
|
-
|
631
|
-
if values.include?(nil)
|
632
|
-
arel_column.in(values.compact).or(arel_column.eq(nil))
|
633
|
-
else
|
634
|
-
arel_column.in(values)
|
635
|
-
end
|
727
|
+
scope = spawn.order!(build_case_for_value_position(arel_column, values, filter: filter))
|
636
728
|
|
637
|
-
|
638
|
-
|
639
|
-
|
729
|
+
if filter
|
730
|
+
where_clause =
|
731
|
+
if values.include?(nil)
|
732
|
+
arel_column.in(values.compact).or(arel_column.eq(nil))
|
733
|
+
else
|
734
|
+
arel_column.in(values)
|
735
|
+
end
|
736
|
+
|
737
|
+
scope = scope.where!(where_clause)
|
738
|
+
end
|
739
|
+
|
740
|
+
scope
|
640
741
|
end
|
641
742
|
|
642
743
|
# Replaces any existing order defined on the relation with the specified order.
|
@@ -667,7 +768,7 @@ module ActiveRecord
|
|
667
768
|
VALID_UNSCOPING_VALUES = Set.new([:where, :select, :group, :order, :lock,
|
668
769
|
:limit, :offset, :joins, :left_outer_joins, :annotate,
|
669
770
|
:includes, :eager_load, :preload, :from, :readonly,
|
670
|
-
:having, :optimizer_hints])
|
771
|
+
:having, :optimizer_hints, :with])
|
671
772
|
|
672
773
|
# Removes an unwanted relation that is already defined on a chain of relations.
|
673
774
|
# This is useful when passing around chains of relations and would like to
|
@@ -717,7 +818,7 @@ module ActiveRecord
|
|
717
818
|
if !VALID_UNSCOPING_VALUES.include?(scope)
|
718
819
|
raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
|
719
820
|
end
|
720
|
-
|
821
|
+
assert_modifiable!
|
721
822
|
@values.delete(scope)
|
722
823
|
when Hash
|
723
824
|
scope.each do |key, target_value|
|
@@ -1082,7 +1183,7 @@ module ActiveRecord
|
|
1082
1183
|
raise ArgumentError, "Relation passed to #or must be structurally compatible. Incompatible values: #{incompatible_values}"
|
1083
1184
|
end
|
1084
1185
|
|
1085
|
-
self.where_clause =
|
1186
|
+
self.where_clause = where_clause.or(other.where_clause)
|
1086
1187
|
self.having_clause = having_clause.or(other.having_clause)
|
1087
1188
|
self.references_values |= other.references_values
|
1088
1189
|
|
@@ -1453,6 +1554,9 @@ module ActiveRecord
|
|
1453
1554
|
# Post.excluding(post_one, post_two)
|
1454
1555
|
# # SELECT "posts".* FROM "posts" WHERE "posts"."id" NOT IN (1, 2)
|
1455
1556
|
#
|
1557
|
+
# Post.excluding(Post.drafts)
|
1558
|
+
# # SELECT "posts".* FROM "posts" WHERE "posts"."id" NOT IN (3, 4, 5)
|
1559
|
+
#
|
1456
1560
|
# This can also be called on associations. As with the above example, either
|
1457
1561
|
# a single record of collection thereof may be specified:
|
1458
1562
|
#
|
@@ -1468,14 +1572,15 @@ module ActiveRecord
|
|
1468
1572
|
# is passed in) are not instances of the same model that the relation is
|
1469
1573
|
# scoping.
|
1470
1574
|
def excluding(*records)
|
1575
|
+
relations = records.extract! { |element| element.is_a?(Relation) }
|
1471
1576
|
records.flatten!(1)
|
1472
1577
|
records.compact!
|
1473
1578
|
|
1474
|
-
unless records.all?(
|
1475
|
-
raise ArgumentError, "You must only pass a single or collection of #{
|
1579
|
+
unless records.all?(model) && relations.all? { |relation| relation.model == model }
|
1580
|
+
raise ArgumentError, "You must only pass a single or collection of #{model.name} objects to ##{__callee__}."
|
1476
1581
|
end
|
1477
1582
|
|
1478
|
-
spawn.excluding!(records)
|
1583
|
+
spawn.excluding!(records + relations.flat_map(&:ids))
|
1479
1584
|
end
|
1480
1585
|
alias :without :excluding
|
1481
1586
|
|
@@ -1487,12 +1592,12 @@ module ActiveRecord
|
|
1487
1592
|
|
1488
1593
|
# Returns the Arel object associated with the relation.
|
1489
1594
|
def arel(aliases = nil) # :nodoc:
|
1490
|
-
@arel ||= build_arel(aliases)
|
1595
|
+
@arel ||= with_connection { |c| build_arel(c, aliases) }
|
1491
1596
|
end
|
1492
1597
|
|
1493
1598
|
def construct_join_dependency(associations, join_type) # :nodoc:
|
1494
1599
|
ActiveRecord::Associations::JoinDependency.new(
|
1495
|
-
|
1600
|
+
model, table, associations, join_type
|
1496
1601
|
)
|
1497
1602
|
end
|
1498
1603
|
|
@@ -1508,16 +1613,28 @@ module ActiveRecord
|
|
1508
1613
|
def build_where_clause(opts, rest = []) # :nodoc:
|
1509
1614
|
opts = sanitize_forbidden_attributes(opts)
|
1510
1615
|
|
1616
|
+
if opts.is_a?(Array)
|
1617
|
+
opts, *rest = opts
|
1618
|
+
end
|
1619
|
+
|
1511
1620
|
case opts
|
1512
|
-
when String
|
1513
|
-
|
1621
|
+
when String
|
1622
|
+
if rest.empty?
|
1623
|
+
parts = [Arel.sql(opts)]
|
1624
|
+
elsif rest.first.is_a?(Hash) && /:\w+/.match?(opts)
|
1625
|
+
parts = [build_named_bound_sql_literal(opts, rest.first)]
|
1626
|
+
elsif opts.include?("?")
|
1627
|
+
parts = [build_bound_sql_literal(opts, rest)]
|
1628
|
+
else
|
1629
|
+
parts = [model.sanitize_sql(rest.empty? ? opts : [opts, *rest])]
|
1630
|
+
end
|
1514
1631
|
when Hash
|
1515
1632
|
opts = opts.transform_keys do |key|
|
1516
1633
|
if key.is_a?(Array)
|
1517
|
-
key.map { |k|
|
1634
|
+
key.map { |k| model.attribute_aliases[k.to_s] || k.to_s }
|
1518
1635
|
else
|
1519
1636
|
key = key.to_s
|
1520
|
-
|
1637
|
+
model.attribute_aliases[key] || key
|
1521
1638
|
end
|
1522
1639
|
end
|
1523
1640
|
references = PredicateBuilder.references(opts)
|
@@ -1541,11 +1658,67 @@ module ActiveRecord
|
|
1541
1658
|
self
|
1542
1659
|
end
|
1543
1660
|
|
1661
|
+
protected
|
1662
|
+
def arel_columns(columns)
|
1663
|
+
columns.flat_map do |field|
|
1664
|
+
case field
|
1665
|
+
when Symbol, String
|
1666
|
+
arel_column(field)
|
1667
|
+
when Proc
|
1668
|
+
field.call
|
1669
|
+
when Hash
|
1670
|
+
arel_columns_from_hash(field)
|
1671
|
+
else
|
1672
|
+
field
|
1673
|
+
end
|
1674
|
+
end
|
1675
|
+
end
|
1676
|
+
|
1544
1677
|
private
|
1545
1678
|
def async
|
1546
1679
|
spawn.async!
|
1547
1680
|
end
|
1548
1681
|
|
1682
|
+
def build_named_bound_sql_literal(statement, values)
|
1683
|
+
bound_values = values.transform_values do |value|
|
1684
|
+
if ActiveRecord::Relation === value
|
1685
|
+
Arel.sql(value.to_sql)
|
1686
|
+
elsif value.respond_to?(:map) && !value.acts_like?(:string)
|
1687
|
+
values = value.map { |v| v.respond_to?(:id_for_database) ? v.id_for_database : v }
|
1688
|
+
values.empty? ? nil : values
|
1689
|
+
else
|
1690
|
+
value = value.id_for_database if value.respond_to?(:id_for_database)
|
1691
|
+
value
|
1692
|
+
end
|
1693
|
+
end
|
1694
|
+
|
1695
|
+
begin
|
1696
|
+
Arel::Nodes::BoundSqlLiteral.new("(#{statement})", nil, bound_values)
|
1697
|
+
rescue Arel::BindError => error
|
1698
|
+
raise ActiveRecord::PreparedStatementInvalid, error.message
|
1699
|
+
end
|
1700
|
+
end
|
1701
|
+
|
1702
|
+
def build_bound_sql_literal(statement, values)
|
1703
|
+
bound_values = values.map do |value|
|
1704
|
+
if ActiveRecord::Relation === value
|
1705
|
+
Arel.sql(value.to_sql)
|
1706
|
+
elsif value.respond_to?(:map) && !value.acts_like?(:string)
|
1707
|
+
values = value.map { |v| v.respond_to?(:id_for_database) ? v.id_for_database : v }
|
1708
|
+
values.empty? ? nil : values
|
1709
|
+
else
|
1710
|
+
value = value.id_for_database if value.respond_to?(:id_for_database)
|
1711
|
+
value
|
1712
|
+
end
|
1713
|
+
end
|
1714
|
+
|
1715
|
+
begin
|
1716
|
+
Arel::Nodes::BoundSqlLiteral.new("(#{statement})", bound_values, nil)
|
1717
|
+
rescue Arel::BindError => error
|
1718
|
+
raise ActiveRecord::PreparedStatementInvalid, error.message
|
1719
|
+
end
|
1720
|
+
end
|
1721
|
+
|
1549
1722
|
def lookup_table_klass_from_join_dependencies(table_name)
|
1550
1723
|
each_join_dependencies do |join|
|
1551
1724
|
return join.base_klass if table_name == join.table_name
|
@@ -1570,12 +1743,11 @@ module ActiveRecord
|
|
1570
1743
|
)
|
1571
1744
|
end
|
1572
1745
|
|
1573
|
-
def
|
1574
|
-
raise
|
1575
|
-
raise ImmutableRelation if defined?(@arel) && @arel
|
1746
|
+
def assert_modifiable!
|
1747
|
+
raise UnmodifiableRelation if @loaded || @arel
|
1576
1748
|
end
|
1577
1749
|
|
1578
|
-
def build_arel(aliases = nil)
|
1750
|
+
def build_arel(connection, aliases = nil)
|
1579
1751
|
arel = Arel::SelectManager.new(table)
|
1580
1752
|
|
1581
1753
|
build_joins(arel.join_sources, aliases)
|
@@ -1674,7 +1846,7 @@ module ActiveRecord
|
|
1674
1846
|
|
1675
1847
|
joins = joins_values.dup
|
1676
1848
|
if joins.last.is_a?(ActiveRecord::Associations::JoinDependency)
|
1677
|
-
stashed_eager_load = joins.pop if joins.last.base_klass ==
|
1849
|
+
stashed_eager_load = joins.pop if joins.last.base_klass == model
|
1678
1850
|
end
|
1679
1851
|
|
1680
1852
|
joins.each_with_index do |join, i|
|
@@ -1731,8 +1903,8 @@ module ActiveRecord
|
|
1731
1903
|
def build_select(arel)
|
1732
1904
|
if select_values.any?
|
1733
1905
|
arel.project(*arel_columns(select_values))
|
1734
|
-
elsif
|
1735
|
-
arel.project(*
|
1906
|
+
elsif model.ignored_columns.any? || model.enumerate_columns_in_select_statements
|
1907
|
+
arel.project(*model.column_names.map { |field| table[field] })
|
1736
1908
|
else
|
1737
1909
|
arel.project(table[Arel.star])
|
1738
1910
|
end
|
@@ -1742,25 +1914,40 @@ module ActiveRecord
|
|
1742
1914
|
return if with_values.empty?
|
1743
1915
|
|
1744
1916
|
with_statements = with_values.map do |with_value|
|
1745
|
-
raise ArgumentError, "Unsupported argument type: #{with_value} #{with_value.class}" unless with_value.is_a?(Hash)
|
1746
|
-
|
1747
1917
|
build_with_value_from_hash(with_value)
|
1748
1918
|
end
|
1749
1919
|
|
1750
|
-
arel.with(with_statements)
|
1920
|
+
@with_is_recursive ? arel.with(:recursive, with_statements) : arel.with(with_statements)
|
1751
1921
|
end
|
1752
1922
|
|
1753
1923
|
def build_with_value_from_hash(hash)
|
1754
1924
|
hash.map do |name, value|
|
1755
|
-
|
1756
|
-
|
1757
|
-
|
1758
|
-
|
1759
|
-
|
1760
|
-
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1925
|
+
Arel::Nodes::TableAlias.new(build_with_expression_from_value(value), name)
|
1926
|
+
end
|
1927
|
+
end
|
1928
|
+
|
1929
|
+
def build_with_expression_from_value(value, nested = false)
|
1930
|
+
case value
|
1931
|
+
when Arel::Nodes::SqlLiteral then Arel::Nodes::Grouping.new(value)
|
1932
|
+
when ActiveRecord::Relation
|
1933
|
+
if nested
|
1934
|
+
value.arel.ast
|
1935
|
+
else
|
1936
|
+
value.arel
|
1937
|
+
end
|
1938
|
+
when Arel::SelectManager then value
|
1939
|
+
when Array
|
1940
|
+
return build_with_expression_from_value(value.first, false) if value.size == 1
|
1941
|
+
|
1942
|
+
parts = value.map do |query|
|
1943
|
+
build_with_expression_from_value(query, true)
|
1944
|
+
end
|
1945
|
+
|
1946
|
+
parts.reduce do |result, value|
|
1947
|
+
Arel::Nodes::UnionAll.new(result, value)
|
1948
|
+
end
|
1949
|
+
else
|
1950
|
+
raise ArgumentError, "Unsupported argument type: `#{value}` #{value.class}"
|
1764
1951
|
end
|
1765
1952
|
end
|
1766
1953
|
|
@@ -1768,46 +1955,60 @@ module ActiveRecord
|
|
1768
1955
|
with_table = Arel::Table.new(name)
|
1769
1956
|
|
1770
1957
|
table.join(with_table, kind).on(
|
1771
|
-
with_table[
|
1958
|
+
with_table[model.model_name.to_s.foreign_key].eq(table[model.primary_key])
|
1772
1959
|
).join_sources.first
|
1773
1960
|
end
|
1774
1961
|
|
1775
|
-
def
|
1776
|
-
|
1777
|
-
|
1778
|
-
|
1779
|
-
|
1780
|
-
|
1962
|
+
def arel_columns_from_hash(fields)
|
1963
|
+
fields.flat_map do |table_name, columns|
|
1964
|
+
table_name = table_name.name if table_name.is_a?(Symbol)
|
1965
|
+
case columns
|
1966
|
+
when Symbol, String
|
1967
|
+
arel_column_with_table(table_name, columns)
|
1968
|
+
when Array
|
1969
|
+
columns.map do |column|
|
1970
|
+
arel_column_with_table(table_name, column)
|
1781
1971
|
end
|
1782
|
-
when String
|
1783
|
-
arel_column(field, &:itself)
|
1784
|
-
when Proc
|
1785
|
-
field.call
|
1786
1972
|
else
|
1787
|
-
|
1973
|
+
raise TypeError, "Expected Symbol, String or Array, got: #{columns.class}"
|
1788
1974
|
end
|
1789
1975
|
end
|
1790
1976
|
end
|
1791
1977
|
|
1978
|
+
def arel_column_with_table(table_name, column_name)
|
1979
|
+
self.references_values |= [Arel.sql(table_name, retryable: true)]
|
1980
|
+
|
1981
|
+
if column_name.is_a?(Symbol) || !column_name.match?(/\W/)
|
1982
|
+
predicate_builder.resolve_arel_attribute(table_name, column_name) do
|
1983
|
+
lookup_table_klass_from_join_dependencies(table_name)
|
1984
|
+
end
|
1985
|
+
else
|
1986
|
+
Arel.sql("#{model.adapter_class.quote_table_name(table_name)}.#{column_name}")
|
1987
|
+
end
|
1988
|
+
end
|
1989
|
+
|
1792
1990
|
def arel_column(field)
|
1793
|
-
field =
|
1991
|
+
field = field.name if is_symbol = field.is_a?(Symbol)
|
1992
|
+
|
1993
|
+
field = model.attribute_aliases[field] || field.to_s
|
1794
1994
|
from = from_clause.name || from_clause.value
|
1795
1995
|
|
1796
|
-
if
|
1996
|
+
if model.columns_hash.key?(field) && (!from || table_name_matches?(from))
|
1797
1997
|
table[field]
|
1798
|
-
elsif
|
1799
|
-
table, column
|
1800
|
-
|
1801
|
-
lookup_table_klass_from_join_dependencies(table)
|
1802
|
-
end
|
1803
|
-
else
|
1998
|
+
elsif /\A(?<table>(?:\w+\.)?\w+)\.(?<column>\w+)\z/ =~ field
|
1999
|
+
arel_column_with_table(table, column)
|
2000
|
+
elsif block_given?
|
1804
2001
|
yield field
|
2002
|
+
elsif Arel.arel_node?(field)
|
2003
|
+
field
|
2004
|
+
else
|
2005
|
+
Arel.sql(is_symbol ? model.adapter_class.quote_table_name(field) : field)
|
1805
2006
|
end
|
1806
2007
|
end
|
1807
2008
|
|
1808
2009
|
def table_name_matches?(from)
|
1809
2010
|
table_name = Regexp.escape(table.name)
|
1810
|
-
quoted_table_name = Regexp.escape(
|
2011
|
+
quoted_table_name = Regexp.escape(model.adapter_class.quote_table_name(table.name))
|
1811
2012
|
/(?:\A|(?<!FROM)\s)(?:\b#{table_name}\b|#{quoted_table_name})(?!\.)/i.match?(from.to_s)
|
1812
2013
|
end
|
1813
2014
|
|
@@ -1863,7 +2064,9 @@ module ActiveRecord
|
|
1863
2064
|
args.each do |arg|
|
1864
2065
|
next unless arg.is_a?(Hash)
|
1865
2066
|
arg.each do |_key, value|
|
1866
|
-
|
2067
|
+
if value.is_a?(Hash)
|
2068
|
+
validate_order_args([value])
|
2069
|
+
elsif VALID_DIRECTIONS.exclude?(value)
|
1867
2070
|
raise ArgumentError,
|
1868
2071
|
"Direction \"#{value}\" is invalid. Valid directions are: #{VALID_DIRECTIONS.to_a.inspect}"
|
1869
2072
|
end
|
@@ -1871,10 +2074,14 @@ module ActiveRecord
|
|
1871
2074
|
end
|
1872
2075
|
end
|
1873
2076
|
|
2077
|
+
def flattened_args(args)
|
2078
|
+
args.flat_map { |e| (e.is_a?(Hash) || e.is_a?(Array)) ? flattened_args(e.to_a) : e }
|
2079
|
+
end
|
2080
|
+
|
1874
2081
|
def preprocess_order_args(order_args)
|
1875
|
-
|
1876
|
-
order_args
|
1877
|
-
permit:
|
2082
|
+
model.disallow_raw_sql!(
|
2083
|
+
flattened_args(order_args),
|
2084
|
+
permit: model.adapter_class.column_name_with_order_matcher
|
1878
2085
|
)
|
1879
2086
|
|
1880
2087
|
validate_order_args(order_args)
|
@@ -1888,14 +2095,20 @@ module ActiveRecord
|
|
1888
2095
|
when Symbol
|
1889
2096
|
order_column(arg.to_s).asc
|
1890
2097
|
when Hash
|
1891
|
-
arg.map
|
1892
|
-
|
1893
|
-
|
1894
|
-
|
2098
|
+
arg.map do |key, value|
|
2099
|
+
if value.is_a?(Hash)
|
2100
|
+
value.map do |field, dir|
|
2101
|
+
order_column([key.to_s, field.to_s].join(".")).public_send(dir.downcase)
|
2102
|
+
end
|
1895
2103
|
else
|
1896
|
-
|
2104
|
+
case key
|
2105
|
+
when Arel::Nodes::SqlLiteral, Arel::Nodes::Node, Arel::Attribute
|
2106
|
+
key.public_send(value.downcase)
|
2107
|
+
else
|
2108
|
+
order_column(key.to_s).public_send(value.downcase)
|
2109
|
+
end
|
1897
2110
|
end
|
1898
|
-
|
2111
|
+
end
|
1899
2112
|
else
|
1900
2113
|
arg
|
1901
2114
|
end
|
@@ -1904,7 +2117,7 @@ module ActiveRecord
|
|
1904
2117
|
|
1905
2118
|
def sanitize_order_arguments(order_args)
|
1906
2119
|
order_args.map! do |arg|
|
1907
|
-
|
2120
|
+
model.sanitize_sql_for_order(arg)
|
1908
2121
|
end
|
1909
2122
|
end
|
1910
2123
|
|
@@ -1930,7 +2143,7 @@ module ActiveRecord
|
|
1930
2143
|
arg.expr.relation.name
|
1931
2144
|
end
|
1932
2145
|
end
|
1933
|
-
end.
|
2146
|
+
end.filter_map { |ref| Arel.sql(ref, retryable: true) if ref }
|
1934
2147
|
end
|
1935
2148
|
|
1936
2149
|
def extract_table_name_from(string)
|
@@ -1942,17 +2155,18 @@ module ActiveRecord
|
|
1942
2155
|
if attr_name == "count" && !group_values.empty?
|
1943
2156
|
table[attr_name]
|
1944
2157
|
else
|
1945
|
-
Arel.sql(
|
2158
|
+
Arel.sql(model.adapter_class.quote_table_name(attr_name), retryable: true)
|
1946
2159
|
end
|
1947
2160
|
end
|
1948
2161
|
end
|
1949
2162
|
|
1950
|
-
def build_case_for_value_position(column, values)
|
2163
|
+
def build_case_for_value_position(column, values, filter: true)
|
1951
2164
|
node = Arel::Nodes::Case.new
|
1952
2165
|
values.each.with_index(1) do |value, order|
|
1953
2166
|
node.when(column.eq(value)).then(order)
|
1954
2167
|
end
|
1955
2168
|
|
2169
|
+
node = node.else(values.length + 1) unless filter
|
1956
2170
|
Arel::Nodes::Ascending.new(node)
|
1957
2171
|
end
|
1958
2172
|
|
@@ -2010,38 +2224,40 @@ module ActiveRecord
|
|
2010
2224
|
def process_select_args(fields)
|
2011
2225
|
fields.flat_map do |field|
|
2012
2226
|
if field.is_a?(Hash)
|
2013
|
-
|
2227
|
+
arel_column_aliases_from_hash(field)
|
2014
2228
|
else
|
2015
2229
|
field
|
2016
2230
|
end
|
2017
2231
|
end
|
2018
2232
|
end
|
2019
2233
|
|
2020
|
-
def
|
2234
|
+
def arel_column_aliases_from_hash(fields)
|
2021
2235
|
fields.flat_map do |key, columns_aliases|
|
2236
|
+
table_name = key.is_a?(Symbol) ? key.name : key
|
2022
2237
|
case columns_aliases
|
2023
2238
|
when Hash
|
2024
2239
|
columns_aliases.map do |column, column_alias|
|
2025
|
-
|
2026
|
-
|
2027
|
-
self.references_values |= references unless references.empty?
|
2028
|
-
end
|
2029
|
-
arel_column("#{key}.#{column}") do
|
2030
|
-
predicate_builder.resolve_arel_attribute(key.to_s, column)
|
2031
|
-
end.as(column_alias.to_s)
|
2240
|
+
arel_column_with_table(table_name, column)
|
2241
|
+
.as(model.adapter_class.quote_column_name(column_alias.to_s))
|
2032
2242
|
end
|
2033
2243
|
when Array
|
2034
2244
|
columns_aliases.map do |column|
|
2035
|
-
|
2245
|
+
arel_column_with_table(table_name, column)
|
2036
2246
|
end
|
2037
2247
|
when String, Symbol
|
2038
|
-
arel_column(key
|
2039
|
-
|
2040
|
-
end.as(columns_aliases.to_s)
|
2248
|
+
arel_column(key)
|
2249
|
+
.as(model.adapter_class.quote_column_name(columns_aliases.to_s))
|
2041
2250
|
end
|
2042
2251
|
end
|
2043
2252
|
end
|
2044
2253
|
|
2254
|
+
def process_with_args(args)
|
2255
|
+
args.flat_map do |arg|
|
2256
|
+
raise ArgumentError, "Unsupported argument type: #{arg} #{arg.class}" unless arg.is_a?(Hash)
|
2257
|
+
arg.map { |k, v| { k => v } }
|
2258
|
+
end
|
2259
|
+
end
|
2260
|
+
|
2045
2261
|
STRUCTURAL_VALUE_METHODS = (
|
2046
2262
|
Relation::VALUE_METHODS -
|
2047
2263
|
[:extending, :where, :having, :unscope, :references, :annotate, :optimizer_hints]
|