activerecord 3.2.22.5 → 4.2.11.3
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 +1632 -609
- data/MIT-LICENSE +1 -1
- data/README.rdoc +37 -41
- data/examples/performance.rb +31 -19
- data/examples/simple.rb +4 -4
- data/lib/active_record/aggregations.rb +56 -42
- data/lib/active_record/association_relation.rb +35 -0
- data/lib/active_record/associations/alias_tracker.rb +47 -36
- data/lib/active_record/associations/association.rb +73 -55
- data/lib/active_record/associations/association_scope.rb +143 -82
- data/lib/active_record/associations/belongs_to_association.rb +65 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
- data/lib/active_record/associations/builder/association.rb +125 -31
- data/lib/active_record/associations/builder/belongs_to.rb +89 -61
- data/lib/active_record/associations/builder/collection_association.rb +69 -49
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +113 -42
- data/lib/active_record/associations/builder/has_many.rb +8 -64
- data/lib/active_record/associations/builder/has_one.rb +12 -51
- data/lib/active_record/associations/builder/singular_association.rb +23 -17
- data/lib/active_record/associations/collection_association.rb +251 -177
- data/lib/active_record/associations/collection_proxy.rb +963 -63
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +113 -22
- data/lib/active_record/associations/has_many_through_association.rb +99 -39
- data/lib/active_record/associations/has_one_association.rb +43 -20
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +76 -107
- data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
- data/lib/active_record/associations/join_dependency.rb +230 -156
- data/lib/active_record/associations/preloader/association.rb +96 -55
- data/lib/active_record/associations/preloader/collection_association.rb +3 -3
- data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
- data/lib/active_record/associations/preloader/has_one.rb +1 -1
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +62 -33
- data/lib/active_record/associations/preloader.rb +101 -79
- data/lib/active_record/associations/singular_association.rb +29 -13
- data/lib/active_record/associations/through_association.rb +30 -16
- data/lib/active_record/associations.rb +463 -345
- data/lib/active_record/attribute.rb +163 -0
- data/lib/active_record/attribute_assignment.rb +142 -151
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
- data/lib/active_record/attribute_methods/dirty.rb +137 -57
- data/lib/active_record/attribute_methods/primary_key.rb +50 -36
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +73 -106
- data/lib/active_record/attribute_methods/serialization.rb +44 -94
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -45
- data/lib/active_record/attribute_methods/write.rb +57 -44
- data/lib/active_record/attribute_methods.rb +301 -141
- data/lib/active_record/attribute_set/builder.rb +106 -0
- data/lib/active_record/attribute_set.rb +81 -0
- data/lib/active_record/attributes.rb +147 -0
- data/lib/active_record/autosave_association.rb +246 -217
- data/lib/active_record/base.rb +70 -474
- data/lib/active_record/callbacks.rb +66 -28
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/coders/yaml_column.rb +18 -21
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +396 -219
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -164
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +29 -24
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -55
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +261 -169
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +707 -259
- data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +298 -89
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +466 -196
- data/lib/active_record/connection_adapters/column.rb +31 -245
- data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +45 -57
- data/lib/active_record/connection_adapters/mysql_adapter.rb +180 -123
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +596 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +430 -999
- data/lib/active_record/connection_adapters/schema_cache.rb +52 -27
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +579 -22
- data/lib/active_record/connection_handling.rb +132 -0
- data/lib/active_record/core.rb +579 -0
- data/lib/active_record/counter_cache.rb +157 -105
- data/lib/active_record/dynamic_matchers.rb +119 -63
- data/lib/active_record/enum.rb +197 -0
- data/lib/active_record/errors.rb +94 -36
- data/lib/active_record/explain.rb +15 -63
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +9 -5
- data/lib/active_record/fixture_set/file.rb +56 -0
- data/lib/active_record/fixtures.rb +302 -215
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +143 -70
- data/lib/active_record/integration.rb +65 -12
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/locale/en.yml +8 -1
- data/lib/active_record/locking/optimistic.rb +73 -52
- data/lib/active_record/locking/pessimistic.rb +5 -5
- data/lib/active_record/log_subscriber.rb +24 -21
- data/lib/active_record/migration/command_recorder.rb +124 -32
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +511 -213
- data/lib/active_record/model_schema.rb +91 -117
- data/lib/active_record/nested_attributes.rb +184 -130
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +81 -0
- data/lib/active_record/persistence.rb +276 -117
- data/lib/active_record/query_cache.rb +19 -37
- data/lib/active_record/querying.rb +28 -18
- data/lib/active_record/railtie.rb +73 -40
- data/lib/active_record/railties/console_sandbox.rb +3 -4
- data/lib/active_record/railties/controller_runtime.rb +4 -3
- data/lib/active_record/railties/databases.rake +141 -416
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +1 -4
- data/lib/active_record/reflection.rb +513 -154
- data/lib/active_record/relation/batches.rb +91 -43
- data/lib/active_record/relation/calculations.rb +199 -161
- data/lib/active_record/relation/delegation.rb +116 -25
- data/lib/active_record/relation/finder_methods.rb +362 -248
- data/lib/active_record/relation/merger.rb +193 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
- data/lib/active_record/relation/predicate_builder.rb +135 -43
- data/lib/active_record/relation/query_methods.rb +928 -167
- data/lib/active_record/relation/spawn_methods.rb +48 -149
- data/lib/active_record/relation.rb +352 -207
- data/lib/active_record/result.rb +101 -10
- data/lib/active_record/runtime_registry.rb +22 -0
- data/lib/active_record/sanitization.rb +56 -59
- data/lib/active_record/schema.rb +19 -13
- data/lib/active_record/schema_dumper.rb +106 -63
- data/lib/active_record/schema_migration.rb +53 -0
- data/lib/active_record/scoping/default.rb +50 -57
- data/lib/active_record/scoping/named.rb +73 -109
- data/lib/active_record/scoping.rb +58 -123
- data/lib/active_record/serialization.rb +6 -2
- data/lib/active_record/serializers/xml_serializer.rb +12 -22
- data/lib/active_record/statement_cache.rb +111 -0
- data/lib/active_record/store.rb +168 -15
- data/lib/active_record/tasks/database_tasks.rb +299 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +159 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +101 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
- data/lib/active_record/timestamp.rb +23 -16
- data/lib/active_record/transactions.rb +125 -79
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +31 -0
- data/lib/active_record/type/date.rb +50 -0
- data/lib/active_record/type/date_time.rb +54 -0
- data/lib/active_record/type/decimal.rb +64 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- data/lib/active_record/type/integer.rb +59 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +62 -0
- data/lib/active_record/type/string.rb +40 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +110 -0
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/validations/associated.rb +24 -16
- data/lib/active_record/validations/presence.rb +67 -0
- data/lib/active_record/validations/uniqueness.rb +123 -64
- data/lib/active_record/validations.rb +36 -29
- data/lib/active_record/version.rb +5 -7
- data/lib/active_record.rb +66 -46
- data/lib/rails/generators/active_record/migration/migration_generator.rb +53 -8
- data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +5 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
- data/lib/rails/generators/active_record/migration.rb +11 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -4
- data/lib/rails/generators/active_record/model/templates/model.rb +4 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- data/lib/rails/generators/active_record.rb +3 -11
- metadata +101 -45
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
- data/lib/active_record/associations/join_helper.rb +0 -55
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/session_store.rb +0 -360
- data/lib/active_record/test_case.rb +0 -73
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
data/lib/active_record/result.rb
CHANGED
@@ -3,36 +3,127 @@ module ActiveRecord
|
|
3
3
|
# This class encapsulates a Result returned from calling +exec_query+ on any
|
4
4
|
# database connection adapter. For example:
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# result = ActiveRecord::Base.connection.exec_query('SELECT id, title, body FROM posts')
|
7
|
+
# result # => #<ActiveRecord::Result:0xdeadbeef>
|
8
|
+
#
|
9
|
+
# # Get the column names of the result:
|
10
|
+
# result.columns
|
11
|
+
# # => ["id", "title", "body"]
|
12
|
+
#
|
13
|
+
# # Get the record values of the result:
|
14
|
+
# result.rows
|
15
|
+
# # => [[1, "title_1", "body_1"],
|
16
|
+
# [2, "title_2", "body_2"],
|
17
|
+
# ...
|
18
|
+
# ]
|
19
|
+
#
|
20
|
+
# # Get an array of hashes representing the result (column => value):
|
21
|
+
# result.to_hash
|
22
|
+
# # => [{"id" => 1, "title" => "title_1", "body" => "body_1"},
|
23
|
+
# {"id" => 2, "title" => "title_2", "body" => "body_2"},
|
24
|
+
# ...
|
25
|
+
# ]
|
26
|
+
#
|
27
|
+
# # ActiveRecord::Result also includes Enumerable.
|
28
|
+
# result.each do |row|
|
29
|
+
# puts row['title'] + " " + row['body']
|
30
|
+
# end
|
8
31
|
class Result
|
9
32
|
include Enumerable
|
10
33
|
|
11
|
-
|
34
|
+
IDENTITY_TYPE = Type::Value.new # :nodoc:
|
35
|
+
|
36
|
+
attr_reader :columns, :rows, :column_types
|
37
|
+
|
38
|
+
def initialize(columns, rows, column_types = {})
|
39
|
+
@columns = columns
|
40
|
+
@rows = rows
|
41
|
+
@hash_rows = nil
|
42
|
+
@column_types = column_types
|
43
|
+
end
|
12
44
|
|
13
|
-
def
|
14
|
-
@
|
15
|
-
@rows = rows
|
16
|
-
@hash_rows = nil
|
45
|
+
def length
|
46
|
+
@rows.length
|
17
47
|
end
|
18
48
|
|
19
49
|
def each
|
20
|
-
|
50
|
+
if block_given?
|
51
|
+
hash_rows.each { |row| yield row }
|
52
|
+
else
|
53
|
+
hash_rows.to_enum { @rows.size }
|
54
|
+
end
|
21
55
|
end
|
22
56
|
|
23
57
|
def to_hash
|
24
58
|
hash_rows
|
25
59
|
end
|
26
60
|
|
61
|
+
alias :map! :map
|
62
|
+
alias :collect! :map
|
63
|
+
|
64
|
+
# Returns true if there are no records.
|
65
|
+
def empty?
|
66
|
+
rows.empty?
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_ary
|
70
|
+
hash_rows
|
71
|
+
end
|
72
|
+
|
73
|
+
def [](idx)
|
74
|
+
hash_rows[idx]
|
75
|
+
end
|
76
|
+
|
77
|
+
def last
|
78
|
+
hash_rows.last
|
79
|
+
end
|
80
|
+
|
81
|
+
def cast_values(type_overrides = {}) # :nodoc:
|
82
|
+
types = columns.map { |name| column_type(name, type_overrides) }
|
83
|
+
result = rows.map do |values|
|
84
|
+
types.zip(values).map { |type, value| type.type_cast_from_database(value) }
|
85
|
+
end
|
86
|
+
|
87
|
+
columns.one? ? result.map!(&:first) : result
|
88
|
+
end
|
89
|
+
|
90
|
+
def initialize_copy(other)
|
91
|
+
@columns = columns.dup
|
92
|
+
@rows = rows.dup
|
93
|
+
@column_types = column_types.dup
|
94
|
+
@hash_rows = nil
|
95
|
+
end
|
96
|
+
|
27
97
|
private
|
98
|
+
|
99
|
+
def column_type(name, type_overrides = {})
|
100
|
+
type_overrides.fetch(name) do
|
101
|
+
column_types.fetch(name, IDENTITY_TYPE)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
28
105
|
def hash_rows
|
29
106
|
@hash_rows ||=
|
30
107
|
begin
|
31
108
|
# We freeze the strings to prevent them getting duped when
|
32
|
-
# used as keys in ActiveRecord::
|
109
|
+
# used as keys in ActiveRecord::Base's @attributes hash
|
33
110
|
columns = @columns.map { |c| c.dup.freeze }
|
34
111
|
@rows.map { |row|
|
35
|
-
Hash[columns.zip(row)]
|
112
|
+
# In the past we used Hash[columns.zip(row)]
|
113
|
+
# though elegant, the verbose way is much more efficient
|
114
|
+
# both time and memory wise cause it avoids a big array allocation
|
115
|
+
# this method is called a lot and needs to be micro optimised
|
116
|
+
hash = {}
|
117
|
+
|
118
|
+
index = 0
|
119
|
+
length = columns.length
|
120
|
+
|
121
|
+
while index < length
|
122
|
+
hash[columns[index]] = row[index]
|
123
|
+
index += 1
|
124
|
+
end
|
125
|
+
|
126
|
+
hash
|
36
127
|
}
|
37
128
|
end
|
38
129
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'active_support/per_thread_registry'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
# This is a thread locals registry for Active Record. For example:
|
5
|
+
#
|
6
|
+
# ActiveRecord::RuntimeRegistry.connection_handler
|
7
|
+
#
|
8
|
+
# returns the connection handler local to the current thread.
|
9
|
+
#
|
10
|
+
# See the documentation of <tt>ActiveSupport::PerThreadRegistry</tt>
|
11
|
+
# for further details.
|
12
|
+
class RuntimeRegistry # :nodoc:
|
13
|
+
extend ActiveSupport::PerThreadRegistry
|
14
|
+
|
15
|
+
attr_accessor :connection_handler, :sql_runtime, :connection_id
|
16
|
+
|
17
|
+
[:connection_handler, :sql_runtime, :connection_id].each do |val|
|
18
|
+
class_eval %{ def self.#{val}; instance.#{val}; end }, __FILE__, __LINE__
|
19
|
+
class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,12 +1,10 @@
|
|
1
|
-
require 'active_support/concern'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
2
|
module Sanitization
|
5
3
|
extend ActiveSupport::Concern
|
6
4
|
|
7
5
|
module ClassMethods
|
8
|
-
def quote_value(value, column
|
9
|
-
connection.quote(value,column)
|
6
|
+
def quote_value(value, column) #:nodoc:
|
7
|
+
connection.quote(value, column)
|
10
8
|
end
|
11
9
|
|
12
10
|
# Used to sanitize objects before they're used in an SQL SELECT statement. Delegates to <tt>connection.quote</tt>.
|
@@ -19,7 +17,7 @@ module ActiveRecord
|
|
19
17
|
# Accepts an array, hash, or string of SQL conditions and sanitizes
|
20
18
|
# them into a valid SQL fragment for a WHERE clause.
|
21
19
|
# ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
|
22
|
-
# { :
|
20
|
+
# { name: "foo'bar", group_id: 4 } returns "name='foo''bar' and group_id='4'"
|
23
21
|
# "name='foo''bar' and group_id='4'" returns "name='foo''bar' and group_id='4'"
|
24
22
|
def sanitize_sql_for_conditions(condition, table_name = self.table_name)
|
25
23
|
return nil if condition.blank?
|
@@ -31,15 +29,16 @@ module ActiveRecord
|
|
31
29
|
end
|
32
30
|
end
|
33
31
|
alias_method :sanitize_sql, :sanitize_sql_for_conditions
|
32
|
+
alias_method :sanitize_conditions, :sanitize_sql
|
34
33
|
|
35
34
|
# Accepts an array, hash, or string of SQL conditions and sanitizes
|
36
35
|
# them into a valid SQL fragment for a SET clause.
|
37
|
-
# { :
|
38
|
-
def sanitize_sql_for_assignment(assignments)
|
36
|
+
# { name: nil, group_id: 4 } returns "name = NULL , group_id='4'"
|
37
|
+
def sanitize_sql_for_assignment(assignments, default_table_name = self.table_name)
|
39
38
|
case assignments
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
when Array; sanitize_sql_array(assignments)
|
40
|
+
when Hash; sanitize_sql_hash_for_assignment(assignments, default_table_name)
|
41
|
+
else assignments
|
43
42
|
end
|
44
43
|
end
|
45
44
|
|
@@ -48,17 +47,17 @@ module ActiveRecord
|
|
48
47
|
# aggregate attribute values.
|
49
48
|
# Given:
|
50
49
|
# class Person < ActiveRecord::Base
|
51
|
-
# composed_of :address, :
|
52
|
-
# :
|
50
|
+
# composed_of :address, class_name: "Address",
|
51
|
+
# mapping: [%w(address_street street), %w(address_city city)]
|
53
52
|
# end
|
54
53
|
# Then:
|
55
|
-
# { :
|
56
|
-
# # => { :
|
54
|
+
# { address: Address.new("813 abc st.", "chicago") }
|
55
|
+
# # => { address_street: "813 abc st.", address_city: "chicago" }
|
57
56
|
def expand_hash_conditions_for_aggregates(attrs)
|
58
57
|
expanded_attrs = {}
|
59
58
|
attrs.each do |attr, value|
|
60
|
-
|
61
|
-
mapping =
|
59
|
+
if aggregation = reflect_on_aggregation(attr.to_sym)
|
60
|
+
mapping = aggregation.mapping
|
62
61
|
mapping.each do |field_attr, aggregate_attr|
|
63
62
|
if mapping.size == 1 && !value.respond_to?(aggregate_attr)
|
64
63
|
expanded_attrs[field_attr] = value
|
@@ -74,38 +73,50 @@ module ActiveRecord
|
|
74
73
|
end
|
75
74
|
|
76
75
|
# Sanitizes a hash of attribute/value pairs into SQL conditions for a WHERE clause.
|
77
|
-
# { :
|
76
|
+
# { name: "foo'bar", group_id: 4 }
|
78
77
|
# # => "name='foo''bar' and group_id= 4"
|
79
|
-
# { :
|
78
|
+
# { status: nil, group_id: [1,2,3] }
|
80
79
|
# # => "status IS NULL and group_id IN (1,2,3)"
|
81
|
-
# { :
|
80
|
+
# { age: 13..18 }
|
82
81
|
# # => "age BETWEEN 13 AND 18"
|
83
82
|
# { 'other_records.id' => 7 }
|
84
83
|
# # => "`other_records`.`id` = 7"
|
85
|
-
# { :
|
84
|
+
# { other_records: { id: 7 } }
|
86
85
|
# # => "`other_records`.`id` = 7"
|
87
86
|
# And for value objects on a composed_of relationship:
|
88
|
-
# { :
|
87
|
+
# { address: Address.new("123 abc st.", "chicago") }
|
89
88
|
# # => "address_street='123 abc st.' and address_city='chicago'"
|
90
89
|
def sanitize_sql_hash_for_conditions(attrs, default_table_name = self.table_name)
|
90
|
+
ActiveSupport::Deprecation.warn(<<-EOWARN)
|
91
|
+
sanitize_sql_hash_for_conditions is deprecated, and will be removed in Rails 5.0
|
92
|
+
EOWARN
|
93
|
+
attrs = PredicateBuilder.resolve_column_aliases self, attrs
|
91
94
|
attrs = expand_hash_conditions_for_aggregates(attrs)
|
92
95
|
|
93
|
-
table = Arel::Table.new(table_name).alias(default_table_name)
|
94
|
-
PredicateBuilder.build_from_hash(
|
95
|
-
connection.visitor.
|
96
|
+
table = Arel::Table.new(table_name, arel_engine).alias(default_table_name)
|
97
|
+
PredicateBuilder.build_from_hash(self, attrs, table).map { |b|
|
98
|
+
connection.visitor.compile b
|
96
99
|
}.join(' AND ')
|
97
100
|
end
|
98
101
|
alias_method :sanitize_sql_hash, :sanitize_sql_hash_for_conditions
|
99
102
|
|
100
103
|
# Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause.
|
101
|
-
# { :
|
104
|
+
# { status: nil, group_id: 1 }
|
102
105
|
# # => "status = NULL , group_id = 1"
|
103
|
-
def sanitize_sql_hash_for_assignment(attrs)
|
106
|
+
def sanitize_sql_hash_for_assignment(attrs, table)
|
107
|
+
c = connection
|
104
108
|
attrs.map do |attr, value|
|
105
|
-
"#{
|
109
|
+
"#{c.quote_table_name_for_assignment(table, attr)} = #{quote_bound_value(value, c, columns_hash[attr.to_s])}"
|
106
110
|
end.join(', ')
|
107
111
|
end
|
108
112
|
|
113
|
+
# Sanitizes a +string+ so that it is safe to use within an SQL
|
114
|
+
# LIKE statement. This method uses +escape_character+ to escape all occurrences of "\", "_" and "%"
|
115
|
+
def sanitize_sql_like(string, escape_character = "\\")
|
116
|
+
pattern = Regexp.union(escape_character, "%", "_")
|
117
|
+
string.gsub(pattern) { |x| [escape_character, x].join }
|
118
|
+
end
|
119
|
+
|
109
120
|
# Accepts an array of conditions. The array has each value
|
110
121
|
# sanitized and interpolated into the SQL statement.
|
111
122
|
# ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
|
@@ -122,13 +133,21 @@ module ActiveRecord
|
|
122
133
|
end
|
123
134
|
end
|
124
135
|
|
125
|
-
alias_method :sanitize_conditions, :sanitize_sql
|
126
|
-
|
127
136
|
def replace_bind_variables(statement, values) #:nodoc:
|
128
137
|
raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
|
129
138
|
bound = values.dup
|
130
139
|
c = connection
|
131
|
-
statement.gsub(
|
140
|
+
statement.gsub(/\?/) do
|
141
|
+
replace_bind_variable(bound.shift, c)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def replace_bind_variable(value, c = connection) #:nodoc:
|
146
|
+
if ActiveRecord::Relation === value
|
147
|
+
value.to_sql
|
148
|
+
else
|
149
|
+
quote_bound_value(value, c)
|
150
|
+
end
|
132
151
|
end
|
133
152
|
|
134
153
|
def replace_named_bind_variables(statement, bind_vars) #:nodoc:
|
@@ -136,32 +155,17 @@ module ActiveRecord
|
|
136
155
|
if $1 == ':' # skip postgresql casts
|
137
156
|
$& # return the whole match
|
138
157
|
elsif bind_vars.include?(match = $2.to_sym)
|
139
|
-
|
158
|
+
replace_bind_variable(bind_vars[match])
|
140
159
|
else
|
141
160
|
raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
|
142
161
|
end
|
143
162
|
end
|
144
163
|
end
|
145
164
|
|
146
|
-
def
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
next if var.is_a?(Hash)
|
151
|
-
|
152
|
-
if var.is_a?(Range)
|
153
|
-
expanded << var.first
|
154
|
-
expanded << var.last
|
155
|
-
else
|
156
|
-
expanded << var
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
expanded
|
161
|
-
end
|
162
|
-
|
163
|
-
def quote_bound_value(value, c = connection) #:nodoc:
|
164
|
-
if value.respond_to?(:map) && !value.acts_like?(:string)
|
165
|
+
def quote_bound_value(value, c = connection, column = nil) #:nodoc:
|
166
|
+
if column
|
167
|
+
c.quote(value, column)
|
168
|
+
elsif value.respond_to?(:map) && !value.acts_like?(:string)
|
165
169
|
if value.respond_to?(:empty?) && value.empty?
|
166
170
|
c.quote(nil)
|
167
171
|
else
|
@@ -180,15 +184,8 @@ module ActiveRecord
|
|
180
184
|
end
|
181
185
|
|
182
186
|
# TODO: Deprecate this
|
183
|
-
def quoted_id
|
184
|
-
quote_value(id, column_for_attribute(self.class.primary_key))
|
185
|
-
end
|
186
|
-
|
187
|
-
private
|
188
|
-
|
189
|
-
# Quote strings appropriately for SQL statements.
|
190
|
-
def quote_value(value, column = nil)
|
191
|
-
self.class.connection.quote(value, column)
|
187
|
+
def quoted_id
|
188
|
+
self.class.quote_value(id, column_for_attribute(self.class.primary_key))
|
192
189
|
end
|
193
190
|
end
|
194
191
|
end
|
data/lib/active_record/schema.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'active_support/core_ext/object/blank'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
2
|
# = Active Record Schema
|
5
3
|
#
|
@@ -12,16 +10,16 @@ module ActiveRecord
|
|
12
10
|
#
|
13
11
|
# ActiveRecord::Schema.define do
|
14
12
|
# create_table :authors do |t|
|
15
|
-
# t.string :name, :
|
13
|
+
# t.string :name, null: false
|
16
14
|
# end
|
17
15
|
#
|
18
16
|
# add_index :authors, :name, :unique
|
19
17
|
#
|
20
18
|
# create_table :posts do |t|
|
21
|
-
# t.integer :author_id, :
|
19
|
+
# t.integer :author_id, null: false
|
22
20
|
# t.string :subject
|
23
21
|
# t.text :body
|
24
|
-
# t.boolean :private, :
|
22
|
+
# t.boolean :private, default: false
|
25
23
|
# end
|
26
24
|
#
|
27
25
|
# add_index :posts, :author_id
|
@@ -30,10 +28,24 @@ module ActiveRecord
|
|
30
28
|
# ActiveRecord::Schema is only supported by database adapters that also
|
31
29
|
# support migrations, the two features being very similar.
|
32
30
|
class Schema < Migration
|
31
|
+
|
32
|
+
# Returns the migrations paths.
|
33
|
+
#
|
34
|
+
# ActiveRecord::Schema.new.migrations_paths
|
35
|
+
# # => ["db/migrate"] # Rails migration path by default.
|
33
36
|
def migrations_paths
|
34
37
|
ActiveRecord::Migrator.migrations_paths
|
35
38
|
end
|
36
39
|
|
40
|
+
def define(info, &block) # :nodoc:
|
41
|
+
instance_eval(&block)
|
42
|
+
|
43
|
+
unless info[:version].blank?
|
44
|
+
initialize_schema_migrations_table
|
45
|
+
connection.assume_migrated_upto_version(info[:version], migrations_paths)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
37
49
|
# Eval the given block. All methods available to the current connection
|
38
50
|
# adapter are available within the block, so you can easily use the
|
39
51
|
# database definition DSL to build up your schema (+create_table+,
|
@@ -42,17 +54,11 @@ module ActiveRecord
|
|
42
54
|
# The +info+ hash is optional, and if given is used to define metadata
|
43
55
|
# about the current schema (currently, only the schema's version):
|
44
56
|
#
|
45
|
-
# ActiveRecord::Schema.define(:
|
57
|
+
# ActiveRecord::Schema.define(version: 20380119000001) do
|
46
58
|
# ...
|
47
59
|
# end
|
48
60
|
def self.define(info={}, &block)
|
49
|
-
|
50
|
-
schema.instance_eval(&block)
|
51
|
-
|
52
|
-
unless info[:version].blank?
|
53
|
-
initialize_schema_migrations_table
|
54
|
-
assume_migrated_upto_version(info[:version], schema.migrations_paths)
|
55
|
-
end
|
61
|
+
new.define(info, &block)
|
56
62
|
end
|
57
63
|
end
|
58
64
|
end
|