activerecord 4.2.0 → 5.2.8.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +640 -928
- data/MIT-LICENSE +2 -2
- data/README.rdoc +10 -11
- data/examples/performance.rb +32 -31
- data/examples/simple.rb +5 -4
- data/lib/active_record/aggregations.rb +264 -247
- data/lib/active_record/association_relation.rb +24 -6
- data/lib/active_record/associations/alias_tracker.rb +29 -35
- data/lib/active_record/associations/association.rb +87 -41
- data/lib/active_record/associations/association_scope.rb +106 -132
- data/lib/active_record/associations/belongs_to_association.rb +55 -36
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +29 -38
- data/lib/active_record/associations/builder/belongs_to.rb +77 -30
- data/lib/active_record/associations/builder/collection_association.rb +14 -23
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
- data/lib/active_record/associations/builder/has_many.rb +6 -4
- data/lib/active_record/associations/builder/has_one.rb +13 -6
- data/lib/active_record/associations/builder/singular_association.rb +15 -11
- data/lib/active_record/associations/collection_association.rb +145 -266
- data/lib/active_record/associations/collection_proxy.rb +242 -138
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +35 -75
- data/lib/active_record/associations/has_many_through_association.rb +51 -69
- data/lib/active_record/associations/has_one_association.rb +39 -24
- data/lib/active_record/associations/has_one_through_association.rb +18 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +40 -81
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
- data/lib/active_record/associations/join_dependency.rb +134 -154
- data/lib/active_record/associations/preloader/association.rb +85 -116
- data/lib/active_record/associations/preloader/through_association.rb +85 -74
- data/lib/active_record/associations/preloader.rb +83 -93
- data/lib/active_record/associations/singular_association.rb +27 -40
- data/lib/active_record/associations/through_association.rb +48 -23
- data/lib/active_record/associations.rb +1732 -1596
- data/lib/active_record/attribute_assignment.rb +58 -182
- data/lib/active_record/attribute_decorators.rb +39 -15
- data/lib/active_record/attribute_methods/before_type_cast.rb +12 -5
- data/lib/active_record/attribute_methods/dirty.rb +94 -125
- data/lib/active_record/attribute_methods/primary_key.rb +86 -71
- data/lib/active_record/attribute_methods/query.rb +4 -2
- data/lib/active_record/attribute_methods/read.rb +45 -63
- data/lib/active_record/attribute_methods/serialization.rb +40 -20
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -36
- data/lib/active_record/attribute_methods/write.rb +31 -46
- data/lib/active_record/attribute_methods.rb +170 -117
- data/lib/active_record/attributes.rb +201 -74
- data/lib/active_record/autosave_association.rb +118 -45
- data/lib/active_record/base.rb +60 -48
- data/lib/active_record/callbacks.rb +97 -57
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +37 -13
- data/lib/active_record/collection_cache_key.rb +53 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -217
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +617 -212
- data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
- data/lib/active_record/connection_adapters/column.rb +50 -41
- data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +42 -195
- data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -13
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +466 -280
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +439 -330
- data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -324
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +40 -27
- data/lib/active_record/core.rb +205 -202
- data/lib/active_record/counter_cache.rb +80 -37
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -105
- data/lib/active_record/enum.rb +136 -90
- data/lib/active_record/errors.rb +180 -52
- data/lib/active_record/explain.rb +23 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +35 -9
- data/lib/active_record/fixtures.rb +193 -135
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +148 -112
- data/lib/active_record/integration.rb +70 -28
- data/lib/active_record/internal_metadata.rb +45 -0
- data/lib/active_record/legacy_yaml_adapter.rb +48 -0
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +92 -98
- data/lib/active_record/locking/pessimistic.rb +15 -3
- data/lib/active_record/log_subscriber.rb +95 -33
- data/lib/active_record/migration/command_recorder.rb +133 -90
- data/lib/active_record/migration/compatibility.rb +217 -0
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/migration.rb +594 -267
- data/lib/active_record/model_schema.rb +292 -111
- data/lib/active_record/nested_attributes.rb +266 -214
- data/lib/active_record/no_touching.rb +8 -2
- data/lib/active_record/null_relation.rb +24 -37
- data/lib/active_record/persistence.rb +350 -119
- data/lib/active_record/query_cache.rb +13 -24
- data/lib/active_record/querying.rb +19 -17
- data/lib/active_record/railtie.rb +117 -35
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +9 -3
- data/lib/active_record/railties/databases.rake +160 -174
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +447 -288
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +204 -55
- data/lib/active_record/relation/calculations.rb +259 -244
- data/lib/active_record/relation/delegation.rb +67 -60
- data/lib/active_record/relation/finder_methods.rb +290 -253
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +91 -68
- data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/predicate_builder.rb +118 -92
- data/lib/active_record/relation/query_attribute.rb +45 -0
- data/lib/active_record/relation/query_methods.rb +446 -389
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +18 -16
- data/lib/active_record/relation/where_clause.rb +186 -0
- data/lib/active_record/relation/where_clause_factory.rb +34 -0
- data/lib/active_record/relation.rb +287 -339
- data/lib/active_record/result.rb +54 -36
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +155 -124
- data/lib/active_record/schema.rb +30 -24
- data/lib/active_record/schema_dumper.rb +91 -87
- data/lib/active_record/schema_migration.rb +19 -19
- data/lib/active_record/scoping/default.rb +102 -84
- data/lib/active_record/scoping/named.rb +81 -32
- data/lib/active_record/scoping.rb +45 -26
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +5 -5
- data/lib/active_record/statement_cache.rb +45 -35
- data/lib/active_record/store.rb +42 -36
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +82 -0
- data/lib/active_record/tasks/database_tasks.rb +136 -95
- data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
- data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
- data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
- data/lib/active_record/timestamp.rb +70 -38
- data/lib/active_record/touch_later.rb +64 -0
- data/lib/active_record/transactions.rb +208 -123
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +136 -0
- data/lib/active_record/type/date.rb +4 -41
- data/lib/active_record/type/date_time.rb +4 -38
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +30 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +11 -16
- data/lib/active_record/type/type_map.rb +15 -17
- data/lib/active_record/type/unsigned_integer.rb +9 -7
- data/lib/active_record/type.rb +79 -23
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +13 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +41 -32
- data/lib/active_record/validations.rb +38 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +36 -21
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -6
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
- data/lib/rails/generators/active_record/migration.rb +18 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +77 -53
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute.rb +0 -149
- data/lib/active_record/attribute_set/builder.rb +0 -86
- data/lib/active_record/attribute_set.rb +0 -77
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -30
- data/lib/active_record/type/decimal.rb +0 -40
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -55
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -36
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -101
- /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,6 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/relation/from_clause"
|
4
|
+
require "active_record/relation/query_attribute"
|
5
|
+
require "active_record/relation/where_clause"
|
6
|
+
require "active_record/relation/where_clause_factory"
|
7
|
+
require "active_model/forbidden_attributes_protection"
|
4
8
|
|
5
9
|
module ActiveRecord
|
6
10
|
module QueryMethods
|
@@ -11,6 +15,8 @@ module ActiveRecord
|
|
11
15
|
# WhereChain objects act as placeholder for queries in which #where does not have any parameter.
|
12
16
|
# In this case, #where must be chained with #not to return a new relation.
|
13
17
|
class WhereChain
|
18
|
+
include ActiveModel::ForbiddenAttributesProtection
|
19
|
+
|
14
20
|
def initialize(scope)
|
15
21
|
@scope = scope
|
16
22
|
end
|
@@ -18,7 +24,7 @@ module ActiveRecord
|
|
18
24
|
# Returns a new relation expressing WHERE + NOT condition according to
|
19
25
|
# the conditions in the arguments.
|
20
26
|
#
|
21
|
-
#
|
27
|
+
# #not accepts conditions as a string, array, or hash. See QueryMethods#where for
|
22
28
|
# more details on each format.
|
23
29
|
#
|
24
30
|
# User.where.not("name = 'Jon'")
|
@@ -39,73 +45,37 @@ module ActiveRecord
|
|
39
45
|
# User.where.not(name: "Jon", role: "admin")
|
40
46
|
# # SELECT * FROM users WHERE name != 'Jon' AND role != 'admin'
|
41
47
|
def not(opts, *rest)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
raise ArgumentError, 'Invalid argument for .where.not(), got nil.'
|
46
|
-
when Arel::Nodes::In
|
47
|
-
Arel::Nodes::NotIn.new(rel.left, rel.right)
|
48
|
-
when Arel::Nodes::Equality
|
49
|
-
Arel::Nodes::NotEqual.new(rel.left, rel.right)
|
50
|
-
when String
|
51
|
-
Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(rel))
|
52
|
-
else
|
53
|
-
Arel::Nodes::Not.new(rel)
|
54
|
-
end
|
55
|
-
end
|
48
|
+
opts = sanitize_forbidden_attributes(opts)
|
49
|
+
|
50
|
+
where_clause = @scope.send(:where_clause_factory).build(opts, rest)
|
56
51
|
|
57
52
|
@scope.references!(PredicateBuilder.references(opts)) if Hash === opts
|
58
|
-
@scope.
|
53
|
+
@scope.where_clause += where_clause.invert
|
59
54
|
@scope
|
60
55
|
end
|
61
56
|
end
|
62
57
|
|
63
|
-
|
64
|
-
|
65
|
-
def #{name}_values # def select_values
|
66
|
-
@values[:#{name}] || [] # @values[:select] || []
|
67
|
-
end # end
|
68
|
-
#
|
69
|
-
def #{name}_values=(values) # def select_values=(values)
|
70
|
-
raise ImmutableRelation if @loaded # raise ImmutableRelation if @loaded
|
71
|
-
check_cached_relation
|
72
|
-
@values[:#{name}] = values # @values[:select] = values
|
73
|
-
end # end
|
74
|
-
CODE
|
75
|
-
end
|
58
|
+
FROZEN_EMPTY_ARRAY = [].freeze
|
59
|
+
FROZEN_EMPTY_HASH = {}.freeze
|
76
60
|
|
77
|
-
|
61
|
+
Relation::VALUE_METHODS.each do |name|
|
62
|
+
method_name = \
|
63
|
+
case name
|
64
|
+
when *Relation::MULTI_VALUE_METHODS then "#{name}_values"
|
65
|
+
when *Relation::SINGLE_VALUE_METHODS then "#{name}_value"
|
66
|
+
when *Relation::CLAUSE_METHODS then "#{name}_clause"
|
67
|
+
end
|
78
68
|
class_eval <<-CODE, __FILE__, __LINE__ + 1
|
79
|
-
def #{
|
80
|
-
|
69
|
+
def #{method_name} # def includes_values
|
70
|
+
get_value(#{name.inspect}) # get_value(:includes)
|
81
71
|
end # end
|
82
|
-
CODE
|
83
|
-
end
|
84
72
|
|
85
|
-
|
86
|
-
|
87
|
-
def #{name}_value=(value) # def readonly_value=(value)
|
88
|
-
raise ImmutableRelation if @loaded # raise ImmutableRelation if @loaded
|
89
|
-
check_cached_relation
|
90
|
-
@values[:#{name}] = value # @values[:readonly] = value
|
73
|
+
def #{method_name}=(value) # def includes_values=(value)
|
74
|
+
set_value(#{name.inspect}, value) # set_value(:includes, value)
|
91
75
|
end # end
|
92
76
|
CODE
|
93
77
|
end
|
94
78
|
|
95
|
-
def check_cached_relation # :nodoc:
|
96
|
-
if defined?(@arel) && @arel
|
97
|
-
@arel = nil
|
98
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
99
|
-
Modifying already cached Relation. The cache will be reset. Use a
|
100
|
-
cloned Relation to prevent this warning.
|
101
|
-
MSG
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def create_with_value # :nodoc:
|
106
|
-
@values[:create_with] || {}
|
107
|
-
end
|
108
|
-
|
109
79
|
alias extensions extending_values
|
110
80
|
|
111
81
|
# Specify relationships to be included in the result set. For
|
@@ -118,7 +88,7 @@ module ActiveRecord
|
|
118
88
|
#
|
119
89
|
# allows you to access the +address+ attribute of the +User+ model without
|
120
90
|
# firing an additional query. This will often result in a
|
121
|
-
# performance improvement over a simple
|
91
|
+
# performance improvement over a simple join.
|
122
92
|
#
|
123
93
|
# You can also specify multiple relationships, like this:
|
124
94
|
#
|
@@ -139,7 +109,7 @@ module ActiveRecord
|
|
139
109
|
#
|
140
110
|
# User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
|
141
111
|
#
|
142
|
-
# Note that
|
112
|
+
# Note that #includes works with association names while #references needs
|
143
113
|
# the actual table name.
|
144
114
|
def includes(*args)
|
145
115
|
check_if_method_has_arguments!(:includes, args)
|
@@ -157,9 +127,9 @@ module ActiveRecord
|
|
157
127
|
# Forces eager loading by performing a LEFT OUTER JOIN on +args+:
|
158
128
|
#
|
159
129
|
# User.eager_load(:posts)
|
160
|
-
#
|
161
|
-
# FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" =
|
162
|
-
# "users"."id"
|
130
|
+
# # SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, ...
|
131
|
+
# # FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" =
|
132
|
+
# # "users"."id"
|
163
133
|
def eager_load(*args)
|
164
134
|
check_if_method_has_arguments!(:eager_load, args)
|
165
135
|
spawn.eager_load!(*args)
|
@@ -170,10 +140,10 @@ module ActiveRecord
|
|
170
140
|
self
|
171
141
|
end
|
172
142
|
|
173
|
-
# Allows preloading of +args+, in the same way that
|
143
|
+
# Allows preloading of +args+, in the same way that #includes does:
|
174
144
|
#
|
175
145
|
# User.preload(:posts)
|
176
|
-
#
|
146
|
+
# # SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (1, 2, 3)
|
177
147
|
def preload(*args)
|
178
148
|
check_if_method_has_arguments!(:preload, args)
|
179
149
|
spawn.preload!(*args)
|
@@ -186,14 +156,14 @@ module ActiveRecord
|
|
186
156
|
|
187
157
|
# Use to indicate that the given +table_names+ are referenced by an SQL string,
|
188
158
|
# and should therefore be JOINed in any query rather than loaded separately.
|
189
|
-
# This method only works in conjunction with
|
159
|
+
# This method only works in conjunction with #includes.
|
190
160
|
# See #includes for more details.
|
191
161
|
#
|
192
162
|
# User.includes(:posts).where("posts.name = 'foo'")
|
193
|
-
# #
|
163
|
+
# # Doesn't JOIN the posts table, resulting in an error.
|
194
164
|
#
|
195
165
|
# User.includes(:posts).where("posts.name = 'foo'").references(:posts)
|
196
|
-
# #
|
166
|
+
# # Query now knows the string references posts, so adds a JOIN
|
197
167
|
def references(*table_names)
|
198
168
|
check_if_method_has_arguments!(:references, table_names)
|
199
169
|
spawn.references!(*table_names)
|
@@ -209,12 +179,13 @@ module ActiveRecord
|
|
209
179
|
|
210
180
|
# Works in two unique ways.
|
211
181
|
#
|
212
|
-
# First: takes a block so it can be used just like Array#select
|
182
|
+
# First: takes a block so it can be used just like <tt>Array#select</tt>.
|
213
183
|
#
|
214
184
|
# Model.all.select { |m| m.field == value }
|
215
185
|
#
|
216
186
|
# This will build an array of objects from the database for the scope,
|
217
|
-
# converting them into an array and iterating through them using
|
187
|
+
# converting them into an array and iterating through them using
|
188
|
+
# <tt>Array#select</tt>.
|
218
189
|
#
|
219
190
|
# Second: Modifies the SELECT statement for the query so that only certain
|
220
191
|
# fields are retrieved:
|
@@ -242,24 +213,25 @@ module ActiveRecord
|
|
242
213
|
# # => "value"
|
243
214
|
#
|
244
215
|
# Accessing attributes of an object that do not have fields retrieved by a select
|
245
|
-
# except +id+ will throw
|
216
|
+
# except +id+ will throw ActiveModel::MissingAttributeError:
|
246
217
|
#
|
247
218
|
# Model.select(:field).first.other_field
|
248
219
|
# # => ActiveModel::MissingAttributeError: missing attribute: other_field
|
249
220
|
def select(*fields)
|
250
221
|
if block_given?
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
222
|
+
if fields.any?
|
223
|
+
raise ArgumentError, "`select' with block doesn't take arguments."
|
224
|
+
end
|
225
|
+
|
226
|
+
return super()
|
255
227
|
end
|
228
|
+
|
229
|
+
raise ArgumentError, "Call `select' with at least one field" if fields.empty?
|
230
|
+
spawn._select!(*fields)
|
256
231
|
end
|
257
232
|
|
258
233
|
def _select!(*fields) # :nodoc:
|
259
234
|
fields.flatten!
|
260
|
-
fields.map! do |field|
|
261
|
-
klass.attribute_alias?(field) ? klass.attribute_alias(field) : field
|
262
|
-
end
|
263
235
|
self.select_values += fields
|
264
236
|
self
|
265
237
|
end
|
@@ -267,22 +239,23 @@ module ActiveRecord
|
|
267
239
|
# Allows to specify a group attribute:
|
268
240
|
#
|
269
241
|
# User.group(:name)
|
270
|
-
#
|
242
|
+
# # SELECT "users".* FROM "users" GROUP BY name
|
271
243
|
#
|
272
244
|
# Returns an array with distinct records based on the +group+ attribute:
|
273
245
|
#
|
274
246
|
# User.select([:id, :name])
|
275
|
-
# => [#<User id: 1, name: "Oscar">, #<User id: 2, name: "Oscar">, #<User id: 3, name: "Foo">
|
247
|
+
# # => [#<User id: 1, name: "Oscar">, #<User id: 2, name: "Oscar">, #<User id: 3, name: "Foo">]
|
276
248
|
#
|
277
249
|
# User.group(:name)
|
278
|
-
# => [#<User id: 3, name: "Foo", ...>, #<User id: 2, name: "Oscar", ...>]
|
250
|
+
# # => [#<User id: 3, name: "Foo", ...>, #<User id: 2, name: "Oscar", ...>]
|
279
251
|
#
|
280
252
|
# User.group('name AS grouped_name, age')
|
281
|
-
# => [#<User id: 3, name: "Foo", age: 21, ...>, #<User id: 2, name: "Oscar", age: 21, ...>, #<User id: 5, name: "Foo", age: 23, ...>]
|
253
|
+
# # => [#<User id: 3, name: "Foo", age: 21, ...>, #<User id: 2, name: "Oscar", age: 21, ...>, #<User id: 5, name: "Foo", age: 23, ...>]
|
282
254
|
#
|
283
255
|
# Passing in an array of attributes to group by is also supported.
|
256
|
+
#
|
284
257
|
# User.select([:id, :first_name]).group(:id, :first_name).first(3)
|
285
|
-
# => [#<User id: 1, first_name: "Bill">, #<User id: 2, first_name: "Earl">, #<User id: 3, first_name: "Beto">]
|
258
|
+
# # => [#<User id: 1, first_name: "Bill">, #<User id: 2, first_name: "Earl">, #<User id: 3, first_name: "Beto">]
|
286
259
|
def group(*args)
|
287
260
|
check_if_method_has_arguments!(:group, args)
|
288
261
|
spawn.group!(*args)
|
@@ -298,27 +271,28 @@ module ActiveRecord
|
|
298
271
|
# Allows to specify an order attribute:
|
299
272
|
#
|
300
273
|
# User.order(:name)
|
301
|
-
#
|
274
|
+
# # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC
|
302
275
|
#
|
303
276
|
# User.order(email: :desc)
|
304
|
-
#
|
277
|
+
# # SELECT "users".* FROM "users" ORDER BY "users"."email" DESC
|
305
278
|
#
|
306
279
|
# User.order(:name, email: :desc)
|
307
|
-
#
|
280
|
+
# # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC
|
308
281
|
#
|
309
282
|
# User.order('name')
|
310
|
-
#
|
283
|
+
# # SELECT "users".* FROM "users" ORDER BY name
|
311
284
|
#
|
312
285
|
# User.order('name DESC')
|
313
|
-
#
|
286
|
+
# # SELECT "users".* FROM "users" ORDER BY name DESC
|
314
287
|
#
|
315
288
|
# User.order('name DESC, email')
|
316
|
-
#
|
289
|
+
# # SELECT "users".* FROM "users" ORDER BY name DESC, email
|
317
290
|
def order(*args)
|
318
291
|
check_if_method_has_arguments!(:order, args)
|
319
292
|
spawn.order!(*args)
|
320
293
|
end
|
321
294
|
|
295
|
+
# Same as #order but operates on relation in-place instead of copying.
|
322
296
|
def order!(*args) # :nodoc:
|
323
297
|
preprocess_order_args(args)
|
324
298
|
|
@@ -340,6 +314,7 @@ module ActiveRecord
|
|
340
314
|
spawn.reorder!(*args)
|
341
315
|
end
|
342
316
|
|
317
|
+
# Same as #reorder but operates on relation in-place instead of copying.
|
343
318
|
def reorder!(*args) # :nodoc:
|
344
319
|
preprocess_order_args(args)
|
345
320
|
|
@@ -349,8 +324,8 @@ module ActiveRecord
|
|
349
324
|
end
|
350
325
|
|
351
326
|
VALID_UNSCOPING_VALUES = Set.new([:where, :select, :group, :order, :lock,
|
352
|
-
:limit, :offset, :joins, :
|
353
|
-
:readonly, :having])
|
327
|
+
:limit, :offset, :joins, :left_outer_joins,
|
328
|
+
:includes, :from, :readonly, :having])
|
354
329
|
|
355
330
|
# Removes an unwanted relation that is already defined on a chain of relations.
|
356
331
|
# This is useful when passing around chains of relations and would like to
|
@@ -365,15 +340,15 @@ module ActiveRecord
|
|
365
340
|
# User.order('email DESC').select('id').where(name: "John")
|
366
341
|
# .unscope(:order, :select, :where) == User.all
|
367
342
|
#
|
368
|
-
# One can additionally pass a hash as an argument to unscope specific
|
343
|
+
# One can additionally pass a hash as an argument to unscope specific +:where+ values.
|
369
344
|
# This is done by passing a hash with a single key-value pair. The key should be
|
370
|
-
#
|
345
|
+
# +:where+ and the value should be the where value to unscope. For example:
|
371
346
|
#
|
372
347
|
# User.where(name: "John", active: true).unscope(where: :name)
|
373
348
|
# == User.where(active: true)
|
374
349
|
#
|
375
|
-
# This method is similar to
|
376
|
-
#
|
350
|
+
# This method is similar to #except, but unlike
|
351
|
+
# #except, it persists across merges:
|
377
352
|
#
|
378
353
|
# User.order('email').merge(User.except(:order))
|
379
354
|
# == User.order('email')
|
@@ -383,7 +358,7 @@ module ActiveRecord
|
|
383
358
|
#
|
384
359
|
# This means it can be used in association definitions:
|
385
360
|
#
|
386
|
-
# has_many :comments, -> { unscope
|
361
|
+
# has_many :comments, -> { unscope(where: :trashed) }
|
387
362
|
#
|
388
363
|
def unscope(*args)
|
389
364
|
check_if_method_has_arguments!(:unscope, args)
|
@@ -397,16 +372,19 @@ module ActiveRecord
|
|
397
372
|
args.each do |scope|
|
398
373
|
case scope
|
399
374
|
when Symbol
|
400
|
-
|
375
|
+
scope = :left_outer_joins if scope == :left_joins
|
376
|
+
if !VALID_UNSCOPING_VALUES.include?(scope)
|
377
|
+
raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
|
378
|
+
end
|
379
|
+
set_value(scope, DEFAULT_VALUES[scope])
|
401
380
|
when Hash
|
402
381
|
scope.each do |key, target_value|
|
403
382
|
if key != :where
|
404
383
|
raise ArgumentError, "Hash arguments in .unscope(*args) must have :where as the key."
|
405
384
|
end
|
406
385
|
|
407
|
-
Array(target_value).
|
408
|
-
|
409
|
-
end
|
386
|
+
target_values = Array(target_value).map(&:to_s)
|
387
|
+
self.where_clause = where_clause.except(*target_values)
|
410
388
|
end
|
411
389
|
else
|
412
390
|
raise ArgumentError, "Unrecognized scoping: #{args.inspect}. Use .unscope(where: :attribute_name) or .unscope(:order), for example."
|
@@ -416,15 +394,35 @@ module ActiveRecord
|
|
416
394
|
self
|
417
395
|
end
|
418
396
|
|
419
|
-
# Performs a joins on +args
|
397
|
+
# Performs a joins on +args+. The given symbol(s) should match the name of
|
398
|
+
# the association(s).
|
420
399
|
#
|
421
400
|
# User.joins(:posts)
|
422
|
-
#
|
401
|
+
# # SELECT "users".*
|
402
|
+
# # FROM "users"
|
403
|
+
# # INNER JOIN "posts" ON "posts"."user_id" = "users"."id"
|
404
|
+
#
|
405
|
+
# Multiple joins:
|
406
|
+
#
|
407
|
+
# User.joins(:posts, :account)
|
408
|
+
# # SELECT "users".*
|
409
|
+
# # FROM "users"
|
410
|
+
# # INNER JOIN "posts" ON "posts"."user_id" = "users"."id"
|
411
|
+
# # INNER JOIN "accounts" ON "accounts"."id" = "users"."account_id"
|
412
|
+
#
|
413
|
+
# Nested joins:
|
414
|
+
#
|
415
|
+
# User.joins(posts: [:comments])
|
416
|
+
# # SELECT "users".*
|
417
|
+
# # FROM "users"
|
418
|
+
# # INNER JOIN "posts" ON "posts"."user_id" = "users"."id"
|
419
|
+
# # INNER JOIN "comments" "comments_posts"
|
420
|
+
# # ON "comments_posts"."post_id" = "posts"."id"
|
423
421
|
#
|
424
422
|
# You can use strings in order to customize your joins:
|
425
423
|
#
|
426
424
|
# User.joins("LEFT JOIN bookmarks ON bookmarks.bookmarkable_type = 'Post' AND bookmarks.user_id = users.id")
|
427
|
-
#
|
425
|
+
# # SELECT "users".* FROM "users" LEFT JOIN bookmarks ON bookmarks.bookmarkable_type = 'Post' AND bookmarks.user_id = users.id
|
428
426
|
def joins(*args)
|
429
427
|
check_if_method_has_arguments!(:joins, args)
|
430
428
|
spawn.joins!(*args)
|
@@ -437,12 +435,21 @@ module ActiveRecord
|
|
437
435
|
self
|
438
436
|
end
|
439
437
|
|
440
|
-
|
441
|
-
|
438
|
+
# Performs a left outer joins on +args+:
|
439
|
+
#
|
440
|
+
# User.left_outer_joins(:posts)
|
441
|
+
# => SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
|
442
|
+
#
|
443
|
+
def left_outer_joins(*args)
|
444
|
+
check_if_method_has_arguments!(__callee__, args)
|
445
|
+
spawn.left_outer_joins!(*args)
|
442
446
|
end
|
447
|
+
alias :left_joins :left_outer_joins
|
443
448
|
|
444
|
-
def
|
445
|
-
|
449
|
+
def left_outer_joins!(*args) # :nodoc:
|
450
|
+
args.compact!
|
451
|
+
args.flatten!
|
452
|
+
self.left_outer_joins_values += args
|
446
453
|
self
|
447
454
|
end
|
448
455
|
|
@@ -489,7 +496,7 @@ module ActiveRecord
|
|
489
496
|
# than the previous methods; you are responsible for ensuring that the values in the template
|
490
497
|
# are properly quoted. The values are passed to the connector for quoting, but the caller
|
491
498
|
# is responsible for ensuring they are enclosed in quotes in the resulting SQL. After quoting,
|
492
|
-
# the values are inserted using the same escapes as the Ruby core method
|
499
|
+
# the values are inserted using the same escapes as the Ruby core method +Kernel::sprintf+.
|
493
500
|
#
|
494
501
|
# User.where(["name = '%s' and email = '%s'", "Joe", "joe@example.com"])
|
495
502
|
# # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com';
|
@@ -566,7 +573,7 @@ module ActiveRecord
|
|
566
573
|
# If the condition is any blank-ish object, then #where is a no-op and returns
|
567
574
|
# the current relation.
|
568
575
|
def where(opts = :chain, *rest)
|
569
|
-
if
|
576
|
+
if :chain == opts
|
570
577
|
WhereChain.new(spawn)
|
571
578
|
elsif opts.blank?
|
572
579
|
self
|
@@ -576,27 +583,61 @@ module ActiveRecord
|
|
576
583
|
end
|
577
584
|
|
578
585
|
def where!(opts, *rest) # :nodoc:
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
end
|
583
|
-
|
584
|
-
self.where_values += build_where(opts, rest)
|
586
|
+
opts = sanitize_forbidden_attributes(opts)
|
587
|
+
references!(PredicateBuilder.references(opts)) if Hash === opts
|
588
|
+
self.where_clause += where_clause_factory.build(opts, rest)
|
585
589
|
self
|
586
590
|
end
|
587
591
|
|
588
592
|
# Allows you to change a previously set where condition for a given attribute, instead of appending to that condition.
|
589
593
|
#
|
590
|
-
# Post.where(trashed: true).where(trashed: false)
|
591
|
-
#
|
592
|
-
# Post.where(active: true).where(trashed: true).rewhere(trashed: false) # => WHERE `active` = 1 AND `trashed` = 0
|
594
|
+
# Post.where(trashed: true).where(trashed: false)
|
595
|
+
# # WHERE `trashed` = 1 AND `trashed` = 0
|
593
596
|
#
|
594
|
-
#
|
595
|
-
#
|
597
|
+
# Post.where(trashed: true).rewhere(trashed: false)
|
598
|
+
# # WHERE `trashed` = 0
|
599
|
+
#
|
600
|
+
# Post.where(active: true).where(trashed: true).rewhere(trashed: false)
|
601
|
+
# # WHERE `active` = 1 AND `trashed` = 0
|
602
|
+
#
|
603
|
+
# This is short-hand for <tt>unscope(where: conditions.keys).where(conditions)</tt>.
|
604
|
+
# Note that unlike reorder, we're only unscoping the named conditions -- not the entire where statement.
|
596
605
|
def rewhere(conditions)
|
597
606
|
unscope(where: conditions.keys).where(conditions)
|
598
607
|
end
|
599
608
|
|
609
|
+
# Returns a new relation, which is the logical union of this relation and the one passed as an
|
610
|
+
# argument.
|
611
|
+
#
|
612
|
+
# The two relations must be structurally compatible: they must be scoping the same model, and
|
613
|
+
# they must differ only by #where (if no #group has been defined) or #having (if a #group is
|
614
|
+
# present). Neither relation may have a #limit, #offset, or #distinct set.
|
615
|
+
#
|
616
|
+
# Post.where("id = 1").or(Post.where("author_id = 3"))
|
617
|
+
# # SELECT `posts`.* FROM `posts` WHERE ((id = 1) OR (author_id = 3))
|
618
|
+
#
|
619
|
+
def or(other)
|
620
|
+
unless other.is_a? Relation
|
621
|
+
raise ArgumentError, "You have passed #{other.class.name} object to #or. Pass an ActiveRecord::Relation object instead."
|
622
|
+
end
|
623
|
+
|
624
|
+
spawn.or!(other)
|
625
|
+
end
|
626
|
+
|
627
|
+
def or!(other) # :nodoc:
|
628
|
+
incompatible_values = structurally_incompatible_values_for_or(other)
|
629
|
+
|
630
|
+
unless incompatible_values.empty?
|
631
|
+
raise ArgumentError, "Relation passed to #or must be structurally compatible. Incompatible values: #{incompatible_values}"
|
632
|
+
end
|
633
|
+
|
634
|
+
self.where_clause = self.where_clause.or(other.where_clause)
|
635
|
+
self.having_clause = having_clause.or(other.having_clause)
|
636
|
+
self.references_values += other.references_values
|
637
|
+
|
638
|
+
self
|
639
|
+
end
|
640
|
+
|
600
641
|
# Allows to specify a HAVING clause. Note that you can't use HAVING
|
601
642
|
# without also specifying a GROUP clause.
|
602
643
|
#
|
@@ -606,9 +647,10 @@ module ActiveRecord
|
|
606
647
|
end
|
607
648
|
|
608
649
|
def having!(opts, *rest) # :nodoc:
|
650
|
+
opts = sanitize_forbidden_attributes(opts)
|
609
651
|
references!(PredicateBuilder.references(opts)) if Hash === opts
|
610
652
|
|
611
|
-
self.
|
653
|
+
self.having_clause += having_clause_factory.build(opts, rest)
|
612
654
|
self
|
613
655
|
end
|
614
656
|
|
@@ -643,7 +685,7 @@ module ActiveRecord
|
|
643
685
|
end
|
644
686
|
|
645
687
|
# Specifies locking settings (default to +true+). For more information
|
646
|
-
# on locking, please see
|
688
|
+
# on locking, please see ActiveRecord::Locking.
|
647
689
|
def lock(locks = true)
|
648
690
|
spawn.lock!(locks)
|
649
691
|
end
|
@@ -674,7 +716,7 @@ module ActiveRecord
|
|
674
716
|
# For example:
|
675
717
|
#
|
676
718
|
# @posts = current_user.visible_posts.where(name: params[:name])
|
677
|
-
# #
|
719
|
+
# # the visible_posts method is expected to return a chainable Relation
|
678
720
|
#
|
679
721
|
# def visible_posts
|
680
722
|
# case role
|
@@ -688,7 +730,7 @@ module ActiveRecord
|
|
688
730
|
# end
|
689
731
|
#
|
690
732
|
def none
|
691
|
-
|
733
|
+
spawn.none!
|
692
734
|
end
|
693
735
|
|
694
736
|
def none! # :nodoc:
|
@@ -700,7 +742,7 @@ module ActiveRecord
|
|
700
742
|
#
|
701
743
|
# users = User.readonly
|
702
744
|
# users.first.save
|
703
|
-
# => ActiveRecord::ReadOnlyRecord:
|
745
|
+
# => ActiveRecord::ReadOnlyRecord: User is marked as readonly
|
704
746
|
def readonly(value = true)
|
705
747
|
spawn.readonly!(value)
|
706
748
|
end
|
@@ -719,7 +761,7 @@ module ActiveRecord
|
|
719
761
|
# users = users.create_with(name: 'DHH')
|
720
762
|
# users.new.name # => 'DHH'
|
721
763
|
#
|
722
|
-
# You can pass +nil+ to
|
764
|
+
# You can pass +nil+ to #create_with to reset attributes:
|
723
765
|
#
|
724
766
|
# users = users.create_with(nil)
|
725
767
|
# users.new.name # => 'Oscar'
|
@@ -732,7 +774,7 @@ module ActiveRecord
|
|
732
774
|
value = sanitize_forbidden_attributes(value)
|
733
775
|
self.create_with_value = create_with_value.merge(value)
|
734
776
|
else
|
735
|
-
self.create_with_value =
|
777
|
+
self.create_with_value = FROZEN_EMPTY_HASH
|
736
778
|
end
|
737
779
|
|
738
780
|
self
|
@@ -741,46 +783,44 @@ module ActiveRecord
|
|
741
783
|
# Specifies table from which the records will be fetched. For example:
|
742
784
|
#
|
743
785
|
# Topic.select('title').from('posts')
|
744
|
-
# #
|
786
|
+
# # SELECT title FROM posts
|
745
787
|
#
|
746
788
|
# Can accept other relation objects. For example:
|
747
789
|
#
|
748
790
|
# Topic.select('title').from(Topic.approved)
|
749
|
-
# #
|
791
|
+
# # SELECT title FROM (SELECT * FROM topics WHERE approved = 't') subquery
|
750
792
|
#
|
751
793
|
# Topic.select('a.title').from(Topic.approved, :a)
|
752
|
-
# #
|
794
|
+
# # SELECT a.title FROM (SELECT * FROM topics WHERE approved = 't') a
|
753
795
|
#
|
754
796
|
def from(value, subquery_name = nil)
|
755
797
|
spawn.from!(value, subquery_name)
|
756
798
|
end
|
757
799
|
|
758
800
|
def from!(value, subquery_name = nil) # :nodoc:
|
759
|
-
self.
|
801
|
+
self.from_clause = Relation::FromClause.new(value, subquery_name)
|
760
802
|
self
|
761
803
|
end
|
762
804
|
|
763
805
|
# Specifies whether the records should be unique or not. For example:
|
764
806
|
#
|
765
807
|
# User.select(:name)
|
766
|
-
# #
|
808
|
+
# # Might return two records with the same name
|
767
809
|
#
|
768
810
|
# User.select(:name).distinct
|
769
|
-
# #
|
811
|
+
# # Returns 1 record per distinct name
|
770
812
|
#
|
771
813
|
# User.select(:name).distinct.distinct(false)
|
772
|
-
# #
|
814
|
+
# # You can also remove the uniqueness
|
773
815
|
def distinct(value = true)
|
774
816
|
spawn.distinct!(value)
|
775
817
|
end
|
776
|
-
alias uniq distinct
|
777
818
|
|
778
819
|
# Like #distinct, but modifies relation in place.
|
779
820
|
def distinct!(value = true) # :nodoc:
|
780
821
|
self.distinct_value = value
|
781
822
|
self
|
782
823
|
end
|
783
|
-
alias uniq! distinct!
|
784
824
|
|
785
825
|
# Used to extend a scope with additional methods, either through
|
786
826
|
# a module or through a block provided.
|
@@ -850,327 +890,344 @@ module ActiveRecord
|
|
850
890
|
self
|
851
891
|
end
|
852
892
|
|
853
|
-
|
854
|
-
|
855
|
-
|
893
|
+
def skip_query_cache!(value = true) # :nodoc:
|
894
|
+
self.skip_query_cache_value = value
|
895
|
+
self
|
856
896
|
end
|
857
897
|
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
898
|
+
# Returns the Arel object associated with the relation.
|
899
|
+
def arel(aliases = nil) # :nodoc:
|
900
|
+
@arel ||= build_arel(aliases)
|
901
|
+
end
|
862
902
|
|
863
|
-
|
903
|
+
# Returns a relation value with a given name
|
904
|
+
def get_value(name) # :nodoc:
|
905
|
+
@values.fetch(name, DEFAULT_VALUES[name])
|
906
|
+
end
|
864
907
|
|
865
|
-
|
908
|
+
protected
|
866
909
|
|
867
|
-
|
910
|
+
# Sets the relation value with the given name
|
911
|
+
def set_value(name, value) # :nodoc:
|
912
|
+
assert_mutability!
|
913
|
+
@values[name] = value
|
914
|
+
end
|
868
915
|
|
869
|
-
|
870
|
-
arel.skip(offset_value.to_i) if offset_value
|
916
|
+
private
|
871
917
|
|
872
|
-
|
918
|
+
def assert_mutability!
|
919
|
+
raise ImmutableRelation if @loaded
|
920
|
+
raise ImmutableRelation if defined?(@arel) && @arel
|
921
|
+
end
|
873
922
|
|
874
|
-
|
923
|
+
def build_arel(aliases)
|
924
|
+
arel = Arel::SelectManager.new(table)
|
925
|
+
|
926
|
+
aliases = build_joins(arel, joins_values.flatten, aliases) unless joins_values.empty?
|
927
|
+
build_left_outer_joins(arel, left_outer_joins_values.flatten, aliases) unless left_outer_joins_values.empty?
|
928
|
+
|
929
|
+
arel.where(where_clause.ast) unless where_clause.empty?
|
930
|
+
arel.having(having_clause.ast) unless having_clause.empty?
|
931
|
+
if limit_value
|
932
|
+
limit_attribute = ActiveModel::Attribute.with_cast_value(
|
933
|
+
"LIMIT".freeze,
|
934
|
+
connection.sanitize_limit(limit_value),
|
935
|
+
Type.default_value,
|
936
|
+
)
|
937
|
+
arel.take(Arel::Nodes::BindParam.new(limit_attribute))
|
938
|
+
end
|
939
|
+
if offset_value
|
940
|
+
offset_attribute = ActiveModel::Attribute.with_cast_value(
|
941
|
+
"OFFSET".freeze,
|
942
|
+
offset_value.to_i,
|
943
|
+
Type.default_value,
|
944
|
+
)
|
945
|
+
arel.skip(Arel::Nodes::BindParam.new(offset_attribute))
|
946
|
+
end
|
947
|
+
arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty?
|
875
948
|
|
876
|
-
|
949
|
+
build_order(arel)
|
877
950
|
|
878
|
-
|
879
|
-
arel.from(build_from) if from_value
|
880
|
-
arel.lock(lock_value) if lock_value
|
951
|
+
build_select(arel)
|
881
952
|
|
882
|
-
|
883
|
-
|
953
|
+
arel.distinct(distinct_value)
|
954
|
+
arel.from(build_from) unless from_clause.empty?
|
955
|
+
arel.lock(lock_value) if lock_value
|
884
956
|
|
885
|
-
|
886
|
-
if !VALID_UNSCOPING_VALUES.include?(scope)
|
887
|
-
raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
|
957
|
+
arel
|
888
958
|
end
|
889
959
|
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
960
|
+
def build_from
|
961
|
+
opts = from_clause.value
|
962
|
+
name = from_clause.name
|
963
|
+
case opts
|
964
|
+
when Relation
|
965
|
+
if opts.eager_loading?
|
966
|
+
opts = opts.send(:apply_join_dependency)
|
967
|
+
end
|
968
|
+
name ||= "subquery"
|
969
|
+
opts.arel.as(name.to_s)
|
970
|
+
else
|
971
|
+
opts
|
972
|
+
end
|
900
973
|
end
|
901
974
|
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
subrelation.name == target_value
|
975
|
+
def build_left_outer_joins(manager, outer_joins, aliases)
|
976
|
+
buckets = outer_joins.group_by do |join|
|
977
|
+
case join
|
978
|
+
when Hash, Symbol, Array
|
979
|
+
:association_join
|
980
|
+
when ActiveRecord::Associations::JoinDependency
|
981
|
+
:stashed_join
|
982
|
+
else
|
983
|
+
raise ArgumentError, "only Hash, Symbol and Array are allowed"
|
984
|
+
end
|
913
985
|
end
|
986
|
+
|
987
|
+
build_join_query(manager, buckets, Arel::Nodes::OuterJoin, aliases)
|
914
988
|
end
|
915
989
|
|
916
|
-
|
917
|
-
|
990
|
+
def build_joins(manager, joins, aliases)
|
991
|
+
buckets = joins.group_by do |join|
|
992
|
+
case join
|
993
|
+
when String
|
994
|
+
:string_join
|
995
|
+
when Hash, Symbol, Array
|
996
|
+
:association_join
|
997
|
+
when ActiveRecord::Associations::JoinDependency
|
998
|
+
:stashed_join
|
999
|
+
when Arel::Nodes::Join
|
1000
|
+
:join_node
|
1001
|
+
else
|
1002
|
+
raise "unknown class: %s" % join.class.name
|
1003
|
+
end
|
1004
|
+
end
|
918
1005
|
|
919
|
-
|
920
|
-
|
1006
|
+
build_join_query(manager, buckets, Arel::Nodes::InnerJoin, aliases)
|
1007
|
+
end
|
921
1008
|
|
922
|
-
|
1009
|
+
def build_join_query(manager, buckets, join_type, aliases)
|
1010
|
+
buckets.default = []
|
923
1011
|
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
when String
|
929
|
-
join = Arel.sql(join)
|
930
|
-
end
|
931
|
-
table.create_string_join(join)
|
932
|
-
end
|
933
|
-
end
|
1012
|
+
association_joins = buckets[:association_join]
|
1013
|
+
stashed_joins = buckets[:stashed_join]
|
1014
|
+
join_nodes = buckets[:join_node].uniq
|
1015
|
+
string_joins = buckets[:string_join].map(&:strip).uniq
|
934
1016
|
|
935
|
-
|
936
|
-
|
937
|
-
next where if ::Arel::Nodes::Equality === where
|
938
|
-
where = Arel.sql(where) if String === where
|
939
|
-
Arel::Nodes::Grouping.new(where)
|
940
|
-
end
|
1017
|
+
join_list = join_nodes + convert_join_strings_to_ast(string_joins)
|
1018
|
+
alias_tracker = alias_tracker(join_list, aliases)
|
941
1019
|
|
942
|
-
|
943
|
-
|
1020
|
+
join_dependency = ActiveRecord::Associations::JoinDependency.new(
|
1021
|
+
klass, table, association_joins
|
1022
|
+
)
|
944
1023
|
|
945
|
-
|
946
|
-
|
947
|
-
when String, Array
|
948
|
-
[@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
|
949
|
-
when Hash
|
950
|
-
opts = PredicateBuilder.resolve_column_aliases(klass, opts)
|
1024
|
+
joins = join_dependency.join_constraints(stashed_joins, join_type, alias_tracker)
|
1025
|
+
joins.each { |join| manager.from(join) }
|
951
1026
|
|
952
|
-
|
953
|
-
self.bind_values += bind_values
|
1027
|
+
manager.join_sources.concat(join_list)
|
954
1028
|
|
955
|
-
|
956
|
-
|
1029
|
+
alias_tracker.aliases
|
1030
|
+
end
|
957
1031
|
|
958
|
-
|
959
|
-
|
960
|
-
|
1032
|
+
def convert_join_strings_to_ast(joins)
|
1033
|
+
joins
|
1034
|
+
.flatten
|
1035
|
+
.reject(&:blank?)
|
1036
|
+
.map { |join| table.create_string_join(Arel.sql(join)) }
|
961
1037
|
end
|
962
|
-
end
|
963
1038
|
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
1039
|
+
def build_select(arel)
|
1040
|
+
if select_values.any?
|
1041
|
+
arel.project(*arel_columns(select_values.uniq))
|
1042
|
+
elsif klass.ignored_columns.any?
|
1043
|
+
arel.project(*klass.column_names.map { |field| arel_attribute(field) })
|
969
1044
|
else
|
970
|
-
|
1045
|
+
arel.project(table[Arel.star])
|
971
1046
|
end
|
972
1047
|
end
|
973
1048
|
|
974
|
-
|
975
|
-
|
1049
|
+
def arel_columns(columns)
|
1050
|
+
columns.flat_map do |field|
|
1051
|
+
case field
|
1052
|
+
when Symbol
|
1053
|
+
arel_column(field.to_s) do |attr_name|
|
1054
|
+
connection.quote_table_name(attr_name)
|
1055
|
+
end
|
1056
|
+
when String
|
1057
|
+
arel_column(field, &:itself)
|
1058
|
+
when Proc
|
1059
|
+
field.call
|
1060
|
+
else
|
1061
|
+
field
|
1062
|
+
end
|
1063
|
+
end
|
976
1064
|
end
|
977
1065
|
|
978
|
-
|
979
|
-
|
1066
|
+
def arel_column(field)
|
1067
|
+
field = klass.attribute_alias(field) if klass.attribute_alias?(field)
|
1068
|
+
from = from_clause.name || from_clause.value
|
980
1069
|
|
981
|
-
|
982
|
-
|
983
|
-
|
1070
|
+
if klass.columns_hash.key?(field) && (!from || table_name_matches?(from))
|
1071
|
+
arel_attribute(field)
|
1072
|
+
else
|
1073
|
+
yield field
|
1074
|
+
end
|
984
1075
|
end
|
985
1076
|
|
986
|
-
|
987
|
-
|
988
|
-
association_new_opts, association_bind = association_relation.send(:create_binds, value)
|
989
|
-
new_opts[column] = association_new_opts
|
990
|
-
binds += association_bind
|
1077
|
+
def table_name_matches?(from)
|
1078
|
+
/(?:\A|(?<!FROM)\s)(?:\b#{table.name}\b|#{connection.quote_table_name(table.name)})(?!\.)/i.match?(from.to_s)
|
991
1079
|
end
|
992
1080
|
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
table_name = table_name.to_s
|
1000
|
-
@klass._reflect_on_association(table_name) ||
|
1001
|
-
@klass._reflect_on_association(table_name.singularize)
|
1002
|
-
end
|
1003
|
-
|
1004
|
-
def build_from
|
1005
|
-
opts, name = from_value
|
1006
|
-
case opts
|
1007
|
-
when Relation
|
1008
|
-
name ||= 'subquery'
|
1009
|
-
self.bind_values = opts.bind_values + self.bind_values
|
1010
|
-
opts.arel.as(name.to_s)
|
1011
|
-
else
|
1012
|
-
opts
|
1013
|
-
end
|
1014
|
-
end
|
1081
|
+
def reverse_sql_order(order_query)
|
1082
|
+
if order_query.empty?
|
1083
|
+
return [arel_attribute(primary_key).desc] if primary_key
|
1084
|
+
raise IrreversibleOrderError,
|
1085
|
+
"Relation has no current order and table has no primary key to be used as default order"
|
1086
|
+
end
|
1015
1087
|
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1088
|
+
order_query.flat_map do |o|
|
1089
|
+
case o
|
1090
|
+
when Arel::Attribute
|
1091
|
+
o.desc
|
1092
|
+
when Arel::Nodes::Ordering
|
1093
|
+
o.reverse
|
1094
|
+
when String
|
1095
|
+
if does_not_support_reverse?(o)
|
1096
|
+
raise IrreversibleOrderError, "Order #{o.inspect} can not be reversed automatically"
|
1097
|
+
end
|
1098
|
+
o.split(",").map! do |s|
|
1099
|
+
s.strip!
|
1100
|
+
s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || (s << " DESC")
|
1101
|
+
end
|
1102
|
+
else
|
1103
|
+
o
|
1104
|
+
end
|
1029
1105
|
end
|
1030
1106
|
end
|
1031
1107
|
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1108
|
+
def does_not_support_reverse?(order)
|
1109
|
+
# Account for String subclasses like Arel::Nodes::SqlLiteral that
|
1110
|
+
# override methods like #count.
|
1111
|
+
order = String.new(order) unless order.instance_of?(String)
|
1036
1112
|
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
join_list
|
1043
|
-
)
|
1113
|
+
# Uses SQL function with multiple arguments.
|
1114
|
+
(order.include?(",") && order.split(",").find { |section| section.count("(") != section.count(")") }) ||
|
1115
|
+
# Uses "nulls first" like construction.
|
1116
|
+
/nulls (first|last)\Z/i.match?(order)
|
1117
|
+
end
|
1044
1118
|
|
1045
|
-
|
1119
|
+
def build_order(arel)
|
1120
|
+
orders = order_values.uniq
|
1121
|
+
orders.reject!(&:blank?)
|
1046
1122
|
|
1047
|
-
|
1048
|
-
info.joins.each { |join| manager.from(join) }
|
1049
|
-
manager.bind_values.concat info.binds
|
1123
|
+
arel.order(*orders) unless orders.empty?
|
1050
1124
|
end
|
1051
1125
|
|
1052
|
-
|
1126
|
+
VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
|
1127
|
+
"asc", "desc", "ASC", "DESC"].to_set # :nodoc:
|
1053
1128
|
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
else
|
1063
|
-
field
|
1129
|
+
def validate_order_args(args)
|
1130
|
+
args.each do |arg|
|
1131
|
+
next unless arg.is_a?(Hash)
|
1132
|
+
arg.each do |_key, value|
|
1133
|
+
unless VALID_DIRECTIONS.include?(value)
|
1134
|
+
raise ArgumentError,
|
1135
|
+
"Direction \"#{value}\" is invalid. Valid directions are: #{VALID_DIRECTIONS.to_a.inspect}"
|
1136
|
+
end
|
1064
1137
|
end
|
1065
1138
|
end
|
1139
|
+
end
|
1066
1140
|
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1141
|
+
def preprocess_order_args(order_args)
|
1142
|
+
order_args.map! do |arg|
|
1143
|
+
klass.sanitize_sql_for_order(arg)
|
1144
|
+
end
|
1145
|
+
order_args.flatten!
|
1146
|
+
|
1147
|
+
@klass.enforce_raw_sql_whitelist(
|
1148
|
+
order_args.flat_map { |a| a.is_a?(Hash) ? a.keys : a },
|
1149
|
+
whitelist: AttributeMethods::ClassMethods::COLUMN_NAME_ORDER_WHITELIST
|
1150
|
+
)
|
1151
|
+
|
1152
|
+
validate_order_args(order_args)
|
1153
|
+
|
1154
|
+
references = order_args.grep(String)
|
1155
|
+
references.map! { |arg| arg =~ /^\W?(\w+)\W?\./ && $1 }.compact!
|
1156
|
+
references!(references) if references.any?
|
1157
|
+
|
1158
|
+
# if a symbol is given we prepend the quoted table name
|
1159
|
+
order_args.map! do |arg|
|
1160
|
+
case arg
|
1161
|
+
when Symbol
|
1162
|
+
order_column(arg.to_s).asc
|
1163
|
+
when Hash
|
1164
|
+
arg.map { |field, dir|
|
1165
|
+
case field
|
1166
|
+
when Arel::Nodes::SqlLiteral
|
1167
|
+
field.send(dir.downcase)
|
1168
|
+
else
|
1169
|
+
order_column(field.to_s).send(dir.downcase)
|
1170
|
+
end
|
1171
|
+
}
|
1172
|
+
else
|
1173
|
+
arg
|
1174
|
+
end
|
1175
|
+
end.flatten!
|
1070
1176
|
end
|
1071
|
-
end
|
1072
1177
|
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
o.reverse
|
1080
|
-
when String
|
1081
|
-
o.to_s.split(',').map! do |s|
|
1082
|
-
s.strip!
|
1083
|
-
s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC')
|
1178
|
+
def order_column(field)
|
1179
|
+
arel_column(field) do |attr_name|
|
1180
|
+
if attr_name == "count" && !group_values.empty?
|
1181
|
+
arel_attribute(attr_name)
|
1182
|
+
else
|
1183
|
+
Arel.sql(connection.quote_table_name(attr_name))
|
1084
1184
|
end
|
1085
|
-
else
|
1086
|
-
o
|
1087
1185
|
end
|
1088
1186
|
end
|
1089
|
-
end
|
1090
1187
|
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
raise ArgumentError, "
|
1110
|
-
"directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value)
|
1188
|
+
# Checks to make sure that the arguments are not blank. Note that if some
|
1189
|
+
# blank-like object were initially passed into the query method, then this
|
1190
|
+
# method will not raise an error.
|
1191
|
+
#
|
1192
|
+
# Example:
|
1193
|
+
#
|
1194
|
+
# Post.references() # raises an error
|
1195
|
+
# Post.references([]) # does not raise an error
|
1196
|
+
#
|
1197
|
+
# This particular method should be called with a method_name and the args
|
1198
|
+
# passed into that method as an input. For example:
|
1199
|
+
#
|
1200
|
+
# def references(*args)
|
1201
|
+
# check_if_method_has_arguments!("references", args)
|
1202
|
+
# ...
|
1203
|
+
# end
|
1204
|
+
def check_if_method_has_arguments!(method_name, args)
|
1205
|
+
if args.blank?
|
1206
|
+
raise ArgumentError, "The method .#{method_name}() must contain arguments."
|
1111
1207
|
end
|
1112
1208
|
end
|
1113
|
-
end
|
1114
|
-
|
1115
|
-
def preprocess_order_args(order_args)
|
1116
|
-
order_args.flatten!
|
1117
|
-
validate_order_args(order_args)
|
1118
|
-
|
1119
|
-
references = order_args.grep(String)
|
1120
|
-
references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
|
1121
|
-
references!(references) if references.any?
|
1122
1209
|
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
arg = klass.attribute_alias(arg) if klass.attribute_alias?(arg)
|
1128
|
-
table[arg].asc
|
1129
|
-
when Hash
|
1130
|
-
arg.map { |field, dir|
|
1131
|
-
field = klass.attribute_alias(field) if klass.attribute_alias?(field)
|
1132
|
-
table[field].send(dir.downcase)
|
1133
|
-
}
|
1134
|
-
else
|
1135
|
-
arg
|
1210
|
+
STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having, :unscope, :references]
|
1211
|
+
def structurally_incompatible_values_for_or(other)
|
1212
|
+
STRUCTURAL_OR_METHODS.reject do |method|
|
1213
|
+
get_value(method) == other.get_value(method)
|
1136
1214
|
end
|
1137
|
-
end
|
1138
|
-
end
|
1215
|
+
end
|
1139
1216
|
|
1140
|
-
|
1141
|
-
|
1142
|
-
# method will not raise an error.
|
1143
|
-
#
|
1144
|
-
# Example:
|
1145
|
-
#
|
1146
|
-
# Post.references() # => raises an error
|
1147
|
-
# Post.references([]) # => does not raise an error
|
1148
|
-
#
|
1149
|
-
# This particular method should be called with a method_name and the args
|
1150
|
-
# passed into that method as an input. For example:
|
1151
|
-
#
|
1152
|
-
# def references(*args)
|
1153
|
-
# check_if_method_has_arguments!("references", args)
|
1154
|
-
# ...
|
1155
|
-
# end
|
1156
|
-
def check_if_method_has_arguments!(method_name, args)
|
1157
|
-
if args.blank?
|
1158
|
-
raise ArgumentError, "The method .#{method_name}() must contain arguments."
|
1217
|
+
def where_clause_factory
|
1218
|
+
@where_clause_factory ||= Relation::WhereClauseFactory.new(klass, predicate_builder)
|
1159
1219
|
end
|
1160
|
-
|
1220
|
+
alias having_clause_factory where_clause_factory
|
1161
1221
|
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
end
|
1172
|
-
end
|
1222
|
+
DEFAULT_VALUES = {
|
1223
|
+
create_with: FROZEN_EMPTY_HASH,
|
1224
|
+
where: Relation::WhereClause.empty,
|
1225
|
+
having: Relation::WhereClause.empty,
|
1226
|
+
from: Relation::FromClause.empty
|
1227
|
+
}
|
1228
|
+
|
1229
|
+
Relation::MULTI_VALUE_METHODS.each do |value|
|
1230
|
+
DEFAULT_VALUES[value] ||= FROZEN_EMPTY_ARRAY
|
1173
1231
|
end
|
1174
|
-
end
|
1175
1232
|
end
|
1176
1233
|
end
|