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
@@ -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,25 +30,23 @@ 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
|
-
value = value.force_encoding(Encoding::ASCII_8BIT)
|
49
|
-
end
|
50
|
-
value
|
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)
|
51
48
|
end
|
49
|
+
value
|
52
50
|
end
|
53
51
|
end
|
54
52
|
|
@@ -59,35 +57,23 @@ module ActiveRecord
|
|
59
57
|
#
|
60
58
|
# * <tt>:database</tt> - Path to the database file.
|
61
59
|
class SQLite3Adapter < AbstractAdapter
|
60
|
+
ADAPTER_NAME = 'SQLite'.freeze
|
62
61
|
include Savepoints
|
63
62
|
|
64
63
|
NATIVE_DATABASE_TYPES = {
|
65
64
|
primary_key: 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL',
|
66
|
-
string: { name: "varchar"
|
65
|
+
string: { name: "varchar" },
|
67
66
|
text: { name: "text" },
|
68
67
|
integer: { name: "integer" },
|
69
68
|
float: { name: "float" },
|
70
69
|
decimal: { name: "decimal" },
|
71
70
|
datetime: { name: "datetime" },
|
72
|
-
timestamp: { name: "datetime" },
|
73
71
|
time: { name: "time" },
|
74
72
|
date: { name: "date" },
|
75
73
|
binary: { name: "blob" },
|
76
74
|
boolean: { name: "boolean" }
|
77
75
|
}
|
78
76
|
|
79
|
-
class Version
|
80
|
-
include Comparable
|
81
|
-
|
82
|
-
def initialize(version_string)
|
83
|
-
@version = version_string.split('.').map { |v| v.to_i }
|
84
|
-
end
|
85
|
-
|
86
|
-
def <=>(version_string)
|
87
|
-
@version <=> version_string.split('.').map { |v| v.to_i }
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
77
|
class StatementPool < ConnectionAdapters::StatementPool
|
92
78
|
def initialize(connection, max)
|
93
79
|
super
|
@@ -107,7 +93,7 @@ module ActiveRecord
|
|
107
93
|
end
|
108
94
|
|
109
95
|
def clear
|
110
|
-
cache.
|
96
|
+
cache.each_value do |hash|
|
111
97
|
dealloc hash[:stmt]
|
112
98
|
end
|
113
99
|
cache.clear
|
@@ -123,11 +109,7 @@ module ActiveRecord
|
|
123
109
|
end
|
124
110
|
end
|
125
111
|
|
126
|
-
|
127
|
-
include Arel::Visitors::BindVisitor
|
128
|
-
end
|
129
|
-
|
130
|
-
def initialize(connection, logger, config)
|
112
|
+
def initialize(connection, logger, connection_options, config)
|
131
113
|
super(connection, logger)
|
132
114
|
|
133
115
|
@active = nil
|
@@ -135,18 +117,15 @@ module ActiveRecord
|
|
135
117
|
self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 }))
|
136
118
|
@config = config
|
137
119
|
|
120
|
+
@visitor = Arel::Visitors::SQLite.new self
|
121
|
+
|
138
122
|
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
139
123
|
@prepared_statements = true
|
140
|
-
@visitor = Arel::Visitors::SQLite.new self
|
141
124
|
else
|
142
|
-
@
|
125
|
+
@prepared_statements = false
|
143
126
|
end
|
144
127
|
end
|
145
128
|
|
146
|
-
def adapter_name #:nodoc:
|
147
|
-
'SQLite'
|
148
|
-
end
|
149
|
-
|
150
129
|
def supports_ddl_transactions?
|
151
130
|
true
|
152
131
|
end
|
@@ -178,7 +157,7 @@ module ActiveRecord
|
|
178
157
|
true
|
179
158
|
end
|
180
159
|
|
181
|
-
def
|
160
|
+
def supports_views?
|
182
161
|
true
|
183
162
|
end
|
184
163
|
|
@@ -225,10 +204,25 @@ module ActiveRecord
|
|
225
204
|
|
226
205
|
# QUOTING ==================================================
|
227
206
|
|
228
|
-
def
|
229
|
-
|
230
|
-
|
231
|
-
"x'#{
|
207
|
+
def _quote(value) # :nodoc:
|
208
|
+
case value
|
209
|
+
when Type::Binary::Data
|
210
|
+
"x'#{value.hex}'"
|
211
|
+
else
|
212
|
+
super
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def _type_cast(value) # :nodoc:
|
217
|
+
case value
|
218
|
+
when BigDecimal
|
219
|
+
value.to_f
|
220
|
+
when String
|
221
|
+
if value.encoding == Encoding::ASCII_8BIT
|
222
|
+
super(value.encode(Encoding::UTF_8))
|
223
|
+
else
|
224
|
+
super
|
225
|
+
end
|
232
226
|
else
|
233
227
|
super
|
234
228
|
end
|
@@ -256,24 +250,13 @@ module ActiveRecord
|
|
256
250
|
end
|
257
251
|
end
|
258
252
|
|
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
|
-
|
253
|
+
#--
|
272
254
|
# DATABASE STATEMENTS ======================================
|
255
|
+
#++
|
273
256
|
|
274
257
|
def explain(arel, binds = [])
|
275
258
|
sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
|
276
|
-
ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN',
|
259
|
+
ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', []))
|
277
260
|
end
|
278
261
|
|
279
262
|
class ExplainPrettyPrinter
|
@@ -362,7 +345,7 @@ module ActiveRecord
|
|
362
345
|
log('commit transaction',nil) { @connection.commit }
|
363
346
|
end
|
364
347
|
|
365
|
-
def
|
348
|
+
def exec_rollback_db_transaction #:nodoc:
|
366
349
|
log('rollback transaction',nil) { @connection.rollback }
|
367
350
|
end
|
368
351
|
|
@@ -372,7 +355,7 @@ module ActiveRecord
|
|
372
355
|
sql = <<-SQL
|
373
356
|
SELECT name
|
374
357
|
FROM sqlite_master
|
375
|
-
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
|
358
|
+
WHERE (type = 'table' OR type = 'view') AND NOT name = 'sqlite_sequence'
|
376
359
|
SQL
|
377
360
|
sql << " AND name = #{quote_table_name(table_name)}" if table_name
|
378
361
|
|
@@ -380,12 +363,14 @@ module ActiveRecord
|
|
380
363
|
row['name']
|
381
364
|
end
|
382
365
|
end
|
366
|
+
alias data_sources tables
|
383
367
|
|
384
368
|
def table_exists?(table_name)
|
385
369
|
table_name && tables(nil, table_name).any?
|
386
370
|
end
|
371
|
+
alias data_source_exists? table_exists?
|
387
372
|
|
388
|
-
# Returns an array of +
|
373
|
+
# Returns an array of +Column+ objects for the table specified by +table_name+.
|
389
374
|
def columns(table_name) #:nodoc:
|
390
375
|
table_structure(table_name).map do |field|
|
391
376
|
case field["dflt_value"]
|
@@ -397,7 +382,9 @@ module ActiveRecord
|
|
397
382
|
field["dflt_value"] = $1.gsub('""', '"')
|
398
383
|
end
|
399
384
|
|
400
|
-
|
385
|
+
sql_type = field['type']
|
386
|
+
cast_type = lookup_cast_type(sql_type)
|
387
|
+
new_column(field['name'], field['dflt_value'], cast_type, sql_type, field['notnull'].to_i == 0)
|
401
388
|
end
|
402
389
|
end
|
403
390
|
|
@@ -427,10 +414,9 @@ module ActiveRecord
|
|
427
414
|
end
|
428
415
|
|
429
416
|
def primary_key(table_name) #:nodoc:
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
column && column['name']
|
417
|
+
pks = table_structure(table_name).select { |f| f['pk'] > 0 }
|
418
|
+
return nil unless pks.count == 1
|
419
|
+
pks[0]['name']
|
434
420
|
end
|
435
421
|
|
436
422
|
def remove_index!(table_name, index_name) #:nodoc:
|
@@ -448,12 +434,12 @@ module ActiveRecord
|
|
448
434
|
|
449
435
|
# See: http://www.sqlite.org/lang_altertable.html
|
450
436
|
# SQLite has an additional restriction on the ALTER TABLE statement
|
451
|
-
def
|
437
|
+
def valid_alter_table_type?(type)
|
452
438
|
type.to_sym != :primary_key
|
453
439
|
end
|
454
440
|
|
455
441
|
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
456
|
-
if
|
442
|
+
if valid_alter_table_type?(type)
|
457
443
|
super(table_name, column_name, type, options)
|
458
444
|
else
|
459
445
|
alter_table(table_name) do |definition|
|
@@ -498,16 +484,16 @@ module ActiveRecord
|
|
498
484
|
end
|
499
485
|
|
500
486
|
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
|
505
|
-
rename_column_indexes(table_name, column_name, new_column_name)
|
487
|
+
column = column_for(table_name, column_name)
|
488
|
+
alter_table(table_name, rename: {column.name => new_column_name.to_s})
|
489
|
+
rename_column_indexes(table_name, column.name, new_column_name)
|
506
490
|
end
|
507
491
|
|
508
492
|
protected
|
509
|
-
|
510
|
-
|
493
|
+
|
494
|
+
def initialize_type_map(m)
|
495
|
+
super
|
496
|
+
m.register_type(/binary/i, SQLite3Binary.new)
|
511
497
|
end
|
512
498
|
|
513
499
|
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)) || ENV["RAILS_ENV"] || ENV["RACK_ENV"] }
|
3
|
+
RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || 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
|
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
|
#
|
@@ -88,11 +88,14 @@ module ActiveRecord
|
|
88
88
|
mattr_accessor :maintain_test_schema, instance_accessor: false
|
89
89
|
|
90
90
|
def self.disable_implicit_join_references=(value)
|
91
|
-
ActiveSupport::Deprecation.warn(
|
92
|
-
|
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
|
93
95
|
end
|
94
96
|
|
95
97
|
class_attribute :default_connection_handler, instance_writer: false
|
98
|
+
class_attribute :find_by_statement_cache
|
96
99
|
|
97
100
|
def self.connection_handler
|
98
101
|
ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler
|
@@ -106,7 +109,94 @@ module ActiveRecord
|
|
106
109
|
end
|
107
110
|
|
108
111
|
module ClassMethods
|
109
|
-
def
|
112
|
+
def allocate
|
113
|
+
define_attribute_methods
|
114
|
+
super
|
115
|
+
end
|
116
|
+
|
117
|
+
def initialize_find_by_cache # :nodoc:
|
118
|
+
self.find_by_statement_cache = {}.extend(Mutex_m)
|
119
|
+
end
|
120
|
+
|
121
|
+
def inherited(child_class) # :nodoc:
|
122
|
+
child_class.initialize_find_by_cache
|
123
|
+
super
|
124
|
+
end
|
125
|
+
|
126
|
+
def find(*ids) # :nodoc:
|
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
|
+
current_scope ||
|
135
|
+
columns_hash.include?(inheritance_column) ||
|
136
|
+
ids.first.kind_of?(Array)
|
137
|
+
|
138
|
+
id = ids.first
|
139
|
+
if ActiveRecord::Base === id
|
140
|
+
id = id.id
|
141
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
142
|
+
You are passing an instance of ActiveRecord::Base to `find`.
|
143
|
+
Please pass the id of the object by calling `.id`
|
144
|
+
MSG
|
145
|
+
end
|
146
|
+
key = primary_key
|
147
|
+
|
148
|
+
s = find_by_statement_cache[key] || find_by_statement_cache.synchronize {
|
149
|
+
find_by_statement_cache[key] ||= StatementCache.create(connection) { |params|
|
150
|
+
where(key => params.bind).limit(1)
|
151
|
+
}
|
152
|
+
}
|
153
|
+
record = s.execute([id], self, connection).first
|
154
|
+
unless record
|
155
|
+
raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}"
|
156
|
+
end
|
157
|
+
record
|
158
|
+
rescue RangeError
|
159
|
+
raise RecordNotFound, "Couldn't find #{name} with an out of range value for '#{primary_key}'"
|
160
|
+
end
|
161
|
+
|
162
|
+
def find_by(*args) # :nodoc:
|
163
|
+
return super if current_scope || !(Hash === args.first) || reflect_on_all_aggregations.any?
|
164
|
+
return super if default_scopes.any?
|
165
|
+
|
166
|
+
hash = args.first
|
167
|
+
|
168
|
+
return super if hash.values.any? { |v|
|
169
|
+
v.nil? || Array === v || Hash === v
|
170
|
+
}
|
171
|
+
|
172
|
+
# We can't cache Post.find_by(author: david) ...yet
|
173
|
+
return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
|
174
|
+
|
175
|
+
key = hash.keys
|
176
|
+
|
177
|
+
klass = self
|
178
|
+
s = find_by_statement_cache[key] || find_by_statement_cache.synchronize {
|
179
|
+
find_by_statement_cache[key] ||= StatementCache.create(connection) { |params|
|
180
|
+
wheres = key.each_with_object({}) { |param,o|
|
181
|
+
o[param] = params.bind
|
182
|
+
}
|
183
|
+
klass.where(wheres).limit(1)
|
184
|
+
}
|
185
|
+
}
|
186
|
+
begin
|
187
|
+
s.execute(hash.values, self, connection).first
|
188
|
+
rescue TypeError => e
|
189
|
+
raise ActiveRecord::StatementInvalid.new(e.message, e)
|
190
|
+
rescue RangeError
|
191
|
+
nil
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def find_by!(*args) # :nodoc:
|
196
|
+
find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}")
|
197
|
+
end
|
198
|
+
|
199
|
+
def initialize_generated_modules # :nodoc:
|
110
200
|
generated_association_methods
|
111
201
|
end
|
112
202
|
|
@@ -180,12 +270,8 @@ module ActiveRecord
|
|
180
270
|
# # Instantiates a single new object
|
181
271
|
# User.new(first_name: 'Jamie')
|
182
272
|
def initialize(attributes = nil, options = {})
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
@attributes = self.class.initialize_attributes(defaults)
|
187
|
-
@column_types_override = nil
|
188
|
-
@column_types = self.class.column_types
|
273
|
+
@attributes = self.class._default_attributes.dup
|
274
|
+
self.class.define_attribute_methods
|
189
275
|
|
190
276
|
init_internals
|
191
277
|
initialize_internals_callback
|
@@ -195,32 +281,35 @@ module ActiveRecord
|
|
195
281
|
init_attributes(attributes, options) if attributes
|
196
282
|
|
197
283
|
yield self if block_given?
|
198
|
-
|
284
|
+
_run_initialize_callbacks
|
199
285
|
end
|
200
286
|
|
201
|
-
# Initialize an empty model object from +coder+. +coder+
|
202
|
-
# the
|
203
|
-
#
|
287
|
+
# Initialize an empty model object from +coder+. +coder+ should be
|
288
|
+
# the result of previously encoding an Active Record model, using
|
289
|
+
# `encode_with`
|
204
290
|
#
|
205
291
|
# class Post < ActiveRecord::Base
|
206
292
|
# end
|
207
293
|
#
|
294
|
+
# old_post = Post.new(title: "hello world")
|
295
|
+
# coder = {}
|
296
|
+
# old_post.encode_with(coder)
|
297
|
+
#
|
208
298
|
# post = Post.allocate
|
209
|
-
# post.init_with(
|
299
|
+
# post.init_with(coder)
|
210
300
|
# post.title # => 'hello world'
|
211
301
|
def init_with(coder)
|
212
|
-
|
213
|
-
@
|
214
|
-
@column_types = self.class.column_types
|
302
|
+
coder = LegacyYamlAdapter.convert(self.class, coder)
|
303
|
+
@attributes = coder['attributes']
|
215
304
|
|
216
305
|
init_internals
|
217
306
|
|
218
|
-
@new_record =
|
307
|
+
@new_record = coder['new_record']
|
219
308
|
|
220
309
|
self.class.define_attribute_methods
|
221
310
|
|
222
|
-
|
223
|
-
|
311
|
+
_run_find_callbacks
|
312
|
+
_run_initialize_callbacks
|
224
313
|
|
225
314
|
self
|
226
315
|
end
|
@@ -253,17 +342,13 @@ module ActiveRecord
|
|
253
342
|
|
254
343
|
##
|
255
344
|
def initialize_dup(other) # :nodoc:
|
256
|
-
|
257
|
-
self.class.
|
258
|
-
|
259
|
-
@attributes = cloned_attributes
|
260
|
-
@attributes[self.class.primary_key] = nil
|
345
|
+
@attributes = @attributes.dup
|
346
|
+
@attributes.reset(self.class.primary_key)
|
261
347
|
|
262
|
-
|
348
|
+
_run_initialize_callbacks
|
263
349
|
|
264
350
|
@aggregation_cache = {}
|
265
351
|
@association_cache = {}
|
266
|
-
@attributes_cache = {}
|
267
352
|
|
268
353
|
@new_record = true
|
269
354
|
@destroyed = false
|
@@ -284,7 +369,11 @@ module ActiveRecord
|
|
284
369
|
# Post.new.encode_with(coder)
|
285
370
|
# coder # => {"attributes" => {"id" => nil, ... }}
|
286
371
|
def encode_with(coder)
|
287
|
-
|
372
|
+
# FIXME: Remove this when we better serialize attributes
|
373
|
+
coder['raw_attributes'] = attributes_before_type_cast
|
374
|
+
coder['attributes'] = @attributes
|
375
|
+
coder['new_record'] = new_record?
|
376
|
+
coder['active_record_yaml_version'] = 0
|
288
377
|
end
|
289
378
|
|
290
379
|
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
|
@@ -307,7 +396,11 @@ module ActiveRecord
|
|
307
396
|
# Delegates to id in order to allow two records of the same type and id to work with something like:
|
308
397
|
# [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
|
309
398
|
def hash
|
310
|
-
id
|
399
|
+
if id
|
400
|
+
id.hash
|
401
|
+
else
|
402
|
+
super
|
403
|
+
end
|
311
404
|
end
|
312
405
|
|
313
406
|
# Clone and freeze the attributes hash such that associations are still
|
@@ -363,21 +456,45 @@ module ActiveRecord
|
|
363
456
|
"#<#{self.class} #{inspection}>"
|
364
457
|
end
|
365
458
|
|
459
|
+
# Takes a PP and prettily prints this record to it, allowing you to get a nice result from `pp record`
|
460
|
+
# when pp is required.
|
461
|
+
def pretty_print(pp)
|
462
|
+
return super if custom_inspect_method_defined?
|
463
|
+
pp.object_address_group(self) do
|
464
|
+
if defined?(@attributes) && @attributes
|
465
|
+
column_names = self.class.column_names.select { |name| has_attribute?(name) || new_record? }
|
466
|
+
pp.seplist(column_names, proc { pp.text ',' }) do |column_name|
|
467
|
+
column_value = read_attribute(column_name)
|
468
|
+
pp.breakable ' '
|
469
|
+
pp.group(1) do
|
470
|
+
pp.text column_name
|
471
|
+
pp.text ':'
|
472
|
+
pp.breakable
|
473
|
+
pp.pp column_value
|
474
|
+
end
|
475
|
+
end
|
476
|
+
else
|
477
|
+
pp.breakable ' '
|
478
|
+
pp.text 'not initialized'
|
479
|
+
end
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
366
483
|
# Returns a hash of the given methods with their names as keys and returned values as values.
|
367
484
|
def slice(*methods)
|
368
485
|
Hash[methods.map! { |method| [method, public_send(method)] }].with_indifferent_access
|
369
486
|
end
|
370
487
|
|
488
|
+
private
|
489
|
+
|
371
490
|
def set_transaction_state(state) # :nodoc:
|
372
491
|
@transaction_state = state
|
373
492
|
end
|
374
493
|
|
375
494
|
def has_transactional_callbacks? # :nodoc:
|
376
|
-
!_rollback_callbacks.empty? || !_commit_callbacks.empty?
|
495
|
+
!_rollback_callbacks.empty? || !_commit_callbacks.empty?
|
377
496
|
end
|
378
497
|
|
379
|
-
private
|
380
|
-
|
381
498
|
# Updates the attributes on this particular ActiveRecord object so that
|
382
499
|
# if it is associated with a transaction, then the state of the AR object
|
383
500
|
# will be updated to reflect the current state of the transaction
|
@@ -400,6 +517,8 @@ module ActiveRecord
|
|
400
517
|
end
|
401
518
|
|
402
519
|
def update_attributes_from_transaction_state(transaction_state, depth)
|
520
|
+
@reflects_state = [false] if depth == 0
|
521
|
+
|
403
522
|
if transaction_state && transaction_state.finalized? && !has_transactional_callbacks?
|
404
523
|
unless @reflects_state[depth]
|
405
524
|
restore_transaction_record_state if transaction_state.rolledback?
|
@@ -426,12 +545,8 @@ module ActiveRecord
|
|
426
545
|
end
|
427
546
|
|
428
547
|
def init_internals
|
429
|
-
pk = self.class.primary_key
|
430
|
-
@attributes[pk] = nil unless @attributes.key?(pk)
|
431
|
-
|
432
548
|
@aggregation_cache = {}
|
433
549
|
@association_cache = {}
|
434
|
-
@attributes_cache = {}
|
435
550
|
@readonly = false
|
436
551
|
@destroyed = false
|
437
552
|
@marked_for_destruction = false
|
@@ -440,7 +555,6 @@ module ActiveRecord
|
|
440
555
|
@txn = nil
|
441
556
|
@_start_transaction_state = {}
|
442
557
|
@transaction_state = nil
|
443
|
-
@reflects_state = [false]
|
444
558
|
end
|
445
559
|
|
446
560
|
def initialize_internals_callback
|
@@ -451,5 +565,15 @@ module ActiveRecord
|
|
451
565
|
def init_attributes(attributes, options)
|
452
566
|
assign_attributes(attributes)
|
453
567
|
end
|
568
|
+
|
569
|
+
def thaw
|
570
|
+
if frozen?
|
571
|
+
@attributes = @attributes.dup
|
572
|
+
end
|
573
|
+
end
|
574
|
+
|
575
|
+
def custom_inspect_method_defined?
|
576
|
+
self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
|
577
|
+
end
|
454
578
|
end
|
455
579
|
end
|