activerecord 4.1.15 → 4.2.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1162 -1792
- data/README.rdoc +15 -10
- data/lib/active_record.rb +4 -0
- data/lib/active_record/aggregations.rb +15 -8
- data/lib/active_record/association_relation.rb +13 -0
- data/lib/active_record/associations.rb +158 -49
- data/lib/active_record/associations/alias_tracker.rb +3 -12
- data/lib/active_record/associations/association.rb +16 -4
- data/lib/active_record/associations/association_scope.rb +83 -38
- data/lib/active_record/associations/belongs_to_association.rb +28 -10
- data/lib/active_record/associations/builder/association.rb +15 -4
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/collection_association.rb +5 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -13
- data/lib/active_record/associations/builder/has_many.rb +1 -1
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +63 -27
- data/lib/active_record/associations/collection_proxy.rb +29 -35
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +83 -22
- data/lib/active_record/associations/has_many_through_association.rb +49 -26
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +26 -13
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
- data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
- data/lib/active_record/associations/preloader.rb +36 -26
- data/lib/active_record/associations/preloader/association.rb +14 -11
- data/lib/active_record/associations/preloader/through_association.rb +4 -3
- data/lib/active_record/associations/singular_association.rb +17 -2
- data/lib/active_record/associations/through_association.rb +5 -12
- data/lib/active_record/attribute.rb +163 -0
- data/lib/active_record/attribute_assignment.rb +19 -11
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods.rb +56 -94
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +107 -43
- data/lib/active_record/attribute_methods/primary_key.rb +7 -8
- data/lib/active_record/attribute_methods/query.rb +1 -1
- data/lib/active_record/attribute_methods/read.rb +22 -59
- data/lib/active_record/attribute_methods/serialization.rb +16 -150
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -40
- data/lib/active_record/attribute_methods/write.rb +9 -24
- data/lib/active_record/attribute_set.rb +81 -0
- data/lib/active_record/attribute_set/builder.rb +106 -0
- data/lib/active_record/attributes.rb +147 -0
- data/lib/active_record/autosave_association.rb +19 -12
- data/lib/active_record/base.rb +13 -24
- data/lib/active_record/callbacks.rb +6 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +84 -52
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +138 -56
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +268 -71
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
- data/lib/active_record/connection_adapters/abstract_adapter.rb +171 -59
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +293 -139
- data/lib/active_record/connection_adapters/column.rb +29 -240
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
- data/lib/active_record/connection_adapters/mysql_adapter.rb +67 -144
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -25
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
- 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/quoting.rb +46 -136
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +131 -43
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +163 -39
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +9 -11
- data/lib/active_record/errors.rb +53 -30
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixtures.rb +55 -69
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +35 -10
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/locking/optimistic.rb +46 -26
- data/lib/active_record/migration.rb +71 -46
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/model_schema.rb +52 -58
- data/lib/active_record/nested_attributes.rb +5 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +46 -26
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +10 -7
- data/lib/active_record/railtie.rb +18 -11
- data/lib/active_record/railties/databases.rake +50 -51
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +273 -114
- data/lib/active_record/relation.rb +57 -25
- data/lib/active_record/relation/batches.rb +0 -2
- data/lib/active_record/relation/calculations.rb +41 -37
- data/lib/active_record/relation/finder_methods.rb +70 -47
- data/lib/active_record/relation/merger.rb +39 -29
- data/lib/active_record/relation/predicate_builder.rb +16 -8
- data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -5
- data/lib/active_record/relation/query_methods.rb +114 -65
- data/lib/active_record/relation/spawn_methods.rb +3 -0
- data/lib/active_record/result.rb +18 -7
- data/lib/active_record/sanitization.rb +12 -2
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +59 -28
- data/lib/active_record/schema_migration.rb +5 -4
- data/lib/active_record/scoping/default.rb +6 -4
- data/lib/active_record/scoping/named.rb +4 -0
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +95 -10
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +61 -6
- data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
- data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +53 -27
- data/lib/active_record/type.rb +23 -0
- 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/validations.rb +25 -19
- data/lib/active_record/validations/associated.rb +5 -3
- data/lib/active_record/validations/presence.rb +5 -3
- data/lib/active_record/validations/uniqueness.rb +25 -29
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +66 -11
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -62,6 +62,9 @@ module ActiveRecord
|
|
62
62
|
# Post.order('id asc').only(:where) # discards the order condition
|
63
63
|
# Post.order('id asc').only(:where, :order) # uses the specified order
|
64
64
|
def only(*onlies)
|
65
|
+
if onlies.any? { |o| o == :where }
|
66
|
+
onlies << :bind
|
67
|
+
end
|
65
68
|
relation_with values.slice(*onlies)
|
66
69
|
end
|
67
70
|
|
data/lib/active_record/result.rb
CHANGED
@@ -31,7 +31,7 @@ module ActiveRecord
|
|
31
31
|
class Result
|
32
32
|
include Enumerable
|
33
33
|
|
34
|
-
IDENTITY_TYPE =
|
34
|
+
IDENTITY_TYPE = Type::Value.new # :nodoc:
|
35
35
|
|
36
36
|
attr_reader :columns, :rows, :column_types
|
37
37
|
|
@@ -42,12 +42,8 @@ module ActiveRecord
|
|
42
42
|
@column_types = column_types
|
43
43
|
end
|
44
44
|
|
45
|
-
def
|
46
|
-
|
47
|
-
end
|
48
|
-
|
49
|
-
def column_type(name)
|
50
|
-
@column_types[name] || identity_type
|
45
|
+
def length
|
46
|
+
@rows.length
|
51
47
|
end
|
52
48
|
|
53
49
|
def each
|
@@ -82,6 +78,15 @@ module ActiveRecord
|
|
82
78
|
hash_rows.last
|
83
79
|
end
|
84
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
|
+
|
85
90
|
def initialize_copy(other)
|
86
91
|
@columns = columns.dup
|
87
92
|
@rows = rows.dup
|
@@ -91,6 +96,12 @@ module ActiveRecord
|
|
91
96
|
|
92
97
|
private
|
93
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
|
+
|
94
105
|
def hash_rows
|
95
106
|
@hash_rows ||=
|
96
107
|
begin
|
@@ -87,12 +87,15 @@ module ActiveRecord
|
|
87
87
|
# { address: Address.new("123 abc st.", "chicago") }
|
88
88
|
# # => "address_street='123 abc st.' and address_city='chicago'"
|
89
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
|
90
93
|
attrs = PredicateBuilder.resolve_column_aliases self, attrs
|
91
94
|
attrs = expand_hash_conditions_for_aggregates(attrs)
|
92
95
|
|
93
96
|
table = Arel::Table.new(table_name, arel_engine).alias(default_table_name)
|
94
97
|
PredicateBuilder.build_from_hash(self, attrs, table).map { |b|
|
95
|
-
connection.visitor.
|
98
|
+
connection.visitor.compile b
|
96
99
|
}.join(' AND ')
|
97
100
|
end
|
98
101
|
alias_method :sanitize_sql_hash, :sanitize_sql_hash_for_conditions
|
@@ -107,6 +110,13 @@ module ActiveRecord
|
|
107
110
|
end.join(', ')
|
108
111
|
end
|
109
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
|
+
|
110
120
|
# Accepts an array of conditions. The array has each value
|
111
121
|
# sanitized and interpolated into the SQL statement.
|
112
122
|
# ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
|
@@ -127,7 +137,7 @@ module ActiveRecord
|
|
127
137
|
raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
|
128
138
|
bound = values.dup
|
129
139
|
c = connection
|
130
|
-
statement.gsub(
|
140
|
+
statement.gsub(/\?/) do
|
131
141
|
replace_bind_variable(bound.shift, c)
|
132
142
|
end
|
133
143
|
end
|
data/lib/active_record/schema.rb
CHANGED
@@ -91,16 +91,17 @@ HEADER
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def tables(stream)
|
94
|
-
@connection.tables.sort
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
94
|
+
sorted_tables = @connection.tables.sort
|
95
|
+
|
96
|
+
sorted_tables.each do |table_name|
|
97
|
+
table(table_name, stream) unless ignored?(table_name)
|
98
|
+
end
|
99
|
+
|
100
|
+
# dump foreign keys at the end to make sure all dependent tables exist.
|
101
|
+
if @connection.supports_foreign_keys?
|
102
|
+
sorted_tables.each do |tbl|
|
103
|
+
foreign_keys(tbl, stream) unless ignored?(tbl)
|
102
104
|
end
|
103
|
-
table(tbl, stream)
|
104
105
|
end
|
105
106
|
end
|
106
107
|
|
@@ -110,26 +111,23 @@ HEADER
|
|
110
111
|
tbl = StringIO.new
|
111
112
|
|
112
113
|
# first dump primary key column
|
113
|
-
|
114
|
-
pk, _ = @connection.pk_and_sequence_for(table)
|
115
|
-
end
|
116
|
-
if !pk && @connection.respond_to?(:primary_key)
|
117
|
-
pk = @connection.primary_key(table)
|
118
|
-
end
|
114
|
+
pk = @connection.primary_key(table)
|
119
115
|
|
120
116
|
tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}"
|
121
117
|
pkcol = columns.detect { |c| c.name == pk }
|
122
118
|
if pkcol
|
123
119
|
if pk != 'id'
|
124
120
|
tbl.print %Q(, primary_key: "#{pk}")
|
121
|
+
elsif pkcol.sql_type == 'bigint'
|
122
|
+
tbl.print ", id: :bigserial"
|
125
123
|
elsif pkcol.sql_type == 'uuid'
|
126
124
|
tbl.print ", id: :uuid"
|
127
|
-
tbl.print %Q(, default:
|
125
|
+
tbl.print %Q(, default: #{pkcol.default_function.inspect})
|
128
126
|
end
|
129
127
|
else
|
130
128
|
tbl.print ", id: false"
|
131
129
|
end
|
132
|
-
tbl.print ", force:
|
130
|
+
tbl.print ", force: :cascade"
|
133
131
|
tbl.puts " do |t|"
|
134
132
|
|
135
133
|
# then dump all non-primary key columns
|
@@ -187,34 +185,67 @@ HEADER
|
|
187
185
|
if (indexes = @connection.indexes(table)).any?
|
188
186
|
add_index_statements = indexes.map do |index|
|
189
187
|
statement_parts = [
|
190
|
-
|
188
|
+
"add_index #{remove_prefix_and_suffix(index.table).inspect}",
|
191
189
|
index.columns.inspect,
|
192
|
-
|
190
|
+
"name: #{index.name.inspect}",
|
193
191
|
]
|
194
192
|
statement_parts << 'unique: true' if index.unique
|
195
193
|
|
196
194
|
index_lengths = (index.lengths || []).compact
|
197
|
-
statement_parts <<
|
195
|
+
statement_parts << "length: #{Hash[index.columns.zip(index.lengths)].inspect}" if index_lengths.any?
|
196
|
+
|
197
|
+
index_orders = index.orders || {}
|
198
|
+
statement_parts << "order: #{index.orders.inspect}" if index_orders.any?
|
199
|
+
statement_parts << "where: #{index.where.inspect}" if index.where
|
200
|
+
statement_parts << "using: #{index.using.inspect}" if index.using
|
201
|
+
statement_parts << "type: #{index.type.inspect}" if index.type
|
202
|
+
|
203
|
+
" #{statement_parts.join(', ')}"
|
204
|
+
end
|
205
|
+
|
206
|
+
stream.puts add_index_statements.sort.join("\n")
|
207
|
+
stream.puts
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def foreign_keys(table, stream)
|
212
|
+
if (foreign_keys = @connection.foreign_keys(table)).any?
|
213
|
+
add_foreign_key_statements = foreign_keys.map do |foreign_key|
|
214
|
+
parts = [
|
215
|
+
"add_foreign_key #{remove_prefix_and_suffix(foreign_key.from_table).inspect}",
|
216
|
+
remove_prefix_and_suffix(foreign_key.to_table).inspect,
|
217
|
+
]
|
198
218
|
|
199
|
-
|
200
|
-
|
219
|
+
if foreign_key.column != @connection.foreign_key_column_for(foreign_key.to_table)
|
220
|
+
parts << "column: #{foreign_key.column.inspect}"
|
221
|
+
end
|
201
222
|
|
202
|
-
|
223
|
+
if foreign_key.custom_primary_key?
|
224
|
+
parts << "primary_key: #{foreign_key.primary_key.inspect}"
|
225
|
+
end
|
203
226
|
|
204
|
-
|
227
|
+
if foreign_key.name !~ /^fk_rails_[0-9a-f]{10}$/
|
228
|
+
parts << "name: #{foreign_key.name.inspect}"
|
229
|
+
end
|
205
230
|
|
206
|
-
|
231
|
+
parts << "on_update: #{foreign_key.on_update.inspect}" if foreign_key.on_update
|
232
|
+
parts << "on_delete: #{foreign_key.on_delete.inspect}" if foreign_key.on_delete
|
207
233
|
|
208
|
-
|
234
|
+
" #{parts.join(', ')}"
|
209
235
|
end
|
210
236
|
|
211
|
-
stream.puts
|
212
|
-
stream.puts
|
237
|
+
stream.puts add_foreign_key_statements.sort.join("\n")
|
213
238
|
end
|
214
239
|
end
|
215
240
|
|
216
241
|
def remove_prefix_and_suffix(table)
|
217
242
|
table.gsub(/^(#{@options[:table_name_prefix]})(.+)(#{@options[:table_name_suffix]})$/, "\\2")
|
218
243
|
end
|
244
|
+
|
245
|
+
def ignored?(table_name)
|
246
|
+
['schema_migrations', ignore_tables].flatten.any? do |ignored|
|
247
|
+
ignored === remove_prefix_and_suffix(table_name)
|
248
|
+
end
|
249
|
+
end
|
219
250
|
end
|
220
251
|
end
|
@@ -34,15 +34,16 @@ module ActiveRecord
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def drop_table
|
37
|
-
if table_exists?
|
38
|
-
connection.remove_index table_name, name: index_name
|
39
|
-
connection.drop_table(table_name)
|
40
|
-
end
|
37
|
+
connection.drop_table table_name if table_exists?
|
41
38
|
end
|
42
39
|
|
43
40
|
def normalize_migration_number(number)
|
44
41
|
"%.3d" % number.to_i
|
45
42
|
end
|
43
|
+
|
44
|
+
def normalized_versions
|
45
|
+
pluck(:version).map { |v| normalize_migration_number v }
|
46
|
+
end
|
46
47
|
end
|
47
48
|
|
48
49
|
def version
|
@@ -11,7 +11,7 @@ module ActiveRecord
|
|
11
11
|
end
|
12
12
|
|
13
13
|
module ClassMethods
|
14
|
-
# Returns a scope for the model without the
|
14
|
+
# Returns a scope for the model without the previously set scopes.
|
15
15
|
#
|
16
16
|
# class Post < ActiveRecord::Base
|
17
17
|
# def self.default_scope
|
@@ -19,11 +19,12 @@ module ActiveRecord
|
|
19
19
|
# end
|
20
20
|
# end
|
21
21
|
#
|
22
|
-
# Post.all
|
23
|
-
# Post.unscoped.all
|
22
|
+
# Post.all # Fires "SELECT * FROM posts WHERE published = true"
|
23
|
+
# Post.unscoped.all # Fires "SELECT * FROM posts"
|
24
|
+
# Post.where(published: false).unscoped.all # Fires "SELECT * FROM posts"
|
24
25
|
#
|
25
26
|
# This method also accepts a block. All queries inside the block will
|
26
|
-
# not use the
|
27
|
+
# not use the previously set scopes.
|
27
28
|
#
|
28
29
|
# Post.unscoped {
|
29
30
|
# Post.limit(10) # Fires "SELECT * FROM posts LIMIT 10"
|
@@ -94,6 +95,7 @@ module ActiveRecord
|
|
94
95
|
end
|
95
96
|
|
96
97
|
def build_default_scope(base_rel = relation) # :nodoc:
|
98
|
+
return if abstract_class?
|
97
99
|
if !Base.is_a?(method(:default_scope).owner)
|
98
100
|
# The user has defined their own default scope method, so call that
|
99
101
|
evaluate_default_scope { default_scope }
|
@@ -139,6 +139,10 @@ module ActiveRecord
|
|
139
139
|
# Article.published.featured.latest_article
|
140
140
|
# Article.featured.titles
|
141
141
|
def scope(name, body, &block)
|
142
|
+
unless body.respond_to?(:call)
|
143
|
+
raise ArgumentError, 'The scope body needs to be callable.'
|
144
|
+
end
|
145
|
+
|
142
146
|
if dangerous_class_method?(name)
|
143
147
|
raise ArgumentError, "You tried to define a scope named \"#{name}\" " \
|
144
148
|
"on the model \"#{self.name}\", but Active Record already defined " \
|
@@ -180,13 +180,9 @@ module ActiveRecord #:nodoc:
|
|
180
180
|
class Attribute < ActiveModel::Serializers::Xml::Serializer::Attribute #:nodoc:
|
181
181
|
def compute_type
|
182
182
|
klass = @serializable.class
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
klass.columns_hash[name].type
|
187
|
-
else
|
188
|
-
NilClass
|
189
|
-
end
|
183
|
+
column = klass.columns_hash[name] || Type::Value.new
|
184
|
+
|
185
|
+
type = ActiveSupport::XmlMini::TYPE_NAMES[value.class.name] || column.type
|
190
186
|
|
191
187
|
{ :text => :string,
|
192
188
|
:time => :datetime }[type] || type
|
@@ -1,26 +1,111 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
|
3
3
|
# Statement cache is used to cache a single statement in order to avoid creating the AST again.
|
4
|
-
# Initializing the cache is done by passing the statement in the
|
4
|
+
# Initializing the cache is done by passing the statement in the create block:
|
5
5
|
#
|
6
|
-
# cache =
|
7
|
-
# Book.where(name: "my book").
|
6
|
+
# cache = StatementCache.create(Book.connection) do |params|
|
7
|
+
# Book.where(name: "my book").where("author_id > 3")
|
8
8
|
# end
|
9
9
|
#
|
10
10
|
# The cached statement is executed by using the +execute+ method:
|
11
11
|
#
|
12
|
-
# cache.execute
|
12
|
+
# cache.execute([], Book, Book.connection)
|
13
13
|
#
|
14
14
|
# The relation returned by the block is cached, and for each +execute+ call the cached relation gets duped.
|
15
15
|
# Database is queried when +to_a+ is called on the relation.
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
#
|
17
|
+
# If you want to cache the statement without the values you can use the +bind+ method of the
|
18
|
+
# block parameter.
|
19
|
+
#
|
20
|
+
# cache = StatementCache.create(Book.connection) do |params|
|
21
|
+
# Book.where(name: params.bind)
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# And pass the bind values as the first argument of +execute+ call.
|
25
|
+
#
|
26
|
+
# cache.execute(["my book"], Book, Book.connection)
|
27
|
+
class StatementCache # :nodoc:
|
28
|
+
class Substitute; end # :nodoc:
|
29
|
+
|
30
|
+
class Query # :nodoc:
|
31
|
+
def initialize(sql)
|
32
|
+
@sql = sql
|
33
|
+
end
|
34
|
+
|
35
|
+
def sql_for(binds, connection)
|
36
|
+
@sql
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class PartialQuery < Query # :nodoc:
|
41
|
+
def initialize values
|
42
|
+
@values = values
|
43
|
+
@indexes = values.each_with_index.find_all { |thing,i|
|
44
|
+
Arel::Nodes::BindParam === thing
|
45
|
+
}.map(&:last)
|
46
|
+
end
|
47
|
+
|
48
|
+
def sql_for(binds, connection)
|
49
|
+
val = @values.dup
|
50
|
+
binds = binds.dup
|
51
|
+
@indexes.each { |i| val[i] = connection.quote(*binds.shift.reverse) }
|
52
|
+
val.join
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.query(visitor, ast)
|
57
|
+
Query.new visitor.accept(ast, Arel::Collectors::SQLString.new).value
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.partial_query(visitor, ast, collector)
|
61
|
+
collected = visitor.accept(ast, collector).value
|
62
|
+
PartialQuery.new collected
|
20
63
|
end
|
21
64
|
|
22
|
-
|
23
|
-
|
65
|
+
class Params # :nodoc:
|
66
|
+
def bind; Substitute.new; end
|
67
|
+
end
|
68
|
+
|
69
|
+
class BindMap # :nodoc:
|
70
|
+
def initialize(bind_values)
|
71
|
+
@indexes = []
|
72
|
+
@bind_values = bind_values
|
73
|
+
|
74
|
+
bind_values.each_with_index do |(_, value), i|
|
75
|
+
if Substitute === value
|
76
|
+
@indexes << i
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def bind(values)
|
82
|
+
bvs = @bind_values.map { |pair| pair.dup }
|
83
|
+
@indexes.each_with_index { |offset,i| bvs[offset][1] = values[i] }
|
84
|
+
bvs
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
attr_reader :bind_map, :query_builder
|
89
|
+
|
90
|
+
def self.create(connection, block = Proc.new)
|
91
|
+
relation = block.call Params.new
|
92
|
+
bind_map = BindMap.new relation.bind_values
|
93
|
+
query_builder = connection.cacheable_query relation.arel
|
94
|
+
new query_builder, bind_map
|
95
|
+
end
|
96
|
+
|
97
|
+
def initialize(query_builder, bind_map)
|
98
|
+
@query_builder = query_builder
|
99
|
+
@bind_map = bind_map
|
100
|
+
end
|
101
|
+
|
102
|
+
def execute(params, klass, connection)
|
103
|
+
bind_values = bind_map.bind params
|
104
|
+
|
105
|
+
sql = query_builder.sql_for bind_values, connection
|
106
|
+
|
107
|
+
klass.find_by_sql sql, bind_values
|
24
108
|
end
|
109
|
+
alias :call :execute
|
25
110
|
end
|
26
111
|
end
|