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.

Files changed (185) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1162 -1792
  3. data/README.rdoc +15 -10
  4. data/lib/active_record.rb +4 -0
  5. data/lib/active_record/aggregations.rb +15 -8
  6. data/lib/active_record/association_relation.rb +13 -0
  7. data/lib/active_record/associations.rb +158 -49
  8. data/lib/active_record/associations/alias_tracker.rb +3 -12
  9. data/lib/active_record/associations/association.rb +16 -4
  10. data/lib/active_record/associations/association_scope.rb +83 -38
  11. data/lib/active_record/associations/belongs_to_association.rb +28 -10
  12. data/lib/active_record/associations/builder/association.rb +15 -4
  13. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -1
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -13
  16. data/lib/active_record/associations/builder/has_many.rb +1 -1
  17. data/lib/active_record/associations/builder/has_one.rb +2 -2
  18. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  19. data/lib/active_record/associations/collection_association.rb +63 -27
  20. data/lib/active_record/associations/collection_proxy.rb +29 -35
  21. data/lib/active_record/associations/foreign_association.rb +11 -0
  22. data/lib/active_record/associations/has_many_association.rb +83 -22
  23. data/lib/active_record/associations/has_many_through_association.rb +49 -26
  24. data/lib/active_record/associations/has_one_association.rb +1 -1
  25. data/lib/active_record/associations/join_dependency.rb +26 -13
  26. data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
  27. data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
  28. data/lib/active_record/associations/preloader.rb +36 -26
  29. data/lib/active_record/associations/preloader/association.rb +14 -11
  30. data/lib/active_record/associations/preloader/through_association.rb +4 -3
  31. data/lib/active_record/associations/singular_association.rb +17 -2
  32. data/lib/active_record/associations/through_association.rb +5 -12
  33. data/lib/active_record/attribute.rb +163 -0
  34. data/lib/active_record/attribute_assignment.rb +19 -11
  35. data/lib/active_record/attribute_decorators.rb +66 -0
  36. data/lib/active_record/attribute_methods.rb +56 -94
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  38. data/lib/active_record/attribute_methods/dirty.rb +107 -43
  39. data/lib/active_record/attribute_methods/primary_key.rb +7 -8
  40. data/lib/active_record/attribute_methods/query.rb +1 -1
  41. data/lib/active_record/attribute_methods/read.rb +22 -59
  42. data/lib/active_record/attribute_methods/serialization.rb +16 -150
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -40
  44. data/lib/active_record/attribute_methods/write.rb +9 -24
  45. data/lib/active_record/attribute_set.rb +81 -0
  46. data/lib/active_record/attribute_set/builder.rb +106 -0
  47. data/lib/active_record/attributes.rb +147 -0
  48. data/lib/active_record/autosave_association.rb +19 -12
  49. data/lib/active_record/base.rb +13 -24
  50. data/lib/active_record/callbacks.rb +6 -6
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +84 -52
  52. data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
  53. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  54. data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
  55. data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
  56. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
  57. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +138 -56
  58. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +268 -71
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +171 -59
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +293 -139
  63. data/lib/active_record/connection_adapters/column.rb +29 -240
  64. data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
  66. data/lib/active_record/connection_adapters/mysql_adapter.rb +67 -144
  67. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  68. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  69. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -25
  70. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
  71. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  96. data/lib/active_record/connection_adapters/postgresql/quoting.rb +46 -136
  97. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  99. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +131 -43
  100. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  101. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
  102. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  103. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
  104. data/lib/active_record/connection_handling.rb +1 -1
  105. data/lib/active_record/core.rb +163 -39
  106. data/lib/active_record/counter_cache.rb +60 -6
  107. data/lib/active_record/enum.rb +9 -11
  108. data/lib/active_record/errors.rb +53 -30
  109. data/lib/active_record/explain.rb +1 -1
  110. data/lib/active_record/explain_subscriber.rb +1 -1
  111. data/lib/active_record/fixtures.rb +55 -69
  112. data/lib/active_record/gem_version.rb +4 -4
  113. data/lib/active_record/inheritance.rb +35 -10
  114. data/lib/active_record/integration.rb +4 -4
  115. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  116. data/lib/active_record/locking/optimistic.rb +46 -26
  117. data/lib/active_record/migration.rb +71 -46
  118. data/lib/active_record/migration/command_recorder.rb +19 -2
  119. data/lib/active_record/migration/join_table.rb +1 -1
  120. data/lib/active_record/model_schema.rb +52 -58
  121. data/lib/active_record/nested_attributes.rb +5 -5
  122. data/lib/active_record/no_touching.rb +1 -1
  123. data/lib/active_record/persistence.rb +46 -26
  124. data/lib/active_record/query_cache.rb +3 -3
  125. data/lib/active_record/querying.rb +10 -7
  126. data/lib/active_record/railtie.rb +18 -11
  127. data/lib/active_record/railties/databases.rake +50 -51
  128. data/lib/active_record/readonly_attributes.rb +0 -1
  129. data/lib/active_record/reflection.rb +273 -114
  130. data/lib/active_record/relation.rb +57 -25
  131. data/lib/active_record/relation/batches.rb +0 -2
  132. data/lib/active_record/relation/calculations.rb +41 -37
  133. data/lib/active_record/relation/finder_methods.rb +70 -47
  134. data/lib/active_record/relation/merger.rb +39 -29
  135. data/lib/active_record/relation/predicate_builder.rb +16 -8
  136. data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
  137. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -5
  138. data/lib/active_record/relation/query_methods.rb +114 -65
  139. data/lib/active_record/relation/spawn_methods.rb +3 -0
  140. data/lib/active_record/result.rb +18 -7
  141. data/lib/active_record/sanitization.rb +12 -2
  142. data/lib/active_record/schema.rb +0 -1
  143. data/lib/active_record/schema_dumper.rb +59 -28
  144. data/lib/active_record/schema_migration.rb +5 -4
  145. data/lib/active_record/scoping/default.rb +6 -4
  146. data/lib/active_record/scoping/named.rb +4 -0
  147. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  148. data/lib/active_record/statement_cache.rb +95 -10
  149. data/lib/active_record/store.rb +5 -5
  150. data/lib/active_record/tasks/database_tasks.rb +61 -6
  151. data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
  152. data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
  153. data/lib/active_record/timestamp.rb +9 -7
  154. data/lib/active_record/transactions.rb +53 -27
  155. data/lib/active_record/type.rb +23 -0
  156. data/lib/active_record/type/big_integer.rb +13 -0
  157. data/lib/active_record/type/binary.rb +50 -0
  158. data/lib/active_record/type/boolean.rb +31 -0
  159. data/lib/active_record/type/date.rb +50 -0
  160. data/lib/active_record/type/date_time.rb +54 -0
  161. data/lib/active_record/type/decimal.rb +64 -0
  162. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  163. data/lib/active_record/type/decorator.rb +14 -0
  164. data/lib/active_record/type/float.rb +19 -0
  165. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  166. data/lib/active_record/type/integer.rb +59 -0
  167. data/lib/active_record/type/mutable.rb +16 -0
  168. data/lib/active_record/type/numeric.rb +36 -0
  169. data/lib/active_record/type/serialized.rb +62 -0
  170. data/lib/active_record/type/string.rb +40 -0
  171. data/lib/active_record/type/text.rb +11 -0
  172. data/lib/active_record/type/time.rb +26 -0
  173. data/lib/active_record/type/time_value.rb +38 -0
  174. data/lib/active_record/type/type_map.rb +64 -0
  175. data/lib/active_record/type/unsigned_integer.rb +15 -0
  176. data/lib/active_record/type/value.rb +110 -0
  177. data/lib/active_record/validations.rb +25 -19
  178. data/lib/active_record/validations/associated.rb +5 -3
  179. data/lib/active_record/validations/presence.rb +5 -3
  180. data/lib/active_record/validations/uniqueness.rb +25 -29
  181. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  182. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  183. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  184. metadata +66 -11
  185. 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
- @primary_keys[table_name]
33
- @columns[table_name]
34
- @columns_hash[table_name]
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(table)
44
- @columns[table]
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(table)
50
- @columns_hash[table]
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] + [@columns, @columns_hash, @primary_keys, @tables].map { |val|
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
- def prepare_default_proc
92
- @columns.default_proc = Proc.new do |h, table_name|
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
- # the database path is not the special path that tells
19
- # Sqlite to build a database only in memory.
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 error
38
+ raise
39
39
  end
40
40
  end
41
41
  end
42
42
 
43
43
  module ConnectionAdapters #:nodoc:
44
- class SQLite3Column < Column #:nodoc:
45
- class << self
46
- def binary_to_string(value)
47
- if value.encoding != Encoding::ASCII_8BIT
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", limit: 255 },
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.values.each do |hash|
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
- class BindSubstitution < Arel::Visitors::SQLite # :nodoc:
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
- @visitor = unprepared_visitor
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 supports_add_column?
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 quote(value, column = nil)
229
- if value.kind_of?(String) && column && column.type == :binary
230
- s = value.unpack("H*")[0]
231
- "x'#{s}'"
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
- def type_cast(value, column) # :nodoc:
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', binds))
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 rollback_db_transaction #:nodoc:
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 +SQLite3Column+ objects for the table specified by +table_name+.
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
- SQLite3Column.new(field['name'], field['dflt_value'], field['type'], field['notnull'].to_i == 0)
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
- column = table_structure(table_name).find { |field|
431
- field['pk'] == 1
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 valid_alter_table_options( type, options)
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 supports_add_column? && valid_alter_table_options( type, options )
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
- unless columns(table_name).detect{|c| c.name == column_name.to_s }
502
- raise ActiveRecord::ActiveRecordError, "Missing column #{table_name}.#{column_name}"
503
- end
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
- def select(sql, name = nil, binds = []) #:nodoc:
510
- exec_query(sql, name, binds)
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
@@ -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 'thread'
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("Implicit join references were removed with Rails 4.1." \
92
- "Make sure to remove this configuration because it does nothing.")
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 initialize_generated_modules
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
- defaults = self.class.column_defaults.dup
184
- defaults.each { |k, v| defaults[k] = v.dup if v.duplicable? }
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
- run_callbacks :initialize unless _initialize_callbacks.empty?
284
+ _run_initialize_callbacks
199
285
  end
200
286
 
201
- # Initialize an empty model object from +coder+. +coder+ must contain
202
- # the attributes necessary for initializing an empty model object. For
203
- # example:
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('attributes' => { 'title' => 'hello world' })
299
+ # post.init_with(coder)
210
300
  # post.title # => 'hello world'
211
301
  def init_with(coder)
212
- @attributes = self.class.initialize_attributes(coder['attributes'])
213
- @column_types_override = coder['column_types']
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 = false
307
+ @new_record = coder['new_record']
219
308
 
220
309
  self.class.define_attribute_methods
221
310
 
222
- run_callbacks :find
223
- run_callbacks :initialize
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
- cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
257
- self.class.initialize_attributes(cloned_attributes, :serialized => false)
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
- run_callbacks(:initialize) unless _initialize_callbacks.empty?
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
- coder['attributes'] = attributes_for_coder
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.hash
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? || !_create_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