activerecord 4.1.0 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +776 -1330
- data/README.rdoc +15 -10
- data/lib/active_record/aggregations.rb +12 -8
- data/lib/active_record/association_relation.rb +4 -0
- data/lib/active_record/associations/alias_tracker.rb +14 -13
- data/lib/active_record/associations/association.rb +2 -2
- data/lib/active_record/associations/association_scope.rb +83 -43
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- 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/has_and_belongs_to_many.rb +9 -6
- 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 +66 -29
- data/lib/active_record/associations/collection_proxy.rb +22 -26
- data/lib/active_record/associations/has_many_association.rb +65 -18
- data/lib/active_record/associations/has_many_through_association.rb +55 -27
- data/lib/active_record/associations/has_one_association.rb +0 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +19 -15
- data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
- data/lib/active_record/associations/join_dependency.rb +20 -12
- data/lib/active_record/associations/preloader/association.rb +34 -11
- data/lib/active_record/associations/preloader/through_association.rb +4 -3
- data/lib/active_record/associations/preloader.rb +49 -59
- data/lib/active_record/associations/singular_association.rb +25 -4
- data/lib/active_record/associations/through_association.rb +23 -14
- data/lib/active_record/associations.rb +171 -42
- data/lib/active_record/attribute.rb +149 -0
- data/lib/active_record/attribute_assignment.rb +18 -10
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
- data/lib/active_record/attribute_methods/dirty.rb +98 -44
- data/lib/active_record/attribute_methods/primary_key.rb +14 -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 +37 -147
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +34 -28
- data/lib/active_record/attribute_methods/write.rb +14 -21
- data/lib/active_record/attribute_methods.rb +67 -94
- data/lib/active_record/attribute_set/builder.rb +86 -0
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attributes.rb +139 -0
- data/lib/active_record/autosave_association.rb +45 -38
- data/lib/active_record/base.rb +10 -20
- data/lib/active_record/callbacks.rb +7 -7
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +78 -52
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +38 -59
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -55
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +126 -54
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +198 -64
- data/lib/active_record/connection_adapters/abstract/transaction.rb +126 -114
- data/lib/active_record/connection_adapters/abstract_adapter.rb +154 -55
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +240 -135
- data/lib/active_record/connection_adapters/column.rb +28 -239
- data/lib/active_record/connection_adapters/connection_specification.rb +16 -25
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +20 -22
- data/lib/active_record/connection_adapters/mysql_adapter.rb +65 -149
- 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 +39 -27
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +99 -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 +14 -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 +27 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -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 +15 -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 +97 -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 +29 -374
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +55 -135
- 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 +127 -38
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +220 -466
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -61
- data/lib/active_record/connection_handling.rb +3 -3
- data/lib/active_record/core.rb +143 -32
- data/lib/active_record/counter_cache.rb +60 -7
- data/lib/active_record/enum.rb +10 -11
- data/lib/active_record/errors.rb +49 -27
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixtures.rb +56 -70
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +35 -10
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/locking/optimistic.rb +35 -17
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +52 -49
- data/lib/active_record/model_schema.rb +49 -57
- data/lib/active_record/nested_attributes.rb +7 -7
- data/lib/active_record/null_relation.rb +19 -5
- data/lib/active_record/persistence.rb +50 -31
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +10 -7
- data/lib/active_record/railtie.rb +14 -11
- data/lib/active_record/railties/databases.rake +56 -54
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +286 -102
- data/lib/active_record/relation/batches.rb +0 -1
- data/lib/active_record/relation/calculations.rb +39 -31
- data/lib/active_record/relation/delegation.rb +2 -2
- data/lib/active_record/relation/finder_methods.rb +80 -36
- data/lib/active_record/relation/merger.rb +25 -30
- data/lib/active_record/relation/predicate_builder/array_handler.rb +31 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +11 -10
- data/lib/active_record/relation/query_methods.rb +141 -55
- data/lib/active_record/relation/spawn_methods.rb +3 -0
- data/lib/active_record/relation.rb +69 -30
- 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 +58 -26
- data/lib/active_record/schema_migration.rb +11 -0
- data/lib/active_record/scoping/default.rb +8 -7
- 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 +19 -10
- data/lib/active_record/tasks/database_tasks.rb +73 -7
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -2
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +11 -9
- data/lib/active_record/transactions.rb +37 -21
- 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 +30 -0
- data/lib/active_record/type/date.rb +46 -0
- data/lib/active_record/type/date_time.rb +43 -0
- data/lib/active_record/type/decimal.rb +40 -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 +17 -0
- data/lib/active_record/type/integer.rb +55 -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 +56 -0
- data/lib/active_record/type/string.rb +36 -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 +101 -0
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/validations/associated.rb +5 -3
- data/lib/active_record/validations/presence.rb +6 -4
- data/lib/active_record/validations/uniqueness.rb +11 -17
- data/lib/active_record/validations.rb +25 -19
- data/lib/active_record.rb +3 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +4 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb +6 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +65 -10
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
module ActiveRecord
|
3
2
|
module ConnectionAdapters
|
4
3
|
class SchemaCache
|
@@ -12,15 +11,15 @@ module ActiveRecord
|
|
12
11
|
@columns_hash = {}
|
13
12
|
@primary_keys = {}
|
14
13
|
@tables = {}
|
15
|
-
prepare_default_proc
|
16
14
|
end
|
17
15
|
|
18
16
|
def primary_keys(table_name)
|
19
|
-
@primary_keys[table_name]
|
17
|
+
@primary_keys[table_name] ||= table_exists?(table_name) ? connection.primary_key(table_name) : nil
|
20
18
|
end
|
21
19
|
|
22
20
|
# A cached lookup for table existence.
|
23
21
|
def table_exists?(name)
|
22
|
+
prepare_tables if @tables.empty?
|
24
23
|
return @tables[name] if @tables.key? name
|
25
24
|
|
26
25
|
@tables[name] = connection.table_exists?(name)
|
@@ -29,9 +28,9 @@ module ActiveRecord
|
|
29
28
|
# Add internal cache for table with +table_name+.
|
30
29
|
def add(table_name)
|
31
30
|
if table_exists?(table_name)
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
primary_keys(table_name)
|
32
|
+
columns(table_name)
|
33
|
+
columns_hash(table_name)
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
@@ -40,14 +39,16 @@ module ActiveRecord
|
|
40
39
|
end
|
41
40
|
|
42
41
|
# Get the columns for a table
|
43
|
-
def columns(
|
44
|
-
@columns[
|
42
|
+
def columns(table_name)
|
43
|
+
@columns[table_name] ||= connection.columns(table_name)
|
45
44
|
end
|
46
45
|
|
47
46
|
# Get the columns for a table as a hash, key is the column name
|
48
47
|
# value is the column object.
|
49
|
-
def columns_hash(
|
50
|
-
@columns_hash[
|
48
|
+
def columns_hash(table_name)
|
49
|
+
@columns_hash[table_name] ||= Hash[columns(table_name).map { |col|
|
50
|
+
[col.name, col]
|
51
|
+
}]
|
51
52
|
end
|
52
53
|
|
53
54
|
# Clears out internal caches
|
@@ -76,33 +77,18 @@ module ActiveRecord
|
|
76
77
|
def marshal_dump
|
77
78
|
# if we get current version during initialization, it happens stack over flow.
|
78
79
|
@version = ActiveRecord::Migrator.current_version
|
79
|
-
[@version
|
80
|
-
Hash[val]
|
81
|
-
}
|
80
|
+
[@version, @columns, @columns_hash, @primary_keys, @tables]
|
82
81
|
end
|
83
82
|
|
84
83
|
def marshal_load(array)
|
85
84
|
@version, @columns, @columns_hash, @primary_keys, @tables = array
|
86
|
-
prepare_default_proc
|
87
85
|
end
|
88
86
|
|
89
87
|
private
|
90
88
|
|
91
|
-
|
92
|
-
|
93
|
-
h[table_name] = connection.columns(table_name)
|
94
|
-
end
|
95
|
-
|
96
|
-
@columns_hash.default_proc = Proc.new do |h, table_name|
|
97
|
-
h[table_name] = Hash[columns(table_name).map { |col|
|
98
|
-
[col.name, col]
|
99
|
-
}]
|
89
|
+
def prepare_tables
|
90
|
+
connection.tables.each { |table| @tables[table] = true }
|
100
91
|
end
|
101
|
-
|
102
|
-
@primary_keys.default_proc = Proc.new do |h, table_name|
|
103
|
-
h[table_name] = table_exists?(table_name) ? connection.primary_key(table_name) : nil
|
104
|
-
end
|
105
|
-
end
|
106
92
|
end
|
107
93
|
end
|
108
94
|
end
|
@@ -14,9 +14,9 @@ module ActiveRecord
|
|
14
14
|
raise ArgumentError, "No database file specified. Missing argument: database"
|
15
15
|
end
|
16
16
|
|
17
|
-
# Allow database path relative to Rails.root, but only if
|
18
|
-
#
|
19
|
-
#
|
17
|
+
# Allow database path relative to Rails.root, but only if the database
|
18
|
+
# path is not the special path that tells sqlite to build a database only
|
19
|
+
# in memory.
|
20
20
|
if ':memory:' != config[:database]
|
21
21
|
config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root)
|
22
22
|
dirname = File.dirname(config[:database])
|
@@ -30,24 +30,32 @@ module ActiveRecord
|
|
30
30
|
|
31
31
|
db.busy_timeout(ConnectionAdapters::SQLite3Adapter.type_cast_config_to_integer(config[:timeout])) if config[:timeout]
|
32
32
|
|
33
|
-
ConnectionAdapters::SQLite3Adapter.new(db, logger, config)
|
33
|
+
ConnectionAdapters::SQLite3Adapter.new(db, logger, nil, config)
|
34
34
|
rescue Errno::ENOENT => error
|
35
35
|
if error.message.include?("No such file or directory")
|
36
|
-
raise ActiveRecord::NoDatabaseError.new(error.message)
|
36
|
+
raise ActiveRecord::NoDatabaseError.new(error.message, error)
|
37
37
|
else
|
38
|
-
raise
|
38
|
+
raise
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
43
|
module ConnectionAdapters #:nodoc:
|
44
|
-
class
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
44
|
+
class SQLite3Binary < Type::Binary # :nodoc:
|
45
|
+
def cast_value(value)
|
46
|
+
if value.encoding != Encoding::ASCII_8BIT
|
47
|
+
value = value.force_encoding(Encoding::ASCII_8BIT)
|
48
|
+
end
|
49
|
+
value
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class SQLite3String < Type::String # :nodoc:
|
54
|
+
def type_cast_for_database(value)
|
55
|
+
if value.is_a?(::String) && value.encoding == Encoding::ASCII_8BIT
|
56
|
+
value.encode(Encoding::UTF_8)
|
57
|
+
else
|
58
|
+
super
|
51
59
|
end
|
52
60
|
end
|
53
61
|
end
|
@@ -59,17 +67,17 @@ module ActiveRecord
|
|
59
67
|
#
|
60
68
|
# * <tt>:database</tt> - Path to the database file.
|
61
69
|
class SQLite3Adapter < AbstractAdapter
|
70
|
+
ADAPTER_NAME = 'SQLite'.freeze
|
62
71
|
include Savepoints
|
63
72
|
|
64
73
|
NATIVE_DATABASE_TYPES = {
|
65
74
|
primary_key: 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL',
|
66
|
-
string: { name: "varchar"
|
75
|
+
string: { name: "varchar" },
|
67
76
|
text: { name: "text" },
|
68
77
|
integer: { name: "integer" },
|
69
78
|
float: { name: "float" },
|
70
79
|
decimal: { name: "decimal" },
|
71
80
|
datetime: { name: "datetime" },
|
72
|
-
timestamp: { name: "datetime" },
|
73
81
|
time: { name: "time" },
|
74
82
|
date: { name: "date" },
|
75
83
|
binary: { name: "blob" },
|
@@ -107,7 +115,7 @@ module ActiveRecord
|
|
107
115
|
end
|
108
116
|
|
109
117
|
def clear
|
110
|
-
cache.
|
118
|
+
cache.each_value do |hash|
|
111
119
|
dealloc hash[:stmt]
|
112
120
|
end
|
113
121
|
cache.clear
|
@@ -123,11 +131,7 @@ module ActiveRecord
|
|
123
131
|
end
|
124
132
|
end
|
125
133
|
|
126
|
-
|
127
|
-
include Arel::Visitors::BindVisitor
|
128
|
-
end
|
129
|
-
|
130
|
-
def initialize(connection, logger, config)
|
134
|
+
def initialize(connection, logger, connection_options, config)
|
131
135
|
super(connection, logger)
|
132
136
|
|
133
137
|
@active = nil
|
@@ -135,18 +139,15 @@ module ActiveRecord
|
|
135
139
|
self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 }))
|
136
140
|
@config = config
|
137
141
|
|
142
|
+
@visitor = Arel::Visitors::SQLite.new self
|
143
|
+
|
138
144
|
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
139
145
|
@prepared_statements = true
|
140
|
-
@visitor = Arel::Visitors::SQLite.new self
|
141
146
|
else
|
142
|
-
@
|
147
|
+
@prepared_statements = false
|
143
148
|
end
|
144
149
|
end
|
145
150
|
|
146
|
-
def adapter_name #:nodoc:
|
147
|
-
'SQLite'
|
148
|
-
end
|
149
|
-
|
150
151
|
def supports_ddl_transactions?
|
151
152
|
true
|
152
153
|
end
|
@@ -178,7 +179,7 @@ module ActiveRecord
|
|
178
179
|
true
|
179
180
|
end
|
180
181
|
|
181
|
-
def
|
182
|
+
def supports_views?
|
182
183
|
true
|
183
184
|
end
|
184
185
|
|
@@ -225,10 +226,19 @@ module ActiveRecord
|
|
225
226
|
|
226
227
|
# QUOTING ==================================================
|
227
228
|
|
228
|
-
def
|
229
|
-
|
230
|
-
|
231
|
-
"x'#{
|
229
|
+
def _quote(value) # :nodoc:
|
230
|
+
case value
|
231
|
+
when Type::Binary::Data
|
232
|
+
"x'#{value.hex}'"
|
233
|
+
else
|
234
|
+
super
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def _type_cast(value) # :nodoc:
|
239
|
+
case value
|
240
|
+
when BigDecimal
|
241
|
+
value.to_f
|
232
242
|
else
|
233
243
|
super
|
234
244
|
end
|
@@ -256,24 +266,13 @@ module ActiveRecord
|
|
256
266
|
end
|
257
267
|
end
|
258
268
|
|
259
|
-
|
260
|
-
return value.to_f if BigDecimal === value
|
261
|
-
return super unless String === value
|
262
|
-
return super unless column && value
|
263
|
-
|
264
|
-
value = super
|
265
|
-
if column.type == :string && value.encoding == Encoding::ASCII_8BIT
|
266
|
-
logger.error "Binary data inserted for `string` type on column `#{column.name}`" if logger
|
267
|
-
value = value.encode Encoding::UTF_8
|
268
|
-
end
|
269
|
-
value
|
270
|
-
end
|
271
|
-
|
269
|
+
#--
|
272
270
|
# DATABASE STATEMENTS ======================================
|
271
|
+
#++
|
273
272
|
|
274
273
|
def explain(arel, binds = [])
|
275
274
|
sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
|
276
|
-
ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN',
|
275
|
+
ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', []))
|
277
276
|
end
|
278
277
|
|
279
278
|
class ExplainPrettyPrinter
|
@@ -299,9 +298,12 @@ module ActiveRecord
|
|
299
298
|
# Don't cache statements if they are not prepared
|
300
299
|
if without_prepared_statement?(binds)
|
301
300
|
stmt = @connection.prepare(sql)
|
302
|
-
|
303
|
-
|
304
|
-
|
301
|
+
begin
|
302
|
+
cols = stmt.columns
|
303
|
+
records = stmt.to_a
|
304
|
+
ensure
|
305
|
+
stmt.close
|
306
|
+
end
|
305
307
|
stmt = records
|
306
308
|
else
|
307
309
|
cache = @statements[sql] ||= {
|
@@ -369,7 +371,7 @@ module ActiveRecord
|
|
369
371
|
sql = <<-SQL
|
370
372
|
SELECT name
|
371
373
|
FROM sqlite_master
|
372
|
-
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
|
374
|
+
WHERE (type = 'table' OR type = 'view') AND NOT name = 'sqlite_sequence'
|
373
375
|
SQL
|
374
376
|
sql << " AND name = #{quote_table_name(table_name)}" if table_name
|
375
377
|
|
@@ -382,7 +384,7 @@ module ActiveRecord
|
|
382
384
|
table_name && tables(nil, table_name).any?
|
383
385
|
end
|
384
386
|
|
385
|
-
# Returns an array of +
|
387
|
+
# Returns an array of +Column+ objects for the table specified by +table_name+.
|
386
388
|
def columns(table_name) #:nodoc:
|
387
389
|
table_structure(table_name).map do |field|
|
388
390
|
case field["dflt_value"]
|
@@ -394,7 +396,9 @@ module ActiveRecord
|
|
394
396
|
field["dflt_value"] = $1.gsub('""', '"')
|
395
397
|
end
|
396
398
|
|
397
|
-
|
399
|
+
sql_type = field['type']
|
400
|
+
cast_type = lookup_cast_type(sql_type)
|
401
|
+
new_column(field['name'], field['dflt_value'], cast_type, sql_type, field['notnull'].to_i == 0)
|
398
402
|
end
|
399
403
|
end
|
400
404
|
|
@@ -445,12 +449,12 @@ module ActiveRecord
|
|
445
449
|
|
446
450
|
# See: http://www.sqlite.org/lang_altertable.html
|
447
451
|
# SQLite has an additional restriction on the ALTER TABLE statement
|
448
|
-
def
|
452
|
+
def valid_alter_table_type?(type)
|
449
453
|
type.to_sym != :primary_key
|
450
454
|
end
|
451
455
|
|
452
456
|
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
453
|
-
if
|
457
|
+
if valid_alter_table_type?(type)
|
454
458
|
super(table_name, column_name, type, options)
|
455
459
|
else
|
456
460
|
alter_table(table_name) do |definition|
|
@@ -495,16 +499,17 @@ module ActiveRecord
|
|
495
499
|
end
|
496
500
|
|
497
501
|
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
|
502
|
-
rename_column_indexes(table_name, column_name, new_column_name)
|
502
|
+
column = column_for(table_name, column_name)
|
503
|
+
alter_table(table_name, rename: {column.name => new_column_name.to_s})
|
504
|
+
rename_column_indexes(table_name, column.name, new_column_name)
|
503
505
|
end
|
504
506
|
|
505
507
|
protected
|
506
|
-
|
507
|
-
|
508
|
+
|
509
|
+
def initialize_type_map(m)
|
510
|
+
super
|
511
|
+
m.register_type(/binary/i, SQLite3Binary.new)
|
512
|
+
register_class_with_limit m, %r(char)i, SQLite3String
|
508
513
|
end
|
509
514
|
|
510
515
|
def table_structure(table_name)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module ConnectionHandling
|
3
|
-
RAILS_ENV = -> { Rails.env if defined?(Rails) }
|
3
|
+
RAILS_ENV = -> { (Rails.env if defined?(Rails)) || ENV["RAILS_ENV"] || ENV["RACK_ENV"] }
|
4
4
|
DEFAULT_ENV = -> { RAILS_ENV.call || "default_env" }
|
5
5
|
|
6
6
|
# Establishes the connection to the database. Accepts a hash as input where
|
@@ -18,14 +18,14 @@ module ActiveRecord
|
|
18
18
|
# Example for SQLite database:
|
19
19
|
#
|
20
20
|
# ActiveRecord::Base.establish_connection(
|
21
|
-
# adapter: "
|
21
|
+
# adapter: "sqlite3",
|
22
22
|
# database: "path/to/dbfile"
|
23
23
|
# )
|
24
24
|
#
|
25
25
|
# Also accepts keys as strings (for parsing from YAML for example):
|
26
26
|
#
|
27
27
|
# ActiveRecord::Base.establish_connection(
|
28
|
-
# "adapter" => "
|
28
|
+
# "adapter" => "sqlite3",
|
29
29
|
# "database" => "path/to/dbfile"
|
30
30
|
# )
|
31
31
|
#
|
data/lib/active_record/core.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
+
require 'thread'
|
1
2
|
require 'active_support/core_ext/hash/indifferent_access'
|
2
3
|
require 'active_support/core_ext/object/duplicable'
|
3
|
-
require '
|
4
|
+
require 'active_support/core_ext/string/filters'
|
4
5
|
|
5
6
|
module ActiveRecord
|
6
7
|
module Core
|
@@ -16,7 +17,6 @@ module ActiveRecord
|
|
16
17
|
mattr_accessor :logger, instance_writer: false
|
17
18
|
|
18
19
|
##
|
19
|
-
# :singleton-method:
|
20
20
|
# Contains the database configuration - as is typically stored in config/database.yml -
|
21
21
|
# as a Hash.
|
22
22
|
#
|
@@ -85,15 +85,17 @@ module ActiveRecord
|
|
85
85
|
mattr_accessor :dump_schema_after_migration, instance_writer: false
|
86
86
|
self.dump_schema_after_migration = true
|
87
87
|
|
88
|
-
# :nodoc:
|
89
88
|
mattr_accessor :maintain_test_schema, instance_accessor: false
|
90
89
|
|
91
90
|
def self.disable_implicit_join_references=(value)
|
92
|
-
ActiveSupport::Deprecation.warn(
|
93
|
-
|
91
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
92
|
+
Implicit join references were removed with Rails 4.1.
|
93
|
+
Make sure to remove this configuration because it does nothing.
|
94
|
+
MSG
|
94
95
|
end
|
95
96
|
|
96
97
|
class_attribute :default_connection_handler, instance_writer: false
|
98
|
+
class_attribute :find_by_statement_cache
|
97
99
|
|
98
100
|
def self.connection_handler
|
99
101
|
ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler
|
@@ -107,9 +109,93 @@ module ActiveRecord
|
|
107
109
|
end
|
108
110
|
|
109
111
|
module ClassMethods
|
110
|
-
def
|
112
|
+
def allocate
|
113
|
+
define_attribute_methods
|
114
|
+
super
|
115
|
+
end
|
116
|
+
|
117
|
+
def initialize_find_by_cache
|
118
|
+
self.find_by_statement_cache = {}.extend(Mutex_m)
|
119
|
+
end
|
120
|
+
|
121
|
+
def inherited(child_class)
|
122
|
+
child_class.initialize_find_by_cache
|
111
123
|
super
|
124
|
+
end
|
125
|
+
|
126
|
+
def find(*ids)
|
127
|
+
# We don't have cache keys for this stuff yet
|
128
|
+
return super unless ids.length == 1
|
129
|
+
# Allow symbols to super to maintain compatibility for deprecated finders until Rails 5
|
130
|
+
return super if ids.first.kind_of?(Symbol)
|
131
|
+
return super if block_given? ||
|
132
|
+
primary_key.nil? ||
|
133
|
+
default_scopes.any? ||
|
134
|
+
columns_hash.include?(inheritance_column) ||
|
135
|
+
ids.first.kind_of?(Array)
|
136
|
+
|
137
|
+
id = ids.first
|
138
|
+
if ActiveRecord::Base === id
|
139
|
+
id = id.id
|
140
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
141
|
+
You are passing an instance of ActiveRecord::Base to `find`.
|
142
|
+
Please pass the id of the object by calling `.id`
|
143
|
+
MSG
|
144
|
+
end
|
145
|
+
key = primary_key
|
146
|
+
|
147
|
+
s = find_by_statement_cache[key] || find_by_statement_cache.synchronize {
|
148
|
+
find_by_statement_cache[key] ||= StatementCache.create(connection) { |params|
|
149
|
+
where(key => params.bind).limit(1)
|
150
|
+
}
|
151
|
+
}
|
152
|
+
record = s.execute([id], self, connection).first
|
153
|
+
unless record
|
154
|
+
raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}"
|
155
|
+
end
|
156
|
+
record
|
157
|
+
rescue RangeError
|
158
|
+
raise RecordNotFound, "Couldn't find #{name} with an out of range value for '#{primary_key}'"
|
159
|
+
end
|
160
|
+
|
161
|
+
def find_by(*args)
|
162
|
+
return super if current_scope || !(Hash === args.first) || reflect_on_all_aggregations.any?
|
163
|
+
return super if default_scopes.any?
|
164
|
+
|
165
|
+
hash = args.first
|
166
|
+
|
167
|
+
return super if hash.values.any? { |v|
|
168
|
+
v.nil? || Array === v || Hash === v
|
169
|
+
}
|
170
|
+
|
171
|
+
# We can't cache Post.find_by(author: david) ...yet
|
172
|
+
return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
|
173
|
+
|
174
|
+
key = hash.keys
|
175
|
+
|
176
|
+
klass = self
|
177
|
+
s = find_by_statement_cache[key] || find_by_statement_cache.synchronize {
|
178
|
+
find_by_statement_cache[key] ||= StatementCache.create(connection) { |params|
|
179
|
+
wheres = key.each_with_object({}) { |param,o|
|
180
|
+
o[param] = params.bind
|
181
|
+
}
|
182
|
+
klass.where(wheres).limit(1)
|
183
|
+
}
|
184
|
+
}
|
185
|
+
begin
|
186
|
+
s.execute(hash.values, self, connection).first
|
187
|
+
rescue TypeError => e
|
188
|
+
raise ActiveRecord::StatementInvalid.new(e.message, e)
|
189
|
+
rescue RangeError
|
190
|
+
nil
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def find_by!(*args)
|
195
|
+
find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}")
|
196
|
+
end
|
112
197
|
|
198
|
+
def initialize_generated_modules
|
113
199
|
generated_association_methods
|
114
200
|
end
|
115
201
|
|
@@ -183,22 +269,18 @@ module ActiveRecord
|
|
183
269
|
# # Instantiates a single new object
|
184
270
|
# User.new(first_name: 'Jamie')
|
185
271
|
def initialize(attributes = nil, options = {})
|
186
|
-
|
187
|
-
defaults.each { |k, v| defaults[k] = v.dup if v.duplicable? }
|
188
|
-
|
189
|
-
@attributes = self.class.initialize_attributes(defaults)
|
190
|
-
@column_types_override = nil
|
191
|
-
@column_types = self.class.column_types
|
272
|
+
@attributes = self.class._default_attributes.dup
|
192
273
|
|
193
274
|
init_internals
|
194
275
|
initialize_internals_callback
|
195
276
|
|
277
|
+
self.class.define_attribute_methods
|
196
278
|
# +options+ argument is only needed to make protected_attributes gem easier to hook.
|
197
279
|
# Remove it when we drop support to this gem.
|
198
280
|
init_attributes(attributes, options) if attributes
|
199
281
|
|
200
282
|
yield self if block_given?
|
201
|
-
|
283
|
+
_run_initialize_callbacks
|
202
284
|
end
|
203
285
|
|
204
286
|
# Initialize an empty model object from +coder+. +coder+ must contain
|
@@ -212,16 +294,16 @@ module ActiveRecord
|
|
212
294
|
# post.init_with('attributes' => { 'title' => 'hello world' })
|
213
295
|
# post.title # => 'hello world'
|
214
296
|
def init_with(coder)
|
215
|
-
@attributes
|
216
|
-
@column_types_override = coder['column_types']
|
217
|
-
@column_types = self.class.column_types
|
297
|
+
@attributes = coder['attributes']
|
218
298
|
|
219
299
|
init_internals
|
220
300
|
|
221
|
-
@new_record =
|
301
|
+
@new_record = coder['new_record']
|
222
302
|
|
223
|
-
|
224
|
-
|
303
|
+
self.class.define_attribute_methods
|
304
|
+
|
305
|
+
_run_find_callbacks
|
306
|
+
_run_initialize_callbacks
|
225
307
|
|
226
308
|
self
|
227
309
|
end
|
@@ -254,19 +336,16 @@ module ActiveRecord
|
|
254
336
|
|
255
337
|
##
|
256
338
|
def initialize_dup(other) # :nodoc:
|
257
|
-
|
258
|
-
self.class.
|
259
|
-
|
260
|
-
@attributes = cloned_attributes
|
261
|
-
@attributes[self.class.primary_key] = nil
|
339
|
+
@attributes = @attributes.dup
|
340
|
+
@attributes.reset(self.class.primary_key)
|
262
341
|
|
263
|
-
|
342
|
+
_run_initialize_callbacks
|
264
343
|
|
265
344
|
@aggregation_cache = {}
|
266
345
|
@association_cache = {}
|
267
|
-
@attributes_cache = {}
|
268
346
|
|
269
347
|
@new_record = true
|
348
|
+
@destroyed = false
|
270
349
|
|
271
350
|
super
|
272
351
|
end
|
@@ -284,7 +363,10 @@ module ActiveRecord
|
|
284
363
|
# Post.new.encode_with(coder)
|
285
364
|
# coder # => {"attributes" => {"id" => nil, ... }}
|
286
365
|
def encode_with(coder)
|
287
|
-
|
366
|
+
# FIXME: Remove this when we better serialize attributes
|
367
|
+
coder['raw_attributes'] = attributes_before_type_cast
|
368
|
+
coder['attributes'] = @attributes
|
369
|
+
coder['new_record'] = new_record?
|
288
370
|
end
|
289
371
|
|
290
372
|
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
|
@@ -307,7 +389,11 @@ module ActiveRecord
|
|
307
389
|
# Delegates to id in order to allow two records of the same type and id to work with something like:
|
308
390
|
# [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
|
309
391
|
def hash
|
310
|
-
id
|
392
|
+
if id
|
393
|
+
id.hash
|
394
|
+
else
|
395
|
+
super
|
396
|
+
end
|
311
397
|
end
|
312
398
|
|
313
399
|
# Clone and freeze the attributes hash such that associations are still
|
@@ -363,6 +449,29 @@ module ActiveRecord
|
|
363
449
|
"#<#{self.class} #{inspection}>"
|
364
450
|
end
|
365
451
|
|
452
|
+
# Takes a PP and prettily prints this record to it, allowing you to get a nice result from `pp record`
|
453
|
+
# when pp is required.
|
454
|
+
def pretty_print(pp)
|
455
|
+
pp.object_address_group(self) do
|
456
|
+
if defined?(@attributes) && @attributes
|
457
|
+
column_names = self.class.column_names.select { |name| has_attribute?(name) || new_record? }
|
458
|
+
pp.seplist(column_names, proc { pp.text ',' }) do |column_name|
|
459
|
+
column_value = read_attribute(column_name)
|
460
|
+
pp.breakable ' '
|
461
|
+
pp.group(1) do
|
462
|
+
pp.text column_name
|
463
|
+
pp.text ':'
|
464
|
+
pp.breakable
|
465
|
+
pp.pp column_value
|
466
|
+
end
|
467
|
+
end
|
468
|
+
else
|
469
|
+
pp.breakable ' '
|
470
|
+
pp.text 'not initialized'
|
471
|
+
end
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
366
475
|
# Returns a hash of the given methods with their names as keys and returned values as values.
|
367
476
|
def slice(*methods)
|
368
477
|
Hash[methods.map! { |method| [method, public_send(method)] }].with_indifferent_access
|
@@ -426,12 +535,8 @@ module ActiveRecord
|
|
426
535
|
end
|
427
536
|
|
428
537
|
def init_internals
|
429
|
-
pk = self.class.primary_key
|
430
|
-
@attributes[pk] = nil unless @attributes.key?(pk)
|
431
|
-
|
432
538
|
@aggregation_cache = {}
|
433
539
|
@association_cache = {}
|
434
|
-
@attributes_cache = {}
|
435
540
|
@readonly = false
|
436
541
|
@destroyed = false
|
437
542
|
@marked_for_destruction = false
|
@@ -451,5 +556,11 @@ module ActiveRecord
|
|
451
556
|
def init_attributes(attributes, options)
|
452
557
|
assign_attributes(attributes)
|
453
558
|
end
|
559
|
+
|
560
|
+
def thaw
|
561
|
+
if frozen?
|
562
|
+
@attributes = @attributes.dup
|
563
|
+
end
|
564
|
+
end
|
454
565
|
end
|
455
566
|
end
|