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.
- 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
|