activerecord 5.2.6 → 6.1.3.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1038 -571
- data/MIT-LICENSE +3 -1
- data/README.rdoc +7 -5
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +13 -12
- data/lib/active_record/aggregations.rb +9 -8
- data/lib/active_record/association_relation.rb +30 -10
- data/lib/active_record/associations.rb +137 -25
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +95 -42
- data/lib/active_record/associations/association_scope.rb +23 -21
- data/lib/active_record/associations/belongs_to_association.rb +54 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -6
- data/lib/active_record/associations/builder/association.rb +45 -22
- data/lib/active_record/associations/builder/belongs_to.rb +29 -59
- data/lib/active_record/associations/builder/collection_association.rb +8 -17
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -2
- data/lib/active_record/associations/builder/has_one.rb +33 -2
- data/lib/active_record/associations/builder/singular_association.rb +3 -1
- data/lib/active_record/associations/collection_association.rb +31 -29
- data/lib/active_record/associations/collection_proxy.rb +25 -21
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +26 -13
- data/lib/active_record/associations/has_many_through_association.rb +24 -18
- data/lib/active_record/associations/has_one_association.rb +43 -31
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +91 -60
- data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
- data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
- data/lib/active_record/associations/preloader.rb +47 -34
- data/lib/active_record/associations/preloader/association.rb +71 -43
- data/lib/active_record/associations/preloader/through_association.rb +49 -40
- data/lib/active_record/associations/singular_association.rb +3 -17
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +17 -19
- data/lib/active_record/attribute_methods.rb +81 -143
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -40
- data/lib/active_record/attribute_methods/primary_key.rb +20 -25
- data/lib/active_record/attribute_methods/query.rb +4 -8
- data/lib/active_record/attribute_methods/read.rb +14 -56
- data/lib/active_record/attribute_methods/serialization.rb +12 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +18 -34
- data/lib/active_record/attributes.rb +46 -9
- data/lib/active_record/autosave_association.rb +57 -42
- data/lib/active_record/base.rb +4 -17
- data/lib/active_record/callbacks.rb +158 -43
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -90
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +385 -144
- data/lib/active_record/connection_adapters/abstract/transaction.rb +155 -68
- data/lib/active_record/connection_adapters/abstract_adapter.rb +228 -98
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
- data/lib/active_record/connection_adapters/column.rb +30 -12
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +86 -32
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +59 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +18 -7
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +38 -54
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -120
- data/lib/active_record/connection_adapters/schema_cache.rb +127 -21
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +19 -6
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +293 -33
- data/lib/active_record/core.rb +323 -97
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations.rb +272 -0
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +80 -0
- data/lib/active_record/database_configurations/hash_config.rb +96 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +111 -37
- data/lib/active_record/errors.rb +62 -19
- data/lib/active_record/explain.rb +10 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +32 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +200 -481
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +53 -24
- data/lib/active_record/insert_all.rb +208 -0
- data/lib/active_record/integration.rb +67 -17
- data/lib/active_record/internal_metadata.rb +26 -9
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +37 -23
- data/lib/active_record/locking/pessimistic.rb +9 -5
- data/lib/active_record/log_subscriber.rb +35 -35
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/migration.rb +206 -157
- data/lib/active_record/migration/command_recorder.rb +96 -44
- data/lib/active_record/migration/compatibility.rb +142 -64
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/model_schema.rb +148 -22
- data/lib/active_record/nested_attributes.rb +4 -7
- data/lib/active_record/no_touching.rb +8 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +267 -59
- data/lib/active_record/query_cache.rb +21 -4
- data/lib/active_record/querying.rb +40 -23
- data/lib/active_record/railtie.rb +115 -58
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +408 -78
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +109 -93
- data/lib/active_record/relation.rb +374 -104
- data/lib/active_record/relation/batches.rb +44 -35
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/calculations.rb +153 -90
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +64 -39
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +32 -40
- data/lib/active_record/relation/predicate_builder.rb +62 -45
- data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +475 -186
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +9 -9
- data/lib/active_record/relation/where_clause.rb +111 -61
- data/lib/active_record/result.rb +64 -38
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +22 -41
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +54 -9
- data/lib/active_record/schema_migration.rb +7 -9
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/scoping/default.rb +4 -6
- data/lib/active_record/scoping/named.rb +17 -24
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +49 -6
- data/lib/active_record/store.rb +88 -9
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -43
- data/lib/active_record/tasks/database_tasks.rb +277 -81
- data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
- data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +246 -0
- data/lib/active_record/timestamp.rb +43 -32
- data/lib/active_record/touch_later.rb +23 -22
- data/lib/active_record/transactions.rb +62 -118
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +10 -5
- data/lib/active_record/type/adapter_specific_registry.rb +3 -13
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type_caster/connection.rb +15 -15
- data/lib/active_record/type_caster/map.rb +8 -8
- data/lib/active_record/validations.rb +4 -3
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +38 -30
- data/lib/arel.rb +54 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -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.rb +70 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -0
- data/lib/arel/nodes/comment.rb +29 -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 +15 -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 +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -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 +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -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 +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -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_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration.rb +19 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +119 -34
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
- data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -16,10 +16,10 @@ module ActiveRecord
|
|
16
16
|
def exec_queries
|
17
17
|
QueryRegistry.reset
|
18
18
|
|
19
|
-
super.tap do
|
19
|
+
super.tap do |records|
|
20
20
|
if logger && warn_on_records_fetched_greater_than
|
21
|
-
if
|
22
|
-
logger.warn "Query fetched #{
|
21
|
+
if records.length > warn_on_records_fetched_greater_than
|
22
|
+
logger.warn "Query fetched #{records.size} #{@klass} records: #{QueryRegistry.queries.join(";")}"
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -8,7 +8,7 @@ module ActiveRecord
|
|
8
8
|
module SpawnMethods
|
9
9
|
# This is overridden by Associations::CollectionProxy
|
10
10
|
def spawn #:nodoc:
|
11
|
-
|
11
|
+
already_in_scope? ? klass.all : clone
|
12
12
|
end
|
13
13
|
|
14
14
|
# Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an ActiveRecord::Relation.
|
@@ -28,21 +28,22 @@ module ActiveRecord
|
|
28
28
|
# # => Post.where(published: true).joins(:comments)
|
29
29
|
#
|
30
30
|
# This is mainly intended for sharing common conditions between multiple associations.
|
31
|
-
def merge(other)
|
31
|
+
def merge(other, *rest)
|
32
32
|
if other.is_a?(Array)
|
33
33
|
records & other
|
34
34
|
elsif other
|
35
|
-
spawn.merge!(other)
|
35
|
+
spawn.merge!(other, *rest)
|
36
36
|
else
|
37
37
|
raise ArgumentError, "invalid argument: #{other.inspect}."
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
def merge!(other) # :nodoc:
|
41
|
+
def merge!(other, *rest) # :nodoc:
|
42
|
+
options = rest.extract_options!
|
42
43
|
if other.is_a?(Hash)
|
43
|
-
Relation::HashMerger.new(self, other).merge
|
44
|
+
Relation::HashMerger.new(self, other, options[:rewhere]).merge
|
44
45
|
elsif other.is_a?(Relation)
|
45
|
-
Relation::Merger.new(self, other).merge
|
46
|
+
Relation::Merger.new(self, other, options[:rewhere]).merge
|
46
47
|
elsif other.respond_to?(:to_proc)
|
47
48
|
instance_exec(&other)
|
48
49
|
else
|
@@ -67,10 +68,9 @@ module ActiveRecord
|
|
67
68
|
end
|
68
69
|
|
69
70
|
private
|
70
|
-
|
71
71
|
def relation_with(values)
|
72
|
-
result =
|
73
|
-
result.
|
72
|
+
result = spawn
|
73
|
+
result.instance_variable_set(:@values, values)
|
74
74
|
result
|
75
75
|
end
|
76
76
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/array/extract"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
class Relation
|
5
7
|
class WhereClause # :nodoc:
|
@@ -10,21 +12,25 @@ module ActiveRecord
|
|
10
12
|
end
|
11
13
|
|
12
14
|
def +(other)
|
13
|
-
WhereClause.new(
|
14
|
-
predicates + other.predicates,
|
15
|
-
)
|
15
|
+
WhereClause.new(predicates + other.predicates)
|
16
16
|
end
|
17
17
|
|
18
18
|
def -(other)
|
19
|
-
WhereClause.new(
|
20
|
-
predicates - other.predicates,
|
21
|
-
)
|
19
|
+
WhereClause.new(predicates - other.predicates)
|
22
20
|
end
|
23
21
|
|
24
|
-
def
|
25
|
-
WhereClause.new(
|
26
|
-
|
27
|
-
|
22
|
+
def |(other)
|
23
|
+
WhereClause.new(predicates | other.predicates)
|
24
|
+
end
|
25
|
+
|
26
|
+
def merge(other, rewhere = nil)
|
27
|
+
predicates = if rewhere
|
28
|
+
except_predicates(other.extract_attributes)
|
29
|
+
else
|
30
|
+
predicates_unreferenced_by(other)
|
31
|
+
end
|
32
|
+
|
33
|
+
WhereClause.new(predicates | other.predicates)
|
28
34
|
end
|
29
35
|
|
30
36
|
def except(*columns)
|
@@ -39,30 +45,31 @@ module ActiveRecord
|
|
39
45
|
if left.empty? || right.empty?
|
40
46
|
common
|
41
47
|
else
|
42
|
-
|
43
|
-
|
44
|
-
)
|
45
|
-
common + or_clause
|
46
|
-
end
|
47
|
-
end
|
48
|
+
left = left.ast
|
49
|
+
left = left.expr if left.is_a?(Arel::Nodes::Grouping)
|
48
50
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
right = right.ast
|
52
|
+
right = right.expr if right.is_a?(Arel::Nodes::Grouping)
|
53
|
+
|
54
|
+
or_clause = Arel::Nodes::Or.new(left, right)
|
55
|
+
|
56
|
+
common.predicates << Arel::Nodes::Grouping.new(or_clause)
|
57
|
+
common
|
55
58
|
end
|
59
|
+
end
|
56
60
|
|
57
|
-
|
61
|
+
def to_h(table_name = nil, equality_only: false)
|
62
|
+
equalities(predicates, equality_only).each_with_object({}) do |node, hash|
|
63
|
+
next if table_name&.!= node.left.relation.name
|
58
64
|
name = node.left.name.to_s
|
59
65
|
value = extract_node_value(node.right)
|
60
|
-
[name
|
61
|
-
|
66
|
+
hash[name] = value
|
67
|
+
end
|
62
68
|
end
|
63
69
|
|
64
70
|
def ast
|
65
|
-
|
71
|
+
predicates = predicates_with_wrapped_sql_literals
|
72
|
+
predicates.one? ? predicates.first : Arel::Nodes::And.new(predicates)
|
66
73
|
end
|
67
74
|
|
68
75
|
def ==(other)
|
@@ -71,34 +78,70 @@ module ActiveRecord
|
|
71
78
|
end
|
72
79
|
|
73
80
|
def invert
|
81
|
+
if predicates.size == 1
|
82
|
+
inverted_predicates = [ invert_predicate(predicates.first) ]
|
83
|
+
else
|
84
|
+
inverted_predicates = [ Arel::Nodes::Not.new(ast) ]
|
85
|
+
end
|
86
|
+
|
74
87
|
WhereClause.new(inverted_predicates)
|
75
88
|
end
|
76
89
|
|
77
90
|
def self.empty
|
78
|
-
@empty ||= new([])
|
91
|
+
@empty ||= new([]).freeze
|
79
92
|
end
|
80
93
|
|
81
|
-
|
94
|
+
def contradiction?
|
95
|
+
predicates.any? do |x|
|
96
|
+
case x
|
97
|
+
when Arel::Nodes::In
|
98
|
+
Array === x.right && x.right.empty?
|
99
|
+
when Arel::Nodes::Equality
|
100
|
+
x.right.respond_to?(:unboundable?) && x.right.unboundable?
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
82
104
|
|
105
|
+
def extract_attributes
|
106
|
+
predicates.each_with_object([]) do |node, attrs|
|
107
|
+
attr = extract_attribute(node) || begin
|
108
|
+
node.left if node.equality? && node.left.is_a?(Arel::Predications)
|
109
|
+
end
|
110
|
+
attrs << attr if attr
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
protected
|
83
115
|
attr_reader :predicates
|
84
116
|
|
85
117
|
def referenced_columns
|
86
|
-
|
87
|
-
|
88
|
-
|
118
|
+
predicates.each_with_object({}) do |node, hash|
|
119
|
+
attr = extract_attribute(node) || begin
|
120
|
+
node.left if equality_node?(node) && node.left.is_a?(Arel::Predications)
|
121
|
+
end
|
122
|
+
|
123
|
+
hash[attr] = node if attr
|
89
124
|
end
|
90
125
|
end
|
91
126
|
|
92
127
|
private
|
93
|
-
def
|
128
|
+
def extract_attribute(node)
|
129
|
+
attr_node = nil
|
130
|
+
Arel.fetch_attribute(node) do |attr|
|
131
|
+
return if attr_node&.!= attr # all attr nodes should be the same
|
132
|
+
attr_node = attr
|
133
|
+
end
|
134
|
+
attr_node
|
135
|
+
end
|
136
|
+
|
137
|
+
def equalities(predicates, equality_only)
|
94
138
|
equalities = []
|
95
139
|
|
96
140
|
predicates.each do |node|
|
97
|
-
|
98
|
-
when Arel::Nodes::Equality
|
141
|
+
if equality_only ? Arel::Nodes::Equality === node : equality_node?(node)
|
99
142
|
equalities << node
|
100
|
-
|
101
|
-
equalities.concat equalities(node.children)
|
143
|
+
elsif node.is_a?(Arel::Nodes::And)
|
144
|
+
equalities.concat equalities(node.children, equality_only)
|
102
145
|
end
|
103
146
|
end
|
104
147
|
|
@@ -106,40 +149,54 @@ module ActiveRecord
|
|
106
149
|
end
|
107
150
|
|
108
151
|
def predicates_unreferenced_by(other)
|
109
|
-
|
110
|
-
|
152
|
+
referenced_columns = other.referenced_columns
|
153
|
+
|
154
|
+
predicates.reject do |node|
|
155
|
+
attr = extract_attribute(node) || begin
|
156
|
+
node.left if equality_node?(node) && node.left.is_a?(Arel::Predications)
|
157
|
+
end
|
158
|
+
next false unless attr
|
159
|
+
|
160
|
+
ref = referenced_columns[attr]
|
161
|
+
next false unless ref
|
162
|
+
|
163
|
+
if equality_node?(node) && equality_node?(ref) || node == ref
|
164
|
+
true
|
165
|
+
else
|
166
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
167
|
+
Merging (#{node.to_sql}) and (#{ref.to_sql}) no longer maintain
|
168
|
+
both conditions, and will be replaced by the latter in Rails 6.2.
|
169
|
+
To migrate to Rails 6.2's behavior, use `relation.merge(other, rewhere: true)`.
|
170
|
+
MSG
|
171
|
+
false
|
172
|
+
end
|
111
173
|
end
|
112
174
|
end
|
113
175
|
|
114
176
|
def equality_node?(node)
|
115
|
-
node.
|
116
|
-
end
|
117
|
-
|
118
|
-
def inverted_predicates
|
119
|
-
predicates.map { |node| invert_predicate(node) }
|
177
|
+
!node.is_a?(String) && node.equality?
|
120
178
|
end
|
121
179
|
|
122
180
|
def invert_predicate(node)
|
123
181
|
case node
|
124
182
|
when NilClass
|
125
183
|
raise ArgumentError, "Invalid argument for .where.not(), got nil."
|
126
|
-
when Arel::Nodes::In
|
127
|
-
Arel::Nodes::NotIn.new(node.left, node.right)
|
128
|
-
when Arel::Nodes::Equality
|
129
|
-
Arel::Nodes::NotEqual.new(node.left, node.right)
|
130
184
|
when String
|
131
185
|
Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(node))
|
132
186
|
else
|
133
|
-
|
187
|
+
node.invert
|
134
188
|
end
|
135
189
|
end
|
136
190
|
|
137
191
|
def except_predicates(columns)
|
192
|
+
attrs = columns.extract! { |node| node.is_a?(Arel::Attribute) }
|
193
|
+
non_attrs = columns.extract! { |node| node.is_a?(Arel::Predications) }
|
194
|
+
|
138
195
|
predicates.reject do |node|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
columns.include?(
|
196
|
+
if !non_attrs.empty? && node.equality? && node.left.is_a?(Arel::Predications)
|
197
|
+
non_attrs.include?(node.left)
|
198
|
+
end || Arel.fetch_attribute(node) do |attr|
|
199
|
+
attrs.include?(attr) || columns.include?(attr.name.to_s)
|
143
200
|
end
|
144
201
|
end
|
145
202
|
end
|
@@ -170,15 +227,8 @@ module ActiveRecord
|
|
170
227
|
case node
|
171
228
|
when Array
|
172
229
|
node.map { |v| extract_node_value(v) }
|
173
|
-
when Arel::Nodes::Casted, Arel::Nodes::Quoted
|
174
|
-
node.
|
175
|
-
when Arel::Nodes::BindParam
|
176
|
-
value = node.value
|
177
|
-
if value.respond_to?(:value_before_type_cast)
|
178
|
-
value.value_before_type_cast
|
179
|
-
else
|
180
|
-
value
|
181
|
-
end
|
230
|
+
when Arel::Nodes::BindParam, Arel::Nodes::Casted, Arel::Nodes::Quoted
|
231
|
+
node.value_before_type_cast
|
182
232
|
end
|
183
233
|
end
|
184
234
|
end
|
data/lib/active_record/result.rb
CHANGED
@@ -21,7 +21,7 @@ module ActiveRecord
|
|
21
21
|
# ]
|
22
22
|
#
|
23
23
|
# # Get an array of hashes representing the result (column => value):
|
24
|
-
# result.
|
24
|
+
# result.to_a
|
25
25
|
# # => [{"id" => 1, "title" => "title_1", "body" => "body_1"},
|
26
26
|
# {"id" => 2, "title" => "title_2", "body" => "body_2"},
|
27
27
|
# ...
|
@@ -43,6 +43,11 @@ module ActiveRecord
|
|
43
43
|
@column_types = column_types
|
44
44
|
end
|
45
45
|
|
46
|
+
# Returns true if this result set includes the column named +name+
|
47
|
+
def includes_column?(name)
|
48
|
+
@columns.include? name
|
49
|
+
end
|
50
|
+
|
46
51
|
# Returns the number of elements in the rows array.
|
47
52
|
def length
|
48
53
|
@rows.length
|
@@ -60,13 +65,10 @@ module ActiveRecord
|
|
60
65
|
end
|
61
66
|
end
|
62
67
|
|
63
|
-
# Returns an array of hashes representing each row record.
|
64
|
-
def to_hash
|
65
|
-
hash_rows
|
66
|
-
end
|
67
|
-
|
68
68
|
alias :map! :map
|
69
69
|
alias :collect! :map
|
70
|
+
deprecate "map!": :map
|
71
|
+
deprecate "collect!": :map
|
70
72
|
|
71
73
|
# Returns true if there are no records, otherwise false.
|
72
74
|
def empty?
|
@@ -78,31 +80,41 @@ module ActiveRecord
|
|
78
80
|
hash_rows
|
79
81
|
end
|
80
82
|
|
83
|
+
alias :to_a :to_ary
|
84
|
+
|
81
85
|
def [](idx)
|
82
86
|
hash_rows[idx]
|
83
87
|
end
|
84
88
|
|
85
|
-
# Returns the first record from the rows collection.
|
86
|
-
# If the rows collection is empty, returns +nil+.
|
87
|
-
def first
|
88
|
-
return nil if @rows.empty?
|
89
|
-
Hash[@columns.zip(@rows.first)]
|
90
|
-
end
|
91
|
-
|
92
89
|
# Returns the last record from the rows collection.
|
93
|
-
|
94
|
-
|
95
|
-
return nil if @rows.empty?
|
96
|
-
Hash[@columns.zip(@rows.last)]
|
90
|
+
def last(n = nil)
|
91
|
+
n ? hash_rows.last(n) : hash_rows.last
|
97
92
|
end
|
98
93
|
|
99
94
|
def cast_values(type_overrides = {}) # :nodoc:
|
100
|
-
|
101
|
-
|
102
|
-
types.zip(values).map { |type, value| type.deserialize(value) }
|
103
|
-
end
|
95
|
+
if columns.one?
|
96
|
+
# Separated to avoid allocating an array per row
|
104
97
|
|
105
|
-
|
98
|
+
type = if type_overrides.is_a?(Array)
|
99
|
+
type_overrides.first
|
100
|
+
else
|
101
|
+
column_type(columns.first, type_overrides)
|
102
|
+
end
|
103
|
+
|
104
|
+
rows.map do |(value)|
|
105
|
+
type.deserialize(value)
|
106
|
+
end
|
107
|
+
else
|
108
|
+
types = if type_overrides.is_a?(Array)
|
109
|
+
type_overrides
|
110
|
+
else
|
111
|
+
columns.map { |name| column_type(name, type_overrides) }
|
112
|
+
end
|
113
|
+
|
114
|
+
rows.map do |values|
|
115
|
+
Array.new(values.size) { |i| types[i].deserialize(values[i]) }
|
116
|
+
end
|
117
|
+
end
|
106
118
|
end
|
107
119
|
|
108
120
|
def initialize_copy(other)
|
@@ -113,7 +125,6 @@ module ActiveRecord
|
|
113
125
|
end
|
114
126
|
|
115
127
|
private
|
116
|
-
|
117
128
|
def column_type(name, type_overrides = {})
|
118
129
|
type_overrides.fetch(name) do
|
119
130
|
column_types.fetch(name, Type.default_value)
|
@@ -125,23 +136,38 @@ module ActiveRecord
|
|
125
136
|
begin
|
126
137
|
# We freeze the strings to prevent them getting duped when
|
127
138
|
# used as keys in ActiveRecord::Base's @attributes hash
|
128
|
-
columns = @columns.map
|
139
|
+
columns = @columns.map(&:-@)
|
140
|
+
length = columns.length
|
141
|
+
template = nil
|
142
|
+
|
129
143
|
@rows.map { |row|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
144
|
+
if template
|
145
|
+
# We use transform_values to build subsequent rows from the
|
146
|
+
# hash of the first row. This is faster because we avoid any
|
147
|
+
# reallocs and in Ruby 2.7+ avoid hashing entirely.
|
148
|
+
index = -1
|
149
|
+
template.transform_values do
|
150
|
+
row[index += 1]
|
151
|
+
end
|
152
|
+
else
|
153
|
+
# In the past we used Hash[columns.zip(row)]
|
154
|
+
# though elegant, the verbose way is much more efficient
|
155
|
+
# both time and memory wise cause it avoids a big array allocation
|
156
|
+
# this method is called a lot and needs to be micro optimised
|
157
|
+
hash = {}
|
158
|
+
|
159
|
+
index = 0
|
160
|
+
while index < length
|
161
|
+
hash[columns[index]] = row[index]
|
162
|
+
index += 1
|
163
|
+
end
|
164
|
+
|
165
|
+
# It's possible to select the same column twice, in which case
|
166
|
+
# we can't use a template
|
167
|
+
template = hash if hash.length == length
|
168
|
+
|
169
|
+
hash
|
142
170
|
end
|
143
|
-
|
144
|
-
hash
|
145
171
|
}
|
146
172
|
end
|
147
173
|
end
|