activerecord 3.2.22.5 → 4.0.0.beta1
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 +4 -4
- data/CHANGELOG.md +1024 -543
- data/MIT-LICENSE +1 -1
- data/README.rdoc +20 -29
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +55 -44
- data/lib/active_record/aggregations.rb +40 -34
- data/lib/active_record/associations.rb +204 -276
- data/lib/active_record/associations/alias_tracker.rb +1 -1
- data/lib/active_record/associations/association.rb +30 -35
- data/lib/active_record/associations/association_scope.rb +40 -40
- data/lib/active_record/associations/belongs_to_association.rb +15 -2
- data/lib/active_record/associations/builder/association.rb +81 -28
- data/lib/active_record/associations/builder/belongs_to.rb +35 -57
- data/lib/active_record/associations/builder/collection_association.rb +54 -40
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +23 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -64
- data/lib/active_record/associations/builder/has_one.rb +13 -50
- data/lib/active_record/associations/builder/singular_association.rb +13 -13
- data/lib/active_record/associations/collection_association.rb +92 -88
- data/lib/active_record/associations/collection_proxy.rb +913 -63
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +12 -10
- data/lib/active_record/associations/has_many_association.rb +35 -9
- data/lib/active_record/associations/has_many_through_association.rb +24 -14
- data/lib/active_record/associations/has_one_association.rb +33 -13
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +17 -22
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_helper.rb +1 -11
- data/lib/active_record/associations/preloader.rb +14 -17
- data/lib/active_record/associations/preloader/association.rb +29 -33
- data/lib/active_record/associations/preloader/collection_association.rb +1 -1
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +1 -1
- data/lib/active_record/associations/preloader/through_association.rb +13 -17
- data/lib/active_record/associations/singular_association.rb +11 -11
- data/lib/active_record/associations/through_association.rb +2 -2
- data/lib/active_record/attribute_assignment.rb +133 -153
- data/lib/active_record/attribute_methods.rb +196 -93
- data/lib/active_record/attribute_methods/before_type_cast.rb +44 -5
- data/lib/active_record/attribute_methods/dirty.rb +31 -28
- data/lib/active_record/attribute_methods/primary_key.rb +38 -30
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +62 -91
- data/lib/active_record/attribute_methods/serialization.rb +97 -66
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -45
- data/lib/active_record/attribute_methods/write.rb +32 -39
- data/lib/active_record/autosave_association.rb +56 -70
- data/lib/active_record/base.rb +53 -450
- data/lib/active_record/callbacks.rb +53 -18
- data/lib/active_record/coders/yaml_column.rb +11 -9
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +353 -197
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +130 -131
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -19
- data/lib/active_record/connection_adapters/abstract/quoting.rb +23 -3
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +101 -91
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +59 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +225 -96
- data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +99 -46
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +114 -36
- data/lib/active_record/connection_adapters/column.rb +46 -24
- data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
- data/lib/active_record/connection_adapters/mysql_adapter.rb +181 -64
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/cast.rb +132 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +347 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +158 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +448 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +454 -885
- data/lib/active_record/connection_adapters/schema_cache.rb +48 -16
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +574 -13
- data/lib/active_record/connection_handling.rb +98 -0
- data/lib/active_record/core.rb +428 -0
- data/lib/active_record/counter_cache.rb +106 -108
- data/lib/active_record/dynamic_matchers.rb +110 -63
- data/lib/active_record/errors.rb +25 -8
- data/lib/active_record/explain.rb +8 -58
- data/lib/active_record/explain_subscriber.rb +6 -3
- data/lib/active_record/fixture_set/file.rb +56 -0
- data/lib/active_record/fixtures.rb +146 -148
- data/lib/active_record/inheritance.rb +77 -59
- data/lib/active_record/integration.rb +5 -5
- data/lib/active_record/locale/en.yml +8 -1
- data/lib/active_record/locking/optimistic.rb +38 -42
- data/lib/active_record/locking/pessimistic.rb +4 -4
- data/lib/active_record/log_subscriber.rb +19 -9
- data/lib/active_record/migration.rb +318 -153
- data/lib/active_record/migration/command_recorder.rb +90 -31
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/model_schema.rb +69 -92
- data/lib/active_record/nested_attributes.rb +113 -148
- data/lib/active_record/null_relation.rb +65 -0
- data/lib/active_record/persistence.rb +188 -97
- data/lib/active_record/query_cache.rb +18 -36
- data/lib/active_record/querying.rb +19 -15
- data/lib/active_record/railtie.rb +91 -36
- data/lib/active_record/railties/console_sandbox.rb +0 -2
- data/lib/active_record/railties/controller_runtime.rb +2 -2
- data/lib/active_record/railties/databases.rake +90 -309
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +7 -3
- data/lib/active_record/reflection.rb +72 -56
- data/lib/active_record/relation.rb +241 -157
- data/lib/active_record/relation/batches.rb +25 -22
- data/lib/active_record/relation/calculations.rb +143 -121
- data/lib/active_record/relation/delegation.rb +96 -18
- data/lib/active_record/relation/finder_methods.rb +117 -183
- data/lib/active_record/relation/merger.rb +133 -0
- data/lib/active_record/relation/predicate_builder.rb +90 -42
- data/lib/active_record/relation/query_methods.rb +666 -136
- data/lib/active_record/relation/spawn_methods.rb +43 -150
- data/lib/active_record/result.rb +33 -6
- data/lib/active_record/sanitization.rb +24 -50
- data/lib/active_record/schema.rb +19 -12
- data/lib/active_record/schema_dumper.rb +31 -39
- data/lib/active_record/schema_migration.rb +36 -0
- data/lib/active_record/scoping.rb +0 -124
- data/lib/active_record/scoping/default.rb +48 -45
- data/lib/active_record/scoping/named.rb +74 -103
- data/lib/active_record/serialization.rb +6 -2
- data/lib/active_record/serializers/xml_serializer.rb +9 -15
- data/lib/active_record/store.rb +119 -15
- data/lib/active_record/tasks/database_tasks.rb +158 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +138 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
- data/lib/active_record/test_case.rb +61 -38
- data/lib/active_record/timestamp.rb +8 -9
- data/lib/active_record/transactions.rb +65 -51
- data/lib/active_record/validations.rb +17 -15
- data/lib/active_record/validations/associated.rb +20 -14
- data/lib/active_record/validations/presence.rb +65 -0
- data/lib/active_record/validations/uniqueness.rb +93 -52
- data/lib/active_record/version.rb +4 -4
- data/lib/rails/generators/active_record.rb +3 -5
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -7
- data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -3
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- metadata +53 -46
- 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/rails/generators/active_record/migration.rb +0 -15
- 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
@@ -1,180 +1,73 @@
|
|
1
|
-
require 'active_support/core_ext/
|
1
|
+
require 'active_support/core_ext/hash/except'
|
2
|
+
require 'active_support/core_ext/hash/slice'
|
3
|
+
require 'active_record/relation/merger'
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
module SpawnMethods
|
5
|
-
def merge(r)
|
6
|
-
return self unless r
|
7
|
-
return to_a & r if r.is_a?(Array)
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
Relation::ASSOCIATION_METHODS.each do |method|
|
14
|
-
value = r.send(:"#{method}_values")
|
15
|
-
|
16
|
-
unless value.empty?
|
17
|
-
if method == :includes
|
18
|
-
merged_relation = merged_relation.includes(value)
|
19
|
-
else
|
20
|
-
merge_relation_method(merged_relation, method, value)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
(Relation::MULTI_VALUE_METHODS - [:joins, :where, :order]).each do |method|
|
26
|
-
value = r.send(:"#{method}_values")
|
27
|
-
merge_relation_method(merged_relation, method, value) if value.present?
|
28
|
-
end
|
29
|
-
|
30
|
-
merge_joins(merged_relation, r)
|
31
|
-
|
32
|
-
merged_wheres = @where_values + r.where_values
|
33
|
-
|
34
|
-
unless @where_values.empty?
|
35
|
-
# Remove duplicate ARel attributes. Last one wins.
|
36
|
-
seen = Hash.new { |h,table| h[table] = {} }
|
37
|
-
merged_wheres = merged_wheres.reverse.reject { |w|
|
38
|
-
nuke = false
|
39
|
-
if w.respond_to?(:operator) && w.operator == :== &&
|
40
|
-
w.left.respond_to?(:relation)
|
41
|
-
name = w.left.name
|
42
|
-
table = w.left.relation.name
|
43
|
-
nuke = seen[table][name]
|
44
|
-
seen[table][name] = true
|
45
|
-
end
|
46
|
-
nuke
|
47
|
-
}.reverse
|
48
|
-
end
|
49
|
-
|
50
|
-
merged_relation.where_values = merged_wheres
|
8
|
+
# This is overridden by Associations::CollectionProxy
|
9
|
+
def spawn #:nodoc:
|
10
|
+
clone
|
11
|
+
end
|
51
12
|
|
52
|
-
|
53
|
-
|
54
|
-
|
13
|
+
# Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an <tt>ActiveRecord::Relation</tt>.
|
14
|
+
# Returns an array representing the intersection of the resulting records with <tt>other</tt>, if <tt>other</tt> is an array.
|
15
|
+
# Post.where(published: true).joins(:comments).merge( Comment.where(spam: false) )
|
16
|
+
# # Performs a single join query with both where conditions.
|
17
|
+
#
|
18
|
+
# recent_posts = Post.order('created_at DESC').first(5)
|
19
|
+
# Post.where(published: true).merge(recent_posts)
|
20
|
+
# # Returns the intersection of all published posts with the 5 most recently created posts.
|
21
|
+
# # (This is just an example. You'd probably want to do this with a single query!)
|
22
|
+
#
|
23
|
+
# Procs will be evaluated by merge:
|
24
|
+
#
|
25
|
+
# Post.where(published: true).merge(-> { joins(:comments) })
|
26
|
+
# # => Post.where(published: true).joins(:comments)
|
27
|
+
#
|
28
|
+
# This is mainly intended for sharing common conditions between multiple associations.
|
29
|
+
def merge(other)
|
30
|
+
if other.is_a?(Array)
|
31
|
+
to_a & other
|
32
|
+
elsif other
|
33
|
+
spawn.merge!(other)
|
34
|
+
else
|
35
|
+
self
|
55
36
|
end
|
37
|
+
end
|
56
38
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
if (r.reordering_value)
|
62
|
-
# override any order specified in the original relation
|
63
|
-
merged_relation.reordering_value = true
|
64
|
-
merged_relation.order_values = r.order_values
|
39
|
+
def merge!(other) # :nodoc:
|
40
|
+
if !other.is_a?(Relation) && other.respond_to?(:to_proc)
|
41
|
+
instance_exec(&other)
|
65
42
|
else
|
66
|
-
|
67
|
-
|
43
|
+
klass = other.is_a?(Hash) ? Relation::HashMerger : Relation::Merger
|
44
|
+
klass.new(self, other).merge
|
68
45
|
end
|
69
|
-
|
70
|
-
# Apply scope extension modules
|
71
|
-
merged_relation.send :apply_modules, r.extensions
|
72
|
-
|
73
|
-
merged_relation
|
74
46
|
end
|
75
47
|
|
76
48
|
# Removes from the query the condition(s) specified in +skips+.
|
77
49
|
#
|
78
|
-
# Example:
|
79
|
-
#
|
80
50
|
# Post.order('id asc').except(:order) # discards the order condition
|
81
51
|
# Post.where('id > 10').order('id asc').except(:where) # discards the where condition but keeps the order
|
82
|
-
#
|
83
52
|
def except(*skips)
|
84
|
-
|
85
|
-
result.default_scoped = default_scoped
|
86
|
-
|
87
|
-
((Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS) - skips).each do |method|
|
88
|
-
result.send(:"#{method}_values=", send(:"#{method}_values"))
|
89
|
-
end
|
90
|
-
|
91
|
-
(Relation::SINGLE_VALUE_METHODS - skips).each do |method|
|
92
|
-
result.send(:"#{method}_value=", send(:"#{method}_value"))
|
93
|
-
end
|
94
|
-
|
95
|
-
# Apply scope extension modules
|
96
|
-
result.send(:apply_modules, extensions)
|
97
|
-
|
98
|
-
result
|
53
|
+
relation_with values.except(*skips)
|
99
54
|
end
|
100
55
|
|
101
56
|
# Removes any condition from the query other than the one(s) specified in +onlies+.
|
102
57
|
#
|
103
|
-
# Example:
|
104
|
-
#
|
105
58
|
# Post.order('id asc').only(:where) # discards the order condition
|
106
59
|
# Post.order('id asc').only(:where, :order) # uses the specified order
|
107
|
-
#
|
108
60
|
def only(*onlies)
|
109
|
-
|
110
|
-
result.default_scoped = default_scoped
|
111
|
-
|
112
|
-
((Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS) & onlies).each do |method|
|
113
|
-
result.send(:"#{method}_values=", send(:"#{method}_values"))
|
114
|
-
end
|
115
|
-
|
116
|
-
(Relation::SINGLE_VALUE_METHODS & onlies).each do |method|
|
117
|
-
result.send(:"#{method}_value=", send(:"#{method}_value"))
|
118
|
-
end
|
119
|
-
|
120
|
-
# Apply scope extension modules
|
121
|
-
result.send(:apply_modules, extensions)
|
122
|
-
|
123
|
-
result
|
124
|
-
end
|
125
|
-
|
126
|
-
VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset, :extend,
|
127
|
-
:order, :select, :readonly, :group, :having, :from, :lock ]
|
128
|
-
|
129
|
-
def apply_finder_options(options)
|
130
|
-
relation = clone
|
131
|
-
return relation unless options
|
132
|
-
|
133
|
-
options.assert_valid_keys(VALID_FIND_OPTIONS)
|
134
|
-
finders = options.dup
|
135
|
-
finders.delete_if { |key, value| value.nil? && key != :limit }
|
136
|
-
|
137
|
-
([:joins, :select, :group, :order, :having, :limit, :offset, :from, :lock, :readonly] & finders.keys).each do |finder|
|
138
|
-
relation = relation.send(finder, finders[finder])
|
139
|
-
end
|
140
|
-
|
141
|
-
relation = relation.where(finders[:conditions]) if options.has_key?(:conditions)
|
142
|
-
relation = relation.includes(finders[:include]) if options.has_key?(:include)
|
143
|
-
relation = relation.extending(finders[:extend]) if options.has_key?(:extend)
|
144
|
-
|
145
|
-
relation
|
61
|
+
relation_with values.slice(*onlies)
|
146
62
|
end
|
147
63
|
|
148
64
|
private
|
149
65
|
|
150
|
-
def
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
relation.joins_values += values
|
156
|
-
else
|
157
|
-
joins_dependency, rest = values.partition do |join|
|
158
|
-
case join
|
159
|
-
when Hash, Symbol, Array
|
160
|
-
true
|
161
|
-
else
|
162
|
-
false
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
join_dependency = ActiveRecord::Associations::JoinDependency.new(
|
167
|
-
other.klass,
|
168
|
-
joins_dependency,
|
169
|
-
[]
|
170
|
-
)
|
171
|
-
|
172
|
-
relation.joins_values += join_dependency.join_associations + rest
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def merge_relation_method(relation, method, value)
|
177
|
-
relation.send(:"#{method}_values=", relation.send(:"#{method}_values") + value)
|
66
|
+
def relation_with(values) # :nodoc:
|
67
|
+
result = Relation.new(klass, table, values)
|
68
|
+
result.default_scoped = default_scoped
|
69
|
+
result.extend(*extending_values) if extending_values.any?
|
70
|
+
result
|
178
71
|
end
|
179
72
|
end
|
180
73
|
end
|
data/lib/active_record/result.rb
CHANGED
@@ -8,12 +8,13 @@ module ActiveRecord
|
|
8
8
|
class Result
|
9
9
|
include Enumerable
|
10
10
|
|
11
|
-
attr_reader :columns, :rows
|
11
|
+
attr_reader :columns, :rows, :column_types
|
12
12
|
|
13
|
-
def initialize(columns, rows)
|
14
|
-
@columns
|
15
|
-
@rows
|
16
|
-
@hash_rows
|
13
|
+
def initialize(columns, rows, column_types = {})
|
14
|
+
@columns = columns
|
15
|
+
@rows = rows
|
16
|
+
@hash_rows = nil
|
17
|
+
@column_types = column_types
|
17
18
|
end
|
18
19
|
|
19
20
|
def each
|
@@ -24,12 +25,38 @@ module ActiveRecord
|
|
24
25
|
hash_rows
|
25
26
|
end
|
26
27
|
|
28
|
+
alias :map! :map
|
29
|
+
alias :collect! :map
|
30
|
+
|
31
|
+
# Returns true if there are no records.
|
32
|
+
def empty?
|
33
|
+
rows.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_ary
|
37
|
+
hash_rows
|
38
|
+
end
|
39
|
+
|
40
|
+
def [](idx)
|
41
|
+
hash_rows[idx]
|
42
|
+
end
|
43
|
+
|
44
|
+
def last
|
45
|
+
hash_rows.last
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize_copy(other)
|
49
|
+
@columns = columns.dup
|
50
|
+
@rows = rows.dup
|
51
|
+
@hash_rows = nil
|
52
|
+
end
|
53
|
+
|
27
54
|
private
|
28
55
|
def hash_rows
|
29
56
|
@hash_rows ||=
|
30
57
|
begin
|
31
58
|
# We freeze the strings to prevent them getting duped when
|
32
|
-
# used as keys in ActiveRecord::
|
59
|
+
# used as keys in ActiveRecord::Base's @attributes hash
|
33
60
|
columns = @columns.map { |c| c.dup.freeze }
|
34
61
|
@rows.map { |row|
|
35
62
|
Hash[columns.zip(row)]
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'active_support/concern'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
2
|
module Sanitization
|
5
3
|
extend ActiveSupport::Concern
|
@@ -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?
|
@@ -34,12 +32,12 @@ module ActiveRecord
|
|
34
32
|
|
35
33
|
# Accepts an array, hash, or string of SQL conditions and sanitizes
|
36
34
|
# them into a valid SQL fragment for a SET clause.
|
37
|
-
# { :
|
38
|
-
def sanitize_sql_for_assignment(assignments)
|
35
|
+
# { name: nil, group_id: 4 } returns "name = NULL , group_id='4'"
|
36
|
+
def sanitize_sql_for_assignment(assignments, default_table_name = self.table_name)
|
39
37
|
case assignments
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
when Array; sanitize_sql_array(assignments)
|
39
|
+
when Hash; sanitize_sql_hash_for_assignment(assignments, default_table_name)
|
40
|
+
else assignments
|
43
41
|
end
|
44
42
|
end
|
45
43
|
|
@@ -48,17 +46,17 @@ module ActiveRecord
|
|
48
46
|
# aggregate attribute values.
|
49
47
|
# Given:
|
50
48
|
# class Person < ActiveRecord::Base
|
51
|
-
# composed_of :address, :
|
52
|
-
# :
|
49
|
+
# composed_of :address, class_name: "Address",
|
50
|
+
# mapping: [%w(address_street street), %w(address_city city)]
|
53
51
|
# end
|
54
52
|
# Then:
|
55
|
-
# { :
|
56
|
-
# # => { :
|
53
|
+
# { address: Address.new("813 abc st.", "chicago") }
|
54
|
+
# # => { address_street: "813 abc st.", address_city: "chicago" }
|
57
55
|
def expand_hash_conditions_for_aggregates(attrs)
|
58
56
|
expanded_attrs = {}
|
59
57
|
attrs.each do |attr, value|
|
60
|
-
|
61
|
-
mapping =
|
58
|
+
if aggregation = reflect_on_aggregation(attr.to_sym)
|
59
|
+
mapping = aggregation.mapping
|
62
60
|
mapping.each do |field_attr, aggregate_attr|
|
63
61
|
if mapping.size == 1 && !value.respond_to?(aggregate_attr)
|
64
62
|
expanded_attrs[field_attr] = value
|
@@ -74,35 +72,35 @@ module ActiveRecord
|
|
74
72
|
end
|
75
73
|
|
76
74
|
# Sanitizes a hash of attribute/value pairs into SQL conditions for a WHERE clause.
|
77
|
-
# { :
|
75
|
+
# { name: "foo'bar", group_id: 4 }
|
78
76
|
# # => "name='foo''bar' and group_id= 4"
|
79
|
-
# { :
|
77
|
+
# { status: nil, group_id: [1,2,3] }
|
80
78
|
# # => "status IS NULL and group_id IN (1,2,3)"
|
81
|
-
# { :
|
79
|
+
# { age: 13..18 }
|
82
80
|
# # => "age BETWEEN 13 AND 18"
|
83
81
|
# { 'other_records.id' => 7 }
|
84
82
|
# # => "`other_records`.`id` = 7"
|
85
|
-
# { :
|
83
|
+
# { other_records: { id: 7 } }
|
86
84
|
# # => "`other_records`.`id` = 7"
|
87
85
|
# And for value objects on a composed_of relationship:
|
88
|
-
# { :
|
86
|
+
# { address: Address.new("123 abc st.", "chicago") }
|
89
87
|
# # => "address_street='123 abc st.' and address_city='chicago'"
|
90
88
|
def sanitize_sql_hash_for_conditions(attrs, default_table_name = self.table_name)
|
91
89
|
attrs = expand_hash_conditions_for_aggregates(attrs)
|
92
90
|
|
93
|
-
table = Arel::Table.new(table_name).alias(default_table_name)
|
94
|
-
PredicateBuilder.build_from_hash(
|
91
|
+
table = Arel::Table.new(table_name, arel_engine).alias(default_table_name)
|
92
|
+
PredicateBuilder.build_from_hash(self.class, attrs, table).map { |b|
|
95
93
|
connection.visitor.accept b
|
96
94
|
}.join(' AND ')
|
97
95
|
end
|
98
96
|
alias_method :sanitize_sql_hash, :sanitize_sql_hash_for_conditions
|
99
97
|
|
100
98
|
# Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause.
|
101
|
-
# { :
|
99
|
+
# { status: nil, group_id: 1 }
|
102
100
|
# # => "status = NULL , group_id = 1"
|
103
|
-
def sanitize_sql_hash_for_assignment(attrs)
|
101
|
+
def sanitize_sql_hash_for_assignment(attrs, table)
|
104
102
|
attrs.map do |attr, value|
|
105
|
-
"#{connection.
|
103
|
+
"#{connection.quote_table_name_for_assignment(table, attr)} = #{quote_bound_value(value)}"
|
106
104
|
end.join(', ')
|
107
105
|
end
|
108
106
|
|
@@ -143,23 +141,6 @@ module ActiveRecord
|
|
143
141
|
end
|
144
142
|
end
|
145
143
|
|
146
|
-
def expand_range_bind_variables(bind_vars) #:nodoc:
|
147
|
-
expanded = []
|
148
|
-
|
149
|
-
bind_vars.each do |var|
|
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
144
|
def quote_bound_value(value, c = connection) #:nodoc:
|
164
145
|
if value.respond_to?(:map) && !value.acts_like?(:string)
|
165
146
|
if value.respond_to?(:empty?) && value.empty?
|
@@ -180,15 +161,8 @@ module ActiveRecord
|
|
180
161
|
end
|
181
162
|
|
182
163
|
# 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)
|
164
|
+
def quoted_id
|
165
|
+
self.class.quote_value(id, column_for_attribute(self.class.primary_key))
|
192
166
|
end
|
193
167
|
end
|
194
168
|
end
|
data/lib/active_record/schema.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'active_support/core_ext/object/blank'
|
2
1
|
|
3
2
|
module ActiveRecord
|
4
3
|
# = Active Record Schema
|
@@ -12,16 +11,16 @@ module ActiveRecord
|
|
12
11
|
#
|
13
12
|
# ActiveRecord::Schema.define do
|
14
13
|
# create_table :authors do |t|
|
15
|
-
# t.string :name, :
|
14
|
+
# t.string :name, null: false
|
16
15
|
# end
|
17
16
|
#
|
18
17
|
# add_index :authors, :name, :unique
|
19
18
|
#
|
20
19
|
# create_table :posts do |t|
|
21
|
-
# t.integer :author_id, :
|
20
|
+
# t.integer :author_id, null: false
|
22
21
|
# t.string :subject
|
23
22
|
# t.text :body
|
24
|
-
# t.boolean :private, :
|
23
|
+
# t.boolean :private, default: false
|
25
24
|
# end
|
26
25
|
#
|
27
26
|
# add_index :posts, :author_id
|
@@ -30,10 +29,24 @@ module ActiveRecord
|
|
30
29
|
# ActiveRecord::Schema is only supported by database adapters that also
|
31
30
|
# support migrations, the two features being very similar.
|
32
31
|
class Schema < Migration
|
32
|
+
|
33
|
+
# Returns the migrations paths.
|
34
|
+
#
|
35
|
+
# ActiveRecord::Schema.new.migrations_paths
|
36
|
+
# # => ["db/migrate"] # Rails migration path by default.
|
33
37
|
def migrations_paths
|
34
38
|
ActiveRecord::Migrator.migrations_paths
|
35
39
|
end
|
36
40
|
|
41
|
+
def define(info, &block) # :nodoc:
|
42
|
+
instance_eval(&block)
|
43
|
+
|
44
|
+
unless info[:version].blank?
|
45
|
+
initialize_schema_migrations_table
|
46
|
+
assume_migrated_upto_version(info[:version], migrations_paths)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
37
50
|
# Eval the given block. All methods available to the current connection
|
38
51
|
# adapter are available within the block, so you can easily use the
|
39
52
|
# database definition DSL to build up your schema (+create_table+,
|
@@ -42,17 +55,11 @@ module ActiveRecord
|
|
42
55
|
# The +info+ hash is optional, and if given is used to define metadata
|
43
56
|
# about the current schema (currently, only the schema's version):
|
44
57
|
#
|
45
|
-
# ActiveRecord::Schema.define(:
|
58
|
+
# ActiveRecord::Schema.define(version: 20380119000001) do
|
46
59
|
# ...
|
47
60
|
# end
|
48
61
|
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
|
62
|
+
new.define(info, &block)
|
56
63
|
end
|
57
64
|
end
|
58
65
|
end
|