activerecord 4.2.11.3 → 5.0.0
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 +1281 -1204
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record/aggregations.rb +35 -24
- data/lib/active_record/association_relation.rb +3 -3
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +11 -9
- data/lib/active_record/associations/association_scope.rb +73 -102
- data/lib/active_record/associations/belongs_to_association.rb +21 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +7 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +14 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +3 -10
- data/lib/active_record/associations/collection_association.rb +49 -41
- data/lib/active_record/associations/collection_proxy.rb +67 -27
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +20 -71
- data/lib/active_record/associations/has_many_through_association.rb +8 -47
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
- data/lib/active_record/associations/join_dependency.rb +29 -19
- data/lib/active_record/associations/preloader/association.rb +46 -52
- data/lib/active_record/associations/preloader/collection_association.rb +0 -6
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/through_association.rb +27 -14
- data/lib/active_record/associations/preloader.rb +14 -4
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +11 -3
- data/lib/active_record/associations.rb +317 -209
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +68 -18
- data/lib/active_record/attribute_assignment.rb +19 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +46 -86
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
- data/lib/active_record/attribute_methods/write.rb +13 -37
- data/lib/active_record/attribute_methods.rb +76 -47
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +6 -4
- data/lib/active_record/attribute_set.rb +30 -3
- data/lib/active_record/attributes.rb +199 -81
- data/lib/active_record/autosave_association.rb +49 -16
- data/lib/active_record/base.rb +32 -23
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +452 -182
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -61
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -10
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +380 -141
- data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +141 -59
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +401 -370
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +29 -166
- data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +10 -72
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -148
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +248 -160
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +149 -192
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +37 -14
- data/lib/active_record/core.rb +89 -107
- data/lib/active_record/counter_cache.rb +13 -24
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +113 -76
- data/lib/active_record/errors.rb +87 -48
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +76 -40
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +18 -2
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +15 -15
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +43 -21
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration.rb +363 -133
- data/lib/active_record/model_schema.rb +129 -41
- data/lib/active_record/nested_attributes.rb +58 -29
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +121 -80
- data/lib/active_record/query_cache.rb +15 -18
- data/lib/active_record/querying.rb +10 -9
- data/lib/active_record/railtie.rb +23 -16
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +69 -46
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +282 -115
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +139 -34
- data/lib/active_record/relation/calculations.rb +79 -108
- data/lib/active_record/relation/delegation.rb +7 -20
- data/lib/active_record/relation/finder_methods.rb +163 -81
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +16 -42
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +120 -107
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +308 -244
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -7
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/relation.rb +176 -116
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +95 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +62 -38
- data/lib/active_record/schema_migration.rb +11 -14
- data/lib/active_record/scoping/default.rb +23 -9
- data/lib/active_record/scoping/named.rb +49 -28
- data/lib/active_record/scoping.rb +32 -15
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +16 -14
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +57 -43
- data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +20 -9
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +138 -56
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -45
- data/lib/active_record/type/date_time.rb +2 -49
- data/lib/active_record/type/internal/abstract_json.rb +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +15 -14
- data/lib/active_record/type/time.rb +10 -16
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +30 -29
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record.rb +8 -4
- data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +59 -34
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- 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/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- 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 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decimal_without_scale.rb +0 -11
- 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 -59
- 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 -40
- data/lib/active_record/type/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -110
@@ -1,15 +1,13 @@
|
|
1
|
-
require 'set'
|
2
1
|
require 'active_support/concern'
|
3
|
-
require 'active_support/deprecation'
|
4
2
|
|
5
3
|
module ActiveRecord
|
6
4
|
module Delegation # :nodoc:
|
7
|
-
module DelegateCache
|
8
|
-
def relation_delegate_class(klass)
|
5
|
+
module DelegateCache # :nodoc:
|
6
|
+
def relation_delegate_class(klass)
|
9
7
|
@relation_delegate_cache[klass]
|
10
8
|
end
|
11
9
|
|
12
|
-
def initialize_relation_delegate_cache
|
10
|
+
def initialize_relation_delegate_cache
|
13
11
|
@relation_delegate_cache = cache = {}
|
14
12
|
[
|
15
13
|
ActiveRecord::Relation,
|
@@ -19,7 +17,7 @@ module ActiveRecord
|
|
19
17
|
delegate = Class.new(klass) {
|
20
18
|
include ClassSpecificRelation
|
21
19
|
}
|
22
|
-
const_set klass.name.gsub('::', '_'), delegate
|
20
|
+
const_set klass.name.gsub('::'.freeze, '_'.freeze), delegate
|
23
21
|
cache[klass] = delegate
|
24
22
|
end
|
25
23
|
end
|
@@ -37,13 +35,9 @@ module ActiveRecord
|
|
37
35
|
# may vary depending on the klass of a relation, so we create a subclass of Relation
|
38
36
|
# for each different klass, and the delegations are compiled into that subclass only.
|
39
37
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
:keep_if, :pop, :shift, :delete_at, :select!
|
44
|
-
].to_set # :nodoc:
|
45
|
-
|
46
|
-
delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join, to: :to_a
|
38
|
+
delegate :to_xml, :encode_with, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join,
|
39
|
+
:[], :&, :|, :+, :-, :sample, :reverse, :compact, :in_groups, :in_groups_of,
|
40
|
+
:shuffle, :split, to: :records
|
47
41
|
|
48
42
|
delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
|
49
43
|
:connection, :columns_hash, :to => :klass
|
@@ -115,21 +109,14 @@ module ActiveRecord
|
|
115
109
|
|
116
110
|
def respond_to?(method, include_private = false)
|
117
111
|
super || @klass.respond_to?(method, include_private) ||
|
118
|
-
array_delegable?(method) ||
|
119
112
|
arel.respond_to?(method, include_private)
|
120
113
|
end
|
121
114
|
|
122
115
|
protected
|
123
116
|
|
124
|
-
def array_delegable?(method)
|
125
|
-
Array.method_defined?(method) && BLACKLISTED_ARRAY_METHODS.exclude?(method)
|
126
|
-
end
|
127
|
-
|
128
117
|
def method_missing(method, *args, &block)
|
129
118
|
if @klass.respond_to?(method)
|
130
119
|
scoping { @klass.public_send(method, *args, &block) }
|
131
|
-
elsif array_delegable?(method)
|
132
|
-
to_a.public_send(method, *args, &block)
|
133
120
|
elsif arel.respond_to?(method)
|
134
121
|
arel.public_send(method, *args, &block)
|
135
122
|
else
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'active_support/deprecation'
|
2
1
|
require 'active_support/core_ext/string/filters'
|
3
2
|
|
4
3
|
module ActiveRecord
|
@@ -6,7 +5,7 @@ module ActiveRecord
|
|
6
5
|
ONE_AS_ONE = '1 AS one'
|
7
6
|
|
8
7
|
# Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
|
9
|
-
# If
|
8
|
+
# If one or more records can not be found for the requested ids, then RecordNotFound will be raised. If the primary key
|
10
9
|
# is an integer, find by id coerces its arguments using +to_i+.
|
11
10
|
#
|
12
11
|
# Person.find(1) # returns the object for ID = 1
|
@@ -17,10 +16,8 @@ module ActiveRecord
|
|
17
16
|
# Person.find([1]) # returns an array for the object with ID = 1
|
18
17
|
# Person.where("administrator = 1").order("created_on DESC").find(1)
|
19
18
|
#
|
20
|
-
# <tt>ActiveRecord::RecordNotFound</tt> will be raised if one or more ids are not found.
|
21
|
-
#
|
22
19
|
# NOTE: The returned records may not be in the same order as the ids you
|
23
|
-
# provide since database rows are unordered. You'd need to provide an explicit
|
20
|
+
# provide since database rows are unordered. You'd need to provide an explicit QueryMethods#order
|
24
21
|
# option if you want the results are sorted.
|
25
22
|
#
|
26
23
|
# ==== Find with lock
|
@@ -37,7 +34,7 @@ module ActiveRecord
|
|
37
34
|
# person.save!
|
38
35
|
# end
|
39
36
|
#
|
40
|
-
# ==== Variations of
|
37
|
+
# ==== Variations of #find
|
41
38
|
#
|
42
39
|
# Person.where(name: 'Spartacus', rating: 4)
|
43
40
|
# # returns a chainable list (which can be empty).
|
@@ -45,13 +42,13 @@ module ActiveRecord
|
|
45
42
|
# Person.find_by(name: 'Spartacus', rating: 4)
|
46
43
|
# # returns the first item or nil.
|
47
44
|
#
|
48
|
-
# Person.
|
45
|
+
# Person.find_or_initialize_by(name: 'Spartacus', rating: 4)
|
49
46
|
# # returns the first item or returns a new instance (requires you call .save to persist against the database).
|
50
47
|
#
|
51
|
-
# Person.
|
52
|
-
# # returns the first item or creates it and returns it
|
48
|
+
# Person.find_or_create_by(name: 'Spartacus', rating: 4)
|
49
|
+
# # returns the first item or creates it and returns it.
|
53
50
|
#
|
54
|
-
# ==== Alternatives for
|
51
|
+
# ==== Alternatives for #find
|
55
52
|
#
|
56
53
|
# Person.where(name: 'Spartacus', rating: 4).exists?(conditions = :none)
|
57
54
|
# # returns a boolean indicating if any record with the given conditions exist.
|
@@ -60,16 +57,13 @@ module ActiveRecord
|
|
60
57
|
# # returns a chainable list of instances with only the mentioned fields.
|
61
58
|
#
|
62
59
|
# Person.where(name: 'Spartacus', rating: 4).ids
|
63
|
-
# # returns an Array of ids
|
60
|
+
# # returns an Array of ids.
|
64
61
|
#
|
65
62
|
# Person.where(name: 'Spartacus', rating: 4).pluck(:field1, :field2)
|
66
|
-
# # returns an Array of the required fields
|
63
|
+
# # returns an Array of the required fields.
|
67
64
|
def find(*args)
|
68
|
-
if block_given?
|
69
|
-
|
70
|
-
else
|
71
|
-
find_with_ids(*args)
|
72
|
-
end
|
65
|
+
return super if block_given?
|
66
|
+
find_with_ids(*args)
|
73
67
|
end
|
74
68
|
|
75
69
|
# Finds the first record matching the specified conditions. There
|
@@ -80,18 +74,19 @@ module ActiveRecord
|
|
80
74
|
#
|
81
75
|
# Post.find_by name: 'Spartacus', rating: 4
|
82
76
|
# Post.find_by "published_at < ?", 2.weeks.ago
|
83
|
-
def find_by(*args)
|
84
|
-
where(*args).take
|
77
|
+
def find_by(arg, *args)
|
78
|
+
where(arg, *args).take
|
85
79
|
rescue RangeError
|
86
80
|
nil
|
87
81
|
end
|
88
82
|
|
89
|
-
# Like
|
90
|
-
# an
|
91
|
-
def find_by!(*args)
|
92
|
-
where(*args).take!
|
83
|
+
# Like #find_by, except that if no record is found, raises
|
84
|
+
# an ActiveRecord::RecordNotFound error.
|
85
|
+
def find_by!(arg, *args)
|
86
|
+
where(arg, *args).take!
|
93
87
|
rescue RangeError
|
94
|
-
raise RecordNotFound
|
88
|
+
raise RecordNotFound.new("Couldn't find #{@klass.name} with an out of range value",
|
89
|
+
@klass.name)
|
95
90
|
end
|
96
91
|
|
97
92
|
# Gives a record (or N records if a parameter is supplied) without any implied
|
@@ -105,10 +100,10 @@ module ActiveRecord
|
|
105
100
|
limit ? limit(limit).to_a : find_take
|
106
101
|
end
|
107
102
|
|
108
|
-
# Same as
|
109
|
-
# is found. Note that
|
103
|
+
# Same as #take but raises ActiveRecord::RecordNotFound if no record
|
104
|
+
# is found. Note that #take! accepts no arguments.
|
110
105
|
def take!
|
111
|
-
take or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql}]")
|
106
|
+
take or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
|
112
107
|
end
|
113
108
|
|
114
109
|
# Find the first record (or first N records if a parameter is supplied).
|
@@ -122,14 +117,14 @@ module ActiveRecord
|
|
122
117
|
#
|
123
118
|
def first(limit = nil)
|
124
119
|
if limit
|
125
|
-
|
120
|
+
find_nth_with_limit_and_offset(0, limit, offset: offset_index)
|
126
121
|
else
|
127
|
-
find_nth
|
122
|
+
find_nth 0
|
128
123
|
end
|
129
124
|
end
|
130
125
|
|
131
|
-
# Same as
|
132
|
-
# is found. Note that
|
126
|
+
# Same as #first but raises ActiveRecord::RecordNotFound if no record
|
127
|
+
# is found. Note that #first! accepts no arguments.
|
133
128
|
def first!
|
134
129
|
find_nth! 0
|
135
130
|
end
|
@@ -150,21 +145,27 @@ module ActiveRecord
|
|
150
145
|
#
|
151
146
|
# [#<Person id:4>, #<Person id:3>, #<Person id:2>]
|
152
147
|
def last(limit = nil)
|
153
|
-
if
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
148
|
+
return find_last(limit) if loaded? || limit_value
|
149
|
+
|
150
|
+
result = limit(limit || 1)
|
151
|
+
result.order!(arel_attribute(primary_key)) if order_values.empty? && primary_key
|
152
|
+
result = result.reverse_order!
|
153
|
+
|
154
|
+
limit ? result.reverse : result.first
|
155
|
+
rescue ActiveRecord::IrreversibleOrderError
|
156
|
+
ActiveSupport::Deprecation.warn(<<-WARNING.squish)
|
157
|
+
Finding a last element by loading the relation when SQL ORDER
|
158
|
+
can not be reversed is deprecated.
|
159
|
+
Rails 5.1 will raise ActiveRecord::IrreversibleOrderError in this case.
|
160
|
+
Please call `to_a.last` if you still want to load the relation.
|
161
|
+
WARNING
|
162
|
+
find_last(limit)
|
162
163
|
end
|
163
164
|
|
164
|
-
# Same as
|
165
|
-
# is found. Note that
|
165
|
+
# Same as #last but raises ActiveRecord::RecordNotFound if no record
|
166
|
+
# is found. Note that #last! accepts no arguments.
|
166
167
|
def last!
|
167
|
-
last or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql}]")
|
168
|
+
last or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
|
168
169
|
end
|
169
170
|
|
170
171
|
# Find the second record.
|
@@ -174,10 +175,10 @@ module ActiveRecord
|
|
174
175
|
# Person.offset(3).second # returns the second object from OFFSET 3 (which is OFFSET 4)
|
175
176
|
# Person.where(["user_name = :u", { u: user_name }]).second
|
176
177
|
def second
|
177
|
-
find_nth
|
178
|
+
find_nth 1
|
178
179
|
end
|
179
180
|
|
180
|
-
# Same as
|
181
|
+
# Same as #second but raises ActiveRecord::RecordNotFound if no record
|
181
182
|
# is found.
|
182
183
|
def second!
|
183
184
|
find_nth! 1
|
@@ -190,10 +191,10 @@ module ActiveRecord
|
|
190
191
|
# Person.offset(3).third # returns the third object from OFFSET 3 (which is OFFSET 5)
|
191
192
|
# Person.where(["user_name = :u", { u: user_name }]).third
|
192
193
|
def third
|
193
|
-
find_nth
|
194
|
+
find_nth 2
|
194
195
|
end
|
195
196
|
|
196
|
-
# Same as
|
197
|
+
# Same as #third but raises ActiveRecord::RecordNotFound if no record
|
197
198
|
# is found.
|
198
199
|
def third!
|
199
200
|
find_nth! 2
|
@@ -206,10 +207,10 @@ module ActiveRecord
|
|
206
207
|
# Person.offset(3).fourth # returns the fourth object from OFFSET 3 (which is OFFSET 6)
|
207
208
|
# Person.where(["user_name = :u", { u: user_name }]).fourth
|
208
209
|
def fourth
|
209
|
-
find_nth
|
210
|
+
find_nth 3
|
210
211
|
end
|
211
212
|
|
212
|
-
# Same as
|
213
|
+
# Same as #fourth but raises ActiveRecord::RecordNotFound if no record
|
213
214
|
# is found.
|
214
215
|
def fourth!
|
215
216
|
find_nth! 3
|
@@ -222,10 +223,10 @@ module ActiveRecord
|
|
222
223
|
# Person.offset(3).fifth # returns the fifth object from OFFSET 3 (which is OFFSET 7)
|
223
224
|
# Person.where(["user_name = :u", { u: user_name }]).fifth
|
224
225
|
def fifth
|
225
|
-
find_nth
|
226
|
+
find_nth 4
|
226
227
|
end
|
227
228
|
|
228
|
-
# Same as
|
229
|
+
# Same as #fifth but raises ActiveRecord::RecordNotFound if no record
|
229
230
|
# is found.
|
230
231
|
def fifth!
|
231
232
|
find_nth! 4
|
@@ -238,17 +239,49 @@ module ActiveRecord
|
|
238
239
|
# Person.offset(3).forty_two # returns the forty-second object from OFFSET 3 (which is OFFSET 44)
|
239
240
|
# Person.where(["user_name = :u", { u: user_name }]).forty_two
|
240
241
|
def forty_two
|
241
|
-
find_nth
|
242
|
+
find_nth 41
|
242
243
|
end
|
243
244
|
|
244
|
-
# Same as
|
245
|
+
# Same as #forty_two but raises ActiveRecord::RecordNotFound if no record
|
245
246
|
# is found.
|
246
247
|
def forty_two!
|
247
248
|
find_nth! 41
|
248
249
|
end
|
249
250
|
|
250
|
-
#
|
251
|
-
#
|
251
|
+
# Find the third-to-last record.
|
252
|
+
# If no order is defined it will order by primary key.
|
253
|
+
#
|
254
|
+
# Person.third_to_last # returns the third-to-last object fetched by SELECT * FROM people
|
255
|
+
# Person.offset(3).third_to_last # returns the third-to-last object from OFFSET 3
|
256
|
+
# Person.where(["user_name = :u", { u: user_name }]).third_to_last
|
257
|
+
def third_to_last
|
258
|
+
find_nth_from_last 3
|
259
|
+
end
|
260
|
+
|
261
|
+
# Same as #third_to_last but raises ActiveRecord::RecordNotFound if no record
|
262
|
+
# is found.
|
263
|
+
def third_to_last!
|
264
|
+
find_nth_from_last 3 or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
|
265
|
+
end
|
266
|
+
|
267
|
+
# Find the second-to-last record.
|
268
|
+
# If no order is defined it will order by primary key.
|
269
|
+
#
|
270
|
+
# Person.second_to_last # returns the second-to-last object fetched by SELECT * FROM people
|
271
|
+
# Person.offset(3).second_to_last # returns the second-to-last object from OFFSET 3
|
272
|
+
# Person.where(["user_name = :u", { u: user_name }]).second_to_last
|
273
|
+
def second_to_last
|
274
|
+
find_nth_from_last 2
|
275
|
+
end
|
276
|
+
|
277
|
+
# Same as #second_to_last but raises ActiveRecord::RecordNotFound if no record
|
278
|
+
# is found.
|
279
|
+
def second_to_last!
|
280
|
+
find_nth_from_last 2 or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
|
281
|
+
end
|
282
|
+
|
283
|
+
# Returns true if a record exists in the table that matches the +id+ or
|
284
|
+
# conditions given, or false otherwise. The argument can take six forms:
|
252
285
|
#
|
253
286
|
# * Integer - Finds the record with this primary key.
|
254
287
|
# * String - Finds the record with a primary key corresponding to this
|
@@ -261,7 +294,7 @@ module ActiveRecord
|
|
261
294
|
# * No args - Returns +false+ if the table is empty, +true+ otherwise.
|
262
295
|
#
|
263
296
|
# For more information about specifying conditions as a hash or array,
|
264
|
-
# see the Conditions section in the introduction to
|
297
|
+
# see the Conditions section in the introduction to ActiveRecord::Base.
|
265
298
|
#
|
266
299
|
# Note: You can't pass in a condition as a string (like <tt>name =
|
267
300
|
# 'Jamie'</tt>), since it would be sanitized and then queried against
|
@@ -279,7 +312,7 @@ module ActiveRecord
|
|
279
312
|
conditions = conditions.id
|
280
313
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
281
314
|
You are passing an instance of ActiveRecord::Base to `exists?`.
|
282
|
-
Please pass the id of the object by calling `.id
|
315
|
+
Please pass the id of the object by calling `.id`.
|
283
316
|
MSG
|
284
317
|
end
|
285
318
|
|
@@ -299,11 +332,11 @@ module ActiveRecord
|
|
299
332
|
end
|
300
333
|
end
|
301
334
|
|
302
|
-
connection.select_value(relation, "#{name} Exists", relation.
|
335
|
+
connection.select_value(relation, "#{name} Exists", relation.bound_attributes) ? true : false
|
303
336
|
end
|
304
337
|
|
305
338
|
# This method is called whenever no records are found with either a single
|
306
|
-
# id or multiple ids and raises
|
339
|
+
# id or multiple ids and raises an ActiveRecord::RecordNotFound exception.
|
307
340
|
#
|
308
341
|
# The error message is different depending on whether a single id or
|
309
342
|
# multiple ids are provided. If multiple ids are provided, then the number
|
@@ -311,7 +344,7 @@ module ActiveRecord
|
|
311
344
|
# the expected number of results should be provided in the +expected_size+
|
312
345
|
# argument.
|
313
346
|
def raise_record_not_found_exception!(ids, result_size, expected_size) #:nodoc:
|
314
|
-
conditions = arel.where_sql
|
347
|
+
conditions = arel.where_sql(@klass.arel_engine)
|
315
348
|
conditions = " [#{conditions}]" if conditions
|
316
349
|
|
317
350
|
if Array(ids).size == 1
|
@@ -353,7 +386,7 @@ module ActiveRecord
|
|
353
386
|
[]
|
354
387
|
else
|
355
388
|
arel = relation.arel
|
356
|
-
rows = connection.select_all(arel, 'SQL',
|
389
|
+
rows = connection.select_all(arel, 'SQL', relation.bound_attributes)
|
357
390
|
join_dependency.instantiate(rows, aliases)
|
358
391
|
end
|
359
392
|
end
|
@@ -385,7 +418,7 @@ module ActiveRecord
|
|
385
418
|
else
|
386
419
|
if relation.limit_value
|
387
420
|
limited_ids = limited_ids_for(relation)
|
388
|
-
limited_ids.empty? ? relation.none! : relation.where!(
|
421
|
+
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
389
422
|
end
|
390
423
|
relation.except(:limit, :offset)
|
391
424
|
end
|
@@ -398,12 +431,12 @@ module ActiveRecord
|
|
398
431
|
relation = relation.except(:select).select(values).distinct!
|
399
432
|
arel = relation.arel
|
400
433
|
|
401
|
-
id_rows = @klass.connection.select_all(arel, 'SQL',
|
434
|
+
id_rows = @klass.connection.select_all(arel, 'SQL', relation.bound_attributes)
|
402
435
|
id_rows.map {|row| row[primary_key]}
|
403
436
|
end
|
404
437
|
|
405
438
|
def using_limitable_reflections?(reflections)
|
406
|
-
reflections.none?
|
439
|
+
reflections.none?(&:collection?)
|
407
440
|
end
|
408
441
|
|
409
442
|
protected
|
@@ -434,7 +467,7 @@ module ActiveRecord
|
|
434
467
|
id = id.id
|
435
468
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
436
469
|
You are passing an instance of ActiveRecord::Base to `find`.
|
437
|
-
Please pass the id of the object by calling `.id
|
470
|
+
Please pass the id of the object by calling `.id`.
|
438
471
|
MSG
|
439
472
|
end
|
440
473
|
|
@@ -447,6 +480,8 @@ module ActiveRecord
|
|
447
480
|
end
|
448
481
|
|
449
482
|
def find_some(ids)
|
483
|
+
return find_some_ordered(ids) unless order_values.present?
|
484
|
+
|
450
485
|
result = where(primary_key => ids).to_a
|
451
486
|
|
452
487
|
expected_size =
|
@@ -468,49 +503,96 @@ module ActiveRecord
|
|
468
503
|
end
|
469
504
|
end
|
470
505
|
|
506
|
+
def find_some_ordered(ids)
|
507
|
+
ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
|
508
|
+
|
509
|
+
result = except(:limit, :offset).where(primary_key => ids).records
|
510
|
+
|
511
|
+
if result.size == ids.size
|
512
|
+
pk_type = @klass.type_for_attribute(primary_key)
|
513
|
+
|
514
|
+
records_by_id = result.index_by(&:id)
|
515
|
+
ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
|
516
|
+
else
|
517
|
+
raise_record_not_found_exception!(ids, result.size, ids.size)
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
471
521
|
def find_take
|
472
522
|
if loaded?
|
473
523
|
@records.first
|
474
524
|
else
|
475
|
-
@take ||= limit(1).
|
525
|
+
@take ||= limit(1).records.first
|
476
526
|
end
|
477
527
|
end
|
478
528
|
|
479
|
-
def find_nth(index, offset)
|
529
|
+
def find_nth(index, offset = nil)
|
530
|
+
# TODO: once the offset argument is removed we rely on offset_index
|
531
|
+
# within find_nth_with_limit, rather than pass it in via
|
532
|
+
# find_nth_with_limit_and_offset
|
533
|
+
if offset
|
534
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
535
|
+
Passing an offset argument to find_nth is deprecated,
|
536
|
+
please use Relation#offset instead.
|
537
|
+
MSG
|
538
|
+
end
|
480
539
|
if loaded?
|
481
540
|
@records[index]
|
482
541
|
else
|
483
|
-
offset
|
484
|
-
@offsets[offset] ||=
|
542
|
+
offset ||= offset_index
|
543
|
+
@offsets[offset + index] ||= find_nth_with_limit_and_offset(index, 1, offset: offset).first
|
485
544
|
end
|
486
545
|
end
|
487
546
|
|
488
547
|
def find_nth!(index)
|
489
|
-
find_nth(index
|
548
|
+
find_nth(index) or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
|
490
549
|
end
|
491
550
|
|
492
|
-
def find_nth_with_limit(
|
551
|
+
def find_nth_with_limit(index, limit)
|
552
|
+
# TODO: once the offset argument is removed from find_nth,
|
553
|
+
# find_nth_with_limit_and_offset can be merged into this method
|
493
554
|
relation = if order_values.empty? && primary_key
|
494
|
-
order(
|
555
|
+
order(arel_attribute(primary_key).asc)
|
495
556
|
else
|
496
557
|
self
|
497
558
|
end
|
498
559
|
|
499
|
-
relation = relation.offset(
|
560
|
+
relation = relation.offset(index) unless index.zero?
|
500
561
|
relation.limit(limit).to_a
|
501
562
|
end
|
502
563
|
|
503
|
-
def
|
564
|
+
def find_nth_from_last(index)
|
504
565
|
if loaded?
|
505
|
-
@records
|
566
|
+
@records[-index]
|
506
567
|
else
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
568
|
+
relation = if order_values.empty? && primary_key
|
569
|
+
order(arel_attribute(primary_key).asc)
|
570
|
+
else
|
571
|
+
self
|
572
|
+
end
|
573
|
+
|
574
|
+
relation.to_a[-index]
|
575
|
+
# TODO: can be made more performant on large result sets by
|
576
|
+
# for instance, last(index)[-index] (which would require
|
577
|
+
# refactoring the last(n) finder method to make test suite pass),
|
578
|
+
# or by using a combination of reverse_order, limit, and offset,
|
579
|
+
# e.g., reverse_order.offset(index-1).first
|
513
580
|
end
|
514
581
|
end
|
582
|
+
|
583
|
+
private
|
584
|
+
|
585
|
+
def find_nth_with_limit_and_offset(index, limit, offset:) # :nodoc:
|
586
|
+
if loaded?
|
587
|
+
@records[index, limit]
|
588
|
+
else
|
589
|
+
index += offset
|
590
|
+
find_nth_with_limit(index, limit)
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
def find_last(limit)
|
595
|
+
limit ? records.last(limit) : records.last
|
596
|
+
end
|
515
597
|
end
|
516
598
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Relation
|
3
|
+
class FromClause # :nodoc:
|
4
|
+
attr_reader :value, :name
|
5
|
+
|
6
|
+
def initialize(value, name)
|
7
|
+
@value = value
|
8
|
+
@name = name
|
9
|
+
end
|
10
|
+
|
11
|
+
def binds
|
12
|
+
if value.is_a?(Relation)
|
13
|
+
value.bound_attributes
|
14
|
+
else
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def merge(other)
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def empty?
|
24
|
+
value.nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.empty
|
28
|
+
@empty ||= new(nil, nil)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'active_support/core_ext/hash/keys'
|
2
|
-
require "set"
|
3
2
|
|
4
3
|
module ActiveRecord
|
5
4
|
class Relation
|
@@ -22,7 +21,7 @@ module ActiveRecord
|
|
22
21
|
# build a relation to merge in rather than directly merging
|
23
22
|
# the values.
|
24
23
|
def other
|
25
|
-
other = Relation.create(relation.klass, relation.table)
|
24
|
+
other = Relation.create(relation.klass, relation.table, relation.predicate_builder)
|
26
25
|
hash.each { |k, v|
|
27
26
|
if k == :joins
|
28
27
|
if Hash === v
|
@@ -49,10 +48,9 @@ module ActiveRecord
|
|
49
48
|
@other = other
|
50
49
|
end
|
51
50
|
|
52
|
-
NORMAL_VALUES = Relation::
|
53
|
-
Relation::
|
54
|
-
[:includes, :preload, :joins, :
|
55
|
-
|
51
|
+
NORMAL_VALUES = Relation::VALUE_METHODS -
|
52
|
+
Relation::CLAUSE_METHODS -
|
53
|
+
[:includes, :preload, :joins, :order, :reverse_order, :lock, :create_with, :reordering] # :nodoc:
|
56
54
|
|
57
55
|
def normal_values
|
58
56
|
NORMAL_VALUES
|
@@ -76,6 +74,7 @@ module ActiveRecord
|
|
76
74
|
|
77
75
|
merge_multi_values
|
78
76
|
merge_single_values
|
77
|
+
merge_clauses
|
79
78
|
merge_preloads
|
80
79
|
merge_joins
|
81
80
|
|
@@ -130,20 +129,6 @@ module ActiveRecord
|
|
130
129
|
end
|
131
130
|
|
132
131
|
def merge_multi_values
|
133
|
-
lhs_wheres = relation.where_values
|
134
|
-
rhs_wheres = other.where_values
|
135
|
-
|
136
|
-
lhs_binds = relation.bind_values
|
137
|
-
rhs_binds = other.bind_values
|
138
|
-
|
139
|
-
removed, kept = partition_overwrites(lhs_wheres, rhs_wheres)
|
140
|
-
|
141
|
-
where_values = kept + rhs_wheres
|
142
|
-
bind_values = filter_binds(lhs_binds, removed) + rhs_binds
|
143
|
-
|
144
|
-
relation.where_values = where_values
|
145
|
-
relation.bind_values = bind_values
|
146
|
-
|
147
132
|
if other.reordering_value
|
148
133
|
# override any order specified in the original relation
|
149
134
|
relation.reorder! other.order_values
|
@@ -156,36 +141,25 @@ module ActiveRecord
|
|
156
141
|
end
|
157
142
|
|
158
143
|
def merge_single_values
|
159
|
-
relation.
|
160
|
-
|
144
|
+
if relation.from_clause.empty?
|
145
|
+
relation.from_clause = other.from_clause
|
146
|
+
end
|
147
|
+
relation.lock_value ||= other.lock_value
|
161
148
|
|
162
149
|
unless other.create_with_value.blank?
|
163
150
|
relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value)
|
164
151
|
end
|
165
152
|
end
|
166
153
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
set = Set.new removed_wheres.map { |x| x.left.name.to_s }
|
171
|
-
lhs_binds.dup.delete_if { |col,_| set.include? col.name }
|
154
|
+
CLAUSE_METHOD_NAMES = CLAUSE_METHODS.map do |name|
|
155
|
+
["#{name}_clause", "#{name}_clause="]
|
172
156
|
end
|
173
157
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
return [[], lhs_wheres]
|
180
|
-
end
|
181
|
-
|
182
|
-
nodes = rhs_wheres.find_all do |w|
|
183
|
-
w.respond_to?(:operator) && w.operator == :==
|
184
|
-
end
|
185
|
-
seen = Set.new(nodes) { |node| node.left }
|
186
|
-
|
187
|
-
lhs_wheres.partition do |w|
|
188
|
-
w.respond_to?(:operator) && w.operator == :== && seen.include?(w.left)
|
158
|
+
def merge_clauses
|
159
|
+
CLAUSE_METHOD_NAMES.each do |(reader, writer)|
|
160
|
+
clause = relation.send(reader)
|
161
|
+
other_clause = other.send(reader)
|
162
|
+
relation.send(writer, clause.merge(other_clause))
|
189
163
|
end
|
190
164
|
end
|
191
165
|
end
|