activerecord 5.0.7 → 5.1.7
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 +657 -2080
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +28 -28
- data/examples/simple.rb +3 -3
- data/lib/active_record/aggregations.rb +244 -244
- data/lib/active_record/association_relation.rb +5 -5
- data/lib/active_record/associations/alias_tracker.rb +10 -11
- data/lib/active_record/associations/association.rb +23 -5
- data/lib/active_record/associations/association_scope.rb +95 -81
- data/lib/active_record/associations/belongs_to_association.rb +7 -4
- data/lib/active_record/associations/builder/belongs_to.rb +30 -16
- data/lib/active_record/associations/builder/collection_association.rb +1 -2
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
- data/lib/active_record/associations/collection_association.rb +36 -205
- data/lib/active_record/associations/collection_proxy.rb +132 -63
- data/lib/active_record/associations/has_many_association.rb +10 -19
- data/lib/active_record/associations/has_many_through_association.rb +12 -4
- data/lib/active_record/associations/has_one_association.rb +24 -28
- data/lib/active_record/associations/has_one_through_association.rb +5 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +4 -28
- data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +121 -118
- data/lib/active_record/associations/preloader/association.rb +64 -64
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
- data/lib/active_record/associations/preloader/collection_association.rb +6 -6
- data/lib/active_record/associations/preloader/has_many.rb +0 -2
- data/lib/active_record/associations/preloader/singular_association.rb +6 -8
- data/lib/active_record/associations/preloader/through_association.rb +41 -41
- data/lib/active_record/associations/preloader.rb +94 -94
- data/lib/active_record/associations/singular_association.rb +8 -25
- data/lib/active_record/associations/through_association.rb +2 -5
- data/lib/active_record/associations.rb +1591 -1562
- data/lib/active_record/attribute/user_provided_default.rb +4 -2
- data/lib/active_record/attribute.rb +98 -71
- data/lib/active_record/attribute_assignment.rb +61 -61
- data/lib/active_record/attribute_decorators.rb +35 -13
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
- data/lib/active_record/attribute_methods/dirty.rb +229 -46
- data/lib/active_record/attribute_methods/primary_key.rb +74 -73
- data/lib/active_record/attribute_methods/read.rb +39 -35
- data/lib/active_record/attribute_methods/serialization.rb +7 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
- data/lib/active_record/attribute_methods/write.rb +30 -33
- data/lib/active_record/attribute_methods.rb +56 -65
- data/lib/active_record/attribute_mutation_tracker.rb +63 -11
- data/lib/active_record/attribute_set/builder.rb +27 -33
- data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
- data/lib/active_record/attribute_set.rb +9 -6
- data/lib/active_record/attributes.rb +22 -22
- data/lib/active_record/autosave_association.rb +18 -13
- data/lib/active_record/base.rb +24 -22
- data/lib/active_record/callbacks.rb +56 -14
- data/lib/active_record/coders/yaml_column.rb +9 -11
- data/lib/active_record/collection_cache_key.rb +3 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +330 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +39 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -51
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +10 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +74 -79
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/abstract/transaction.rb +49 -43
- data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -135
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +404 -424
- data/lib/active_record/connection_adapters/column.rb +26 -4
- data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
- data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
- data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -28
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +7 -6
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +32 -53
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +0 -10
- data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +32 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
- data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -35
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +182 -222
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +6 -4
- data/lib/active_record/connection_adapters/postgresql/utils.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +198 -167
- data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -19
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +184 -167
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
- data/lib/active_record/connection_handling.rb +14 -26
- data/lib/active_record/core.rb +109 -93
- data/lib/active_record/counter_cache.rb +60 -13
- data/lib/active_record/define_callbacks.rb +20 -0
- data/lib/active_record/dynamic_matchers.rb +80 -79
- data/lib/active_record/enum.rb +8 -6
- data/lib/active_record/errors.rb +64 -15
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +7 -4
- data/lib/active_record/fixture_set/file.rb +11 -8
- data/lib/active_record/fixtures.rb +66 -53
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +93 -79
- data/lib/active_record/integration.rb +7 -7
- data/lib/active_record/internal_metadata.rb +3 -16
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +69 -74
- data/lib/active_record/locking/pessimistic.rb +10 -1
- data/lib/active_record/log_subscriber.rb +23 -28
- data/lib/active_record/migration/command_recorder.rb +94 -94
- data/lib/active_record/migration/compatibility.rb +100 -47
- data/lib/active_record/migration/join_table.rb +6 -6
- data/lib/active_record/migration.rb +153 -155
- data/lib/active_record/model_schema.rb +94 -107
- data/lib/active_record/nested_attributes.rb +200 -199
- data/lib/active_record/null_relation.rb +11 -34
- data/lib/active_record/persistence.rb +65 -50
- data/lib/active_record/query_cache.rb +2 -6
- data/lib/active_record/querying.rb +3 -4
- data/lib/active_record/railtie.rb +16 -17
- data/lib/active_record/railties/controller_runtime.rb +6 -2
- data/lib/active_record/railties/databases.rake +105 -133
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -2
- data/lib/active_record/reflection.rb +154 -108
- data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
- data/lib/active_record/relation/batches.rb +80 -51
- data/lib/active_record/relation/calculations.rb +169 -162
- data/lib/active_record/relation/delegation.rb +32 -31
- data/lib/active_record/relation/finder_methods.rb +197 -231
- data/lib/active_record/relation/merger.rb +58 -62
- data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
- data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder.rb +92 -89
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +255 -293
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +4 -5
- data/lib/active_record/relation/where_clause.rb +80 -65
- data/lib/active_record/relation/where_clause_factory.rb +47 -8
- data/lib/active_record/relation.rb +93 -119
- data/lib/active_record/result.rb +41 -32
- data/lib/active_record/runtime_registry.rb +3 -3
- data/lib/active_record/sanitization.rb +176 -192
- data/lib/active_record/schema.rb +3 -3
- data/lib/active_record/schema_dumper.rb +15 -38
- data/lib/active_record/schema_migration.rb +8 -4
- data/lib/active_record/scoping/default.rb +90 -90
- data/lib/active_record/scoping/named.rb +11 -11
- data/lib/active_record/scoping.rb +6 -6
- data/lib/active_record/secure_token.rb +2 -2
- data/lib/active_record/statement_cache.rb +13 -15
- data/lib/active_record/store.rb +31 -32
- data/lib/active_record/suppressor.rb +2 -1
- data/lib/active_record/table_metadata.rb +9 -5
- data/lib/active_record/tasks/database_tasks.rb +65 -55
- data/lib/active_record/tasks/mysql_database_tasks.rb +76 -73
- data/lib/active_record/tasks/postgresql_database_tasks.rb +72 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
- data/lib/active_record/timestamp.rb +46 -25
- data/lib/active_record/touch_later.rb +1 -2
- data/lib/active_record/transactions.rb +97 -109
- data/lib/active_record/type/adapter_specific_registry.rb +46 -42
- data/lib/active_record/type/decimal_without_scale.rb +13 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
- data/lib/active_record/type/internal/abstract_json.rb +4 -0
- data/lib/active_record/type/serialized.rb +14 -8
- data/lib/active_record/type/text.rb +9 -0
- data/lib/active_record/type/time.rb +0 -1
- data/lib/active_record/type/type_map.rb +11 -15
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type.rb +17 -13
- data/lib/active_record/type_caster/connection.rb +8 -6
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.rb +2 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +8 -39
- data/lib/active_record/validations.rb +4 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +20 -20
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
- data/lib/rails/generators/active_record/migration.rb +1 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
- data/lib/rails/generators/active_record.rb +4 -4
- metadata +24 -13
- data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
data/lib/active_record/result.rb
CHANGED
@@ -32,8 +32,6 @@ module ActiveRecord
|
|
32
32
|
class Result
|
33
33
|
include Enumerable
|
34
34
|
|
35
|
-
IDENTITY_TYPE = Type::Value.new # :nodoc:
|
36
|
-
|
37
35
|
attr_reader :columns, :rows, :column_types
|
38
36
|
|
39
37
|
def initialize(columns, rows, column_types = {})
|
@@ -43,10 +41,15 @@ module ActiveRecord
|
|
43
41
|
@column_types = column_types
|
44
42
|
end
|
45
43
|
|
44
|
+
# Returns the number of elements in the rows array.
|
46
45
|
def length
|
47
46
|
@rows.length
|
48
47
|
end
|
49
48
|
|
49
|
+
# Calls the given block once for each element in row collection, passing
|
50
|
+
# row as parameter.
|
51
|
+
#
|
52
|
+
# Returns an +Enumerator+ if no block is given.
|
50
53
|
def each
|
51
54
|
if block_given?
|
52
55
|
hash_rows.each { |row| yield row }
|
@@ -55,6 +58,7 @@ module ActiveRecord
|
|
55
58
|
end
|
56
59
|
end
|
57
60
|
|
61
|
+
# Returns an array of hashes representing each row record.
|
58
62
|
def to_hash
|
59
63
|
hash_rows
|
60
64
|
end
|
@@ -62,11 +66,12 @@ module ActiveRecord
|
|
62
66
|
alias :map! :map
|
63
67
|
alias :collect! :map
|
64
68
|
|
65
|
-
# Returns true if there are no records.
|
69
|
+
# Returns true if there are no records, otherwise false.
|
66
70
|
def empty?
|
67
71
|
rows.empty?
|
68
72
|
end
|
69
73
|
|
74
|
+
# Returns an array of hashes representing each row record.
|
70
75
|
def to_ary
|
71
76
|
hash_rows
|
72
77
|
end
|
@@ -75,11 +80,15 @@ module ActiveRecord
|
|
75
80
|
hash_rows[idx]
|
76
81
|
end
|
77
82
|
|
83
|
+
# Returns the first record from the rows collection.
|
84
|
+
# If the rows collection is empty, returns +nil+.
|
78
85
|
def first
|
79
86
|
return nil if @rows.empty?
|
80
87
|
Hash[@columns.zip(@rows.first)]
|
81
88
|
end
|
82
89
|
|
90
|
+
# Returns the last record from the rows collection.
|
91
|
+
# If the rows collection is empty, returns +nil+.
|
83
92
|
def last
|
84
93
|
return nil if @rows.empty?
|
85
94
|
Hash[@columns.zip(@rows.last)]
|
@@ -103,36 +112,36 @@ module ActiveRecord
|
|
103
112
|
|
104
113
|
private
|
105
114
|
|
106
|
-
|
107
|
-
|
108
|
-
|
115
|
+
def column_type(name, type_overrides = {})
|
116
|
+
type_overrides.fetch(name) do
|
117
|
+
column_types.fetch(name, Type.default_value)
|
118
|
+
end
|
109
119
|
end
|
110
|
-
end
|
111
120
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
121
|
+
def hash_rows
|
122
|
+
@hash_rows ||=
|
123
|
+
begin
|
124
|
+
# We freeze the strings to prevent them getting duped when
|
125
|
+
# used as keys in ActiveRecord::Base's @attributes hash
|
126
|
+
columns = @columns.map { |c| c.dup.freeze }
|
127
|
+
@rows.map { |row|
|
128
|
+
# In the past we used Hash[columns.zip(row)]
|
129
|
+
# though elegant, the verbose way is much more efficient
|
130
|
+
# both time and memory wise cause it avoids a big array allocation
|
131
|
+
# this method is called a lot and needs to be micro optimised
|
132
|
+
hash = {}
|
133
|
+
|
134
|
+
index = 0
|
135
|
+
length = columns.length
|
136
|
+
|
137
|
+
while index < length
|
138
|
+
hash[columns[index]] = row[index]
|
139
|
+
index += 1
|
140
|
+
end
|
141
|
+
|
142
|
+
hash
|
143
|
+
}
|
144
|
+
end
|
145
|
+
end
|
137
146
|
end
|
138
147
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "active_support/per_thread_registry"
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
# This is a thread locals registry for Active Record. For example:
|
@@ -12,9 +12,9 @@ module ActiveRecord
|
|
12
12
|
class RuntimeRegistry # :nodoc:
|
13
13
|
extend ActiveSupport::PerThreadRegistry
|
14
14
|
|
15
|
-
attr_accessor :connection_handler, :sql_runtime
|
15
|
+
attr_accessor :connection_handler, :sql_runtime
|
16
16
|
|
17
|
-
[:connection_handler, :sql_runtime
|
17
|
+
[:connection_handler, :sql_runtime].each do |val|
|
18
18
|
class_eval %{ def self.#{val}; instance.#{val}; end }, __FILE__, __LINE__
|
19
19
|
class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__
|
20
20
|
end
|
@@ -3,228 +3,212 @@ module ActiveRecord
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
module ClassMethods
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
def sanitize_sql_for_conditions(condition)
|
30
|
-
return nil if condition.blank?
|
31
|
-
|
32
|
-
case condition
|
33
|
-
when Array; sanitize_sql_array(condition)
|
34
|
-
else condition
|
6
|
+
private
|
7
|
+
|
8
|
+
# Accepts an array or string of SQL conditions and sanitizes
|
9
|
+
# them into a valid SQL fragment for a WHERE clause.
|
10
|
+
#
|
11
|
+
# sanitize_sql_for_conditions(["name=? and group_id=?", "foo'bar", 4])
|
12
|
+
# # => "name='foo''bar' and group_id=4"
|
13
|
+
#
|
14
|
+
# sanitize_sql_for_conditions(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4])
|
15
|
+
# # => "name='foo''bar' and group_id='4'"
|
16
|
+
#
|
17
|
+
# sanitize_sql_for_conditions(["name='%s' and group_id='%s'", "foo'bar", 4])
|
18
|
+
# # => "name='foo''bar' and group_id='4'"
|
19
|
+
#
|
20
|
+
# sanitize_sql_for_conditions("name='foo''bar' and group_id='4'")
|
21
|
+
# # => "name='foo''bar' and group_id='4'"
|
22
|
+
def sanitize_sql_for_conditions(condition) # :doc:
|
23
|
+
return nil if condition.blank?
|
24
|
+
|
25
|
+
case condition
|
26
|
+
when Array; sanitize_sql_array(condition)
|
27
|
+
else condition
|
28
|
+
end
|
35
29
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
30
|
+
alias :sanitize_sql :sanitize_sql_for_conditions
|
31
|
+
alias :sanitize_conditions :sanitize_sql
|
32
|
+
deprecate sanitize_conditions: :sanitize_sql
|
33
|
+
|
34
|
+
# Accepts an array, hash, or string of SQL conditions and sanitizes
|
35
|
+
# them into a valid SQL fragment for a SET clause.
|
36
|
+
#
|
37
|
+
# sanitize_sql_for_assignment(["name=? and group_id=?", nil, 4])
|
38
|
+
# # => "name=NULL and group_id=4"
|
39
|
+
#
|
40
|
+
# sanitize_sql_for_assignment(["name=:name and group_id=:group_id", name: nil, group_id: 4])
|
41
|
+
# # => "name=NULL and group_id=4"
|
42
|
+
#
|
43
|
+
# Post.send(:sanitize_sql_for_assignment, { name: nil, group_id: 4 })
|
44
|
+
# # => "`posts`.`name` = NULL, `posts`.`group_id` = 4"
|
45
|
+
#
|
46
|
+
# sanitize_sql_for_assignment("name=NULL and group_id='4'")
|
47
|
+
# # => "name=NULL and group_id='4'"
|
48
|
+
def sanitize_sql_for_assignment(assignments, default_table_name = table_name) # :doc:
|
49
|
+
case assignments
|
50
|
+
when Array; sanitize_sql_array(assignments)
|
51
|
+
when Hash; sanitize_sql_hash_for_assignment(assignments, default_table_name)
|
52
|
+
else assignments
|
53
|
+
end
|
59
54
|
end
|
60
|
-
end
|
61
55
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
56
|
+
# Accepts an array, or string of SQL conditions and sanitizes
|
57
|
+
# them into a valid SQL fragment for an ORDER clause.
|
58
|
+
#
|
59
|
+
# sanitize_sql_for_order(["field(id, ?)", [1,3,2]])
|
60
|
+
# # => "field(id, 1,3,2)"
|
61
|
+
#
|
62
|
+
# sanitize_sql_for_order("id ASC")
|
63
|
+
# # => "id ASC"
|
64
|
+
def sanitize_sql_for_order(condition) # :doc:
|
65
|
+
if condition.is_a?(Array) && condition.first.to_s.include?("?")
|
66
|
+
sanitize_sql_array(condition)
|
67
|
+
else
|
68
|
+
condition
|
69
|
+
end
|
75
70
|
end
|
76
|
-
end
|
77
71
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
72
|
+
# Accepts a hash of SQL conditions and replaces those attributes
|
73
|
+
# that correspond to a {#composed_of}[rdoc-ref:Aggregations::ClassMethods#composed_of]
|
74
|
+
# relationship with their expanded aggregate attribute values.
|
75
|
+
#
|
76
|
+
# Given:
|
77
|
+
#
|
78
|
+
# class Person < ActiveRecord::Base
|
79
|
+
# composed_of :address, class_name: "Address",
|
80
|
+
# mapping: [%w(address_street street), %w(address_city city)]
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# Then:
|
84
|
+
#
|
85
|
+
# { address: Address.new("813 abc st.", "chicago") }
|
86
|
+
# # => { address_street: "813 abc st.", address_city: "chicago" }
|
87
|
+
def expand_hash_conditions_for_aggregates(attrs) # :doc:
|
88
|
+
expanded_attrs = {}
|
89
|
+
attrs.each do |attr, value|
|
90
|
+
if aggregation = reflect_on_aggregation(attr.to_sym)
|
91
|
+
mapping = aggregation.mapping
|
92
|
+
mapping.each do |field_attr, aggregate_attr|
|
93
|
+
if mapping.size == 1 && !value.respond_to?(aggregate_attr)
|
94
|
+
expanded_attrs[field_attr] = value
|
95
|
+
else
|
96
|
+
expanded_attrs[field_attr] = value.send(aggregate_attr)
|
97
|
+
end
|
103
98
|
end
|
99
|
+
else
|
100
|
+
expanded_attrs[attr] = value
|
104
101
|
end
|
105
|
-
else
|
106
|
-
expanded_attrs[attr] = value
|
107
102
|
end
|
103
|
+
expanded_attrs
|
108
104
|
end
|
109
|
-
expanded_attrs
|
110
|
-
end
|
111
105
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
if value.is_a?(Base)
|
120
|
-
require "active_support/core_ext/string/filters"
|
121
|
-
ActiveSupport::Deprecation.warn(<<-WARNING.squish)
|
122
|
-
Passing `ActiveRecord::Base` objects to
|
123
|
-
`sanitize_sql_hash_for_assignment` (or methods which call it,
|
124
|
-
such as `update_all`) is deprecated. Please pass the id directly,
|
125
|
-
instead.
|
126
|
-
WARNING
|
127
|
-
else
|
106
|
+
# Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause.
|
107
|
+
#
|
108
|
+
# sanitize_sql_hash_for_assignment({ status: nil, group_id: 1 }, "posts")
|
109
|
+
# # => "`posts`.`status` = NULL, `posts`.`group_id` = 1"
|
110
|
+
def sanitize_sql_hash_for_assignment(attrs, table) # :doc:
|
111
|
+
c = connection
|
112
|
+
attrs.map do |attr, value|
|
128
113
|
value = type_for_attribute(attr.to_s).serialize(value)
|
129
|
-
|
130
|
-
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
# Sanitizes a +string+ so that it is safe to use within an SQL
|
135
|
-
# LIKE statement. This method uses +escape_character+ to escape all occurrences of "\", "_" and "%".
|
136
|
-
#
|
137
|
-
# sanitize_sql_like("100%")
|
138
|
-
# # => "100\\%"
|
139
|
-
#
|
140
|
-
# sanitize_sql_like("snake_cased_string")
|
141
|
-
# # => "snake\\_cased\\_string"
|
142
|
-
#
|
143
|
-
# sanitize_sql_like("100%", "!")
|
144
|
-
# # => "100!%"
|
145
|
-
#
|
146
|
-
# sanitize_sql_like("snake_cased_string", "!")
|
147
|
-
# # => "snake!_cased!_string"
|
148
|
-
def sanitize_sql_like(string, escape_character = "\\")
|
149
|
-
pattern = Regexp.union(escape_character, "%", "_")
|
150
|
-
string.gsub(pattern) { |x| [escape_character, x].join }
|
151
|
-
end
|
114
|
+
"#{c.quote_table_name_for_assignment(table, attr)} = #{c.quote(value)}"
|
115
|
+
end.join(", ")
|
116
|
+
end
|
152
117
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
elsif statement.blank?
|
171
|
-
statement
|
172
|
-
else
|
173
|
-
statement % values.collect { |value| connection.quote_string(value.to_s) }
|
118
|
+
# Sanitizes a +string+ so that it is safe to use within an SQL
|
119
|
+
# LIKE statement. This method uses +escape_character+ to escape all occurrences of "\", "_" and "%".
|
120
|
+
#
|
121
|
+
# sanitize_sql_like("100%")
|
122
|
+
# # => "100\\%"
|
123
|
+
#
|
124
|
+
# sanitize_sql_like("snake_cased_string")
|
125
|
+
# # => "snake\\_cased\\_string"
|
126
|
+
#
|
127
|
+
# sanitize_sql_like("100%", "!")
|
128
|
+
# # => "100!%"
|
129
|
+
#
|
130
|
+
# sanitize_sql_like("snake_cased_string", "!")
|
131
|
+
# # => "snake!_cased!_string"
|
132
|
+
def sanitize_sql_like(string, escape_character = "\\") # :doc:
|
133
|
+
pattern = Regexp.union(escape_character, "%", "_")
|
134
|
+
string.gsub(pattern) { |x| [escape_character, x].join }
|
174
135
|
end
|
175
|
-
end
|
176
136
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
137
|
+
# Accepts an array of conditions. The array has each value
|
138
|
+
# sanitized and interpolated into the SQL statement.
|
139
|
+
#
|
140
|
+
# sanitize_sql_array(["name=? and group_id=?", "foo'bar", 4])
|
141
|
+
# # => "name='foo''bar' and group_id=4"
|
142
|
+
#
|
143
|
+
# sanitize_sql_array(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4])
|
144
|
+
# # => "name='foo''bar' and group_id=4"
|
145
|
+
#
|
146
|
+
# sanitize_sql_array(["name='%s' and group_id='%s'", "foo'bar", 4])
|
147
|
+
# # => "name='foo''bar' and group_id='4'"
|
148
|
+
def sanitize_sql_array(ary) # :doc:
|
149
|
+
statement, *values = ary
|
150
|
+
if values.first.is_a?(Hash) && /:\w+/.match?(statement)
|
151
|
+
replace_named_bind_variables(statement, values.first)
|
152
|
+
elsif statement.include?("?")
|
153
|
+
replace_bind_variables(statement, values)
|
154
|
+
elsif statement.blank?
|
155
|
+
statement
|
156
|
+
else
|
157
|
+
statement % values.collect { |value| connection.quote_string(value.to_s) }
|
158
|
+
end
|
183
159
|
end
|
184
|
-
end
|
185
160
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
161
|
+
def replace_bind_variables(statement, values)
|
162
|
+
raise_if_bind_arity_mismatch(statement, statement.count("?"), values.size)
|
163
|
+
bound = values.dup
|
164
|
+
c = connection
|
165
|
+
statement.gsub(/\?/) do
|
166
|
+
replace_bind_variable(bound.shift, c)
|
167
|
+
end
|
191
168
|
end
|
192
|
-
end
|
193
169
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
match # return the whole match
|
198
|
-
elsif bind_vars.include?(match = $2.to_sym)
|
199
|
-
replace_bind_variable(bind_vars[match])
|
170
|
+
def replace_bind_variable(value, c = connection)
|
171
|
+
if ActiveRecord::Relation === value
|
172
|
+
value.to_sql
|
200
173
|
else
|
201
|
-
|
174
|
+
quote_bound_value(value, c)
|
202
175
|
end
|
203
176
|
end
|
204
|
-
end
|
205
177
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
178
|
+
def replace_named_bind_variables(statement, bind_vars)
|
179
|
+
statement.gsub(/(:?):([a-zA-Z]\w*)/) do |match|
|
180
|
+
if $1 == ":" # skip postgresql casts
|
181
|
+
match # return the whole match
|
182
|
+
elsif bind_vars.include?(match = $2.to_sym)
|
183
|
+
replace_bind_variable(bind_vars[match])
|
184
|
+
else
|
185
|
+
raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def quote_bound_value(value, c = connection)
|
191
|
+
if value.respond_to?(:map) && !value.acts_like?(:string)
|
192
|
+
if value.respond_to?(:empty?) && value.empty?
|
193
|
+
c.quote(nil)
|
194
|
+
else
|
195
|
+
value.map { |v| c.quote(v) }.join(",")
|
196
|
+
end
|
210
197
|
else
|
211
|
-
|
198
|
+
c.quote(value)
|
212
199
|
end
|
213
|
-
else
|
214
|
-
c.quote(value)
|
215
200
|
end
|
216
|
-
end
|
217
201
|
|
218
|
-
|
219
|
-
|
220
|
-
|
202
|
+
def raise_if_bind_arity_mismatch(statement, expected, provided)
|
203
|
+
unless expected == provided
|
204
|
+
raise PreparedStatementInvalid, "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}"
|
205
|
+
end
|
221
206
|
end
|
222
|
-
end
|
223
207
|
end
|
224
208
|
|
225
|
-
# TODO: Deprecate this
|
226
209
|
def quoted_id # :nodoc:
|
227
|
-
self.class.
|
210
|
+
self.class.connection.quote(@attributes[self.class.primary_key].value_for_database)
|
228
211
|
end
|
212
|
+
deprecate :quoted_id
|
229
213
|
end
|
230
214
|
end
|
data/lib/active_record/schema.rb
CHANGED
@@ -40,7 +40,7 @@ module ActiveRecord
|
|
40
40
|
# ActiveRecord::Schema.define(version: 20380119000001) do
|
41
41
|
# ...
|
42
42
|
# end
|
43
|
-
def self.define(info={}, &block)
|
43
|
+
def self.define(info = {}, &block)
|
44
44
|
new.define(info, &block)
|
45
45
|
end
|
46
46
|
|
@@ -48,7 +48,7 @@ module ActiveRecord
|
|
48
48
|
instance_eval(&block)
|
49
49
|
|
50
50
|
if info[:version].present?
|
51
|
-
|
51
|
+
ActiveRecord::SchemaMigration.create_table
|
52
52
|
connection.assume_migrated_upto_version(info[:version], migrations_paths)
|
53
53
|
end
|
54
54
|
|
@@ -61,7 +61,7 @@ module ActiveRecord
|
|
61
61
|
#
|
62
62
|
# ActiveRecord::Schema.new.migrations_paths
|
63
63
|
# # => ["db/migrate"] # Rails migration path by default.
|
64
|
-
def migrations_paths
|
64
|
+
def migrations_paths
|
65
65
|
ActiveRecord::Migrator.migrations_paths
|
66
66
|
end
|
67
67
|
end
|