activerecord 4.0.13 → 4.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +745 -2700
  3. data/README.rdoc +2 -2
  4. data/examples/performance.rb +30 -18
  5. data/examples/simple.rb +4 -4
  6. data/lib/active_record.rb +2 -6
  7. data/lib/active_record/aggregations.rb +2 -1
  8. data/lib/active_record/association_relation.rb +0 -4
  9. data/lib/active_record/associations.rb +87 -43
  10. data/lib/active_record/associations/alias_tracker.rb +1 -3
  11. data/lib/active_record/associations/association.rb +8 -16
  12. data/lib/active_record/associations/association_scope.rb +5 -16
  13. data/lib/active_record/associations/belongs_to_association.rb +34 -25
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  15. data/lib/active_record/associations/builder/association.rb +78 -54
  16. data/lib/active_record/associations/builder/belongs_to.rb +91 -58
  17. data/lib/active_record/associations/builder/collection_association.rb +47 -45
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -25
  19. data/lib/active_record/associations/builder/has_many.rb +2 -2
  20. data/lib/active_record/associations/builder/has_one.rb +5 -7
  21. data/lib/active_record/associations/builder/singular_association.rb +6 -7
  22. data/lib/active_record/associations/collection_association.rb +68 -105
  23. data/lib/active_record/associations/collection_proxy.rb +12 -15
  24. data/lib/active_record/associations/has_many_association.rb +11 -9
  25. data/lib/active_record/associations/has_many_through_association.rb +16 -12
  26. data/lib/active_record/associations/has_one_association.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +204 -165
  28. data/lib/active_record/associations/join_dependency/join_association.rb +43 -101
  29. data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
  31. data/lib/active_record/associations/join_helper.rb +2 -11
  32. data/lib/active_record/associations/preloader.rb +89 -34
  33. data/lib/active_record/associations/preloader/association.rb +43 -25
  34. data/lib/active_record/associations/preloader/collection_association.rb +2 -2
  35. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +58 -26
  38. data/lib/active_record/associations/singular_association.rb +6 -5
  39. data/lib/active_record/associations/through_association.rb +2 -2
  40. data/lib/active_record/attribute_assignment.rb +5 -2
  41. data/lib/active_record/attribute_methods.rb +45 -40
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
  43. data/lib/active_record/attribute_methods/dirty.rb +8 -22
  44. data/lib/active_record/attribute_methods/primary_key.rb +1 -7
  45. data/lib/active_record/attribute_methods/read.rb +55 -28
  46. data/lib/active_record/attribute_methods/serialization.rb +12 -33
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -13
  48. data/lib/active_record/attribute_methods/write.rb +37 -12
  49. data/lib/active_record/autosave_association.rb +207 -207
  50. data/lib/active_record/base.rb +5 -1
  51. data/lib/active_record/callbacks.rb +2 -2
  52. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +2 -7
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +11 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +12 -14
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -5
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +84 -0
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +52 -83
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +0 -5
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +14 -97
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +58 -60
  63. data/lib/active_record/connection_adapters/column.rb +1 -35
  64. data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +3 -4
  66. data/lib/active_record/connection_adapters/mysql_adapter.rb +16 -15
  67. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +24 -18
  68. data/lib/active_record/connection_adapters/postgresql/cast.rb +20 -16
  69. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +23 -43
  70. data/lib/active_record/connection_adapters/postgresql/oid.rb +19 -12
  71. data/lib/active_record/connection_adapters/postgresql/quoting.rb +28 -23
  72. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +8 -30
  73. data/lib/active_record/connection_adapters/postgresql_adapter.rb +92 -75
  74. data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
  75. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +31 -64
  76. data/lib/active_record/connection_handling.rb +2 -2
  77. data/lib/active_record/core.rb +22 -43
  78. data/lib/active_record/counter_cache.rb +7 -7
  79. data/lib/active_record/enum.rb +100 -0
  80. data/lib/active_record/errors.rb +10 -5
  81. data/lib/active_record/fixture_set/file.rb +2 -1
  82. data/lib/active_record/fixtures.rb +171 -74
  83. data/lib/active_record/inheritance.rb +16 -22
  84. data/lib/active_record/integration.rb +52 -1
  85. data/lib/active_record/locking/optimistic.rb +7 -2
  86. data/lib/active_record/locking/pessimistic.rb +1 -1
  87. data/lib/active_record/log_subscriber.rb +5 -12
  88. data/lib/active_record/migration.rb +62 -46
  89. data/lib/active_record/migration/command_recorder.rb +7 -13
  90. data/lib/active_record/model_schema.rb +7 -14
  91. data/lib/active_record/nested_attributes.rb +10 -8
  92. data/lib/active_record/no_touching.rb +52 -0
  93. data/lib/active_record/null_relation.rb +3 -3
  94. data/lib/active_record/persistence.rb +16 -34
  95. data/lib/active_record/querying.rb +14 -12
  96. data/lib/active_record/railtie.rb +0 -50
  97. data/lib/active_record/railties/databases.rake +12 -15
  98. data/lib/active_record/readonly_attributes.rb +0 -6
  99. data/lib/active_record/reflection.rb +189 -75
  100. data/lib/active_record/relation.rb +69 -94
  101. data/lib/active_record/relation/batches.rb +57 -23
  102. data/lib/active_record/relation/calculations.rb +36 -43
  103. data/lib/active_record/relation/delegation.rb +54 -39
  104. data/lib/active_record/relation/finder_methods.rb +107 -62
  105. data/lib/active_record/relation/merger.rb +7 -20
  106. data/lib/active_record/relation/predicate_builder.rb +57 -38
  107. data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
  108. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  109. data/lib/active_record/relation/query_methods.rb +110 -98
  110. data/lib/active_record/relation/spawn_methods.rb +1 -2
  111. data/lib/active_record/result.rb +45 -6
  112. data/lib/active_record/runtime_registry.rb +5 -0
  113. data/lib/active_record/sanitization.rb +6 -8
  114. data/lib/active_record/schema_dumper.rb +16 -5
  115. data/lib/active_record/schema_migration.rb +24 -25
  116. data/lib/active_record/scoping/default.rb +5 -18
  117. data/lib/active_record/scoping/named.rb +8 -29
  118. data/lib/active_record/store.rb +56 -28
  119. data/lib/active_record/tasks/database_tasks.rb +8 -4
  120. data/lib/active_record/timestamp.rb +4 -4
  121. data/lib/active_record/transactions.rb +8 -10
  122. data/lib/active_record/validations/presence.rb +1 -1
  123. data/lib/active_record/validations/uniqueness.rb +1 -6
  124. data/lib/active_record/version.rb +1 -1
  125. data/lib/rails/generators/active_record.rb +2 -8
  126. data/lib/rails/generators/active_record/migration.rb +18 -0
  127. data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
  128. data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
  129. metadata +32 -45
  130. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
  131. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  132. data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
  133. data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
  134. data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
  135. data/lib/active_record/test_case.rb +0 -102
@@ -55,7 +55,7 @@ module ActiveRecord
55
55
  begin
56
56
  require path_to_adapter
57
57
  rescue Gem::LoadError => e
58
- raise Gem::LoadError, "Specified '#{spec[:adapter]}' for database adapter, but the gem is not loaded. Add `gem '#{e.name}'` to your Gemfile."
58
+ raise Gem::LoadError, "Specified '#{spec[:adapter]}' for database adapter, but the gem is not loaded. Add `gem '#{e.name}'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord)."
59
59
  rescue LoadError => e
60
60
  raise LoadError, "Could not load '#{path_to_adapter}'. Make sure that the adapter in config/database.yml is valid. If you use an adapter other than 'mysql', 'mysql2', 'postgresql' or 'sqlite3' add the necessary adapter gem to the Gemfile.", e.backtrace
61
61
  end
@@ -74,7 +74,7 @@ module ActiveRecord
74
74
  :password => config.password,
75
75
  :port => config.port,
76
76
  :database => config.path.sub(%r{^/},""),
77
- :host => config.hostname }
77
+ :host => config.host }
78
78
 
79
79
  spec.reject!{ |_,value| value.blank? }
80
80
 
@@ -1,6 +1,6 @@
1
1
  require 'active_record/connection_adapters/abstract_mysql_adapter'
2
2
 
3
- gem 'mysql2', '~> 0.3.10'
3
+ gem 'mysql2', '~> 0.3.13'
4
4
  require 'mysql2'
5
5
 
6
6
  module ActiveRecord
@@ -207,7 +207,7 @@ module ActiveRecord
207
207
 
208
208
  # Returns an array of arrays containing the field values.
209
209
  # Order is the same as that returned by +columns+.
210
- def select_rows(sql, name = nil, binds = [])
210
+ def select_rows(sql, name = nil)
211
211
  execute(sql, name).to_a
212
212
  end
213
213
 
@@ -229,8 +229,7 @@ module ActiveRecord
229
229
 
230
230
  alias exec_without_stmt exec_query
231
231
 
232
- # Returns an array of record hashes with the column names as keys and
233
- # column values as values.
232
+ # Returns an ActiveRecord::Result instance.
234
233
  def select(sql, name = nil, binds = [])
235
234
  exec_query(sql, name)
236
235
  end
@@ -160,12 +160,6 @@ module ActiveRecord
160
160
 
161
161
  # QUOTING ==================================================
162
162
 
163
- def type_cast(value, column)
164
- return super unless value == true || value == false
165
-
166
- value ? 1 : 0
167
- end
168
-
169
163
  def quote_string(string) #:nodoc:
170
164
  @connection.quote(string)
171
165
  end
@@ -213,9 +207,9 @@ module ActiveRecord
213
207
 
214
208
  # DATABASE STATEMENTS ======================================
215
209
 
216
- def select_rows(sql, name = nil, binds = [])
210
+ def select_rows(sql, name = nil)
217
211
  @connection.query_with_result = true
218
- rows = exec_query(sql, name, binds).rows
212
+ rows = exec_query(sql, name).rows
219
213
  @connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
220
214
  rows
221
215
  end
@@ -425,14 +419,19 @@ module ActiveRecord
425
419
 
426
420
  if result
427
421
  types = {}
422
+ fields = []
428
423
  result.fetch_fields.each { |field|
424
+ field_name = field.name
425
+ fields << field_name
426
+
429
427
  if field.decimals > 0
430
- types[field.name] = Fields::Decimal.new
428
+ types[field_name] = Fields::Decimal.new
431
429
  else
432
- types[field.name] = Fields.find_type field
430
+ types[field_name] = Fields.find_type field
433
431
  end
434
432
  }
435
- result_set = ActiveRecord::Result.new(types.keys, result.to_a, types)
433
+
434
+ result_set = ActiveRecord::Result.new(fields, result.to_a, types)
436
435
  result.free
437
436
  else
438
437
  result_set = ActiveRecord::Result.new([], [])
@@ -468,15 +467,17 @@ module ActiveRecord
468
467
 
469
468
  def begin_db_transaction #:nodoc:
470
469
  exec_query "BEGIN"
471
- rescue Mysql::Error
472
- # Transactions aren't supported
473
470
  end
474
471
 
475
472
  private
476
473
 
477
474
  def exec_stmt(sql, name, binds)
478
475
  cache = {}
479
- log(sql, name, binds) do
476
+ type_casted_binds = binds.map { |col, val|
477
+ [col, type_cast(val, col)]
478
+ }
479
+
480
+ log(sql, name, type_casted_binds) do
480
481
  if binds.empty?
481
482
  stmt = @connection.prepare(sql)
482
483
  else
@@ -487,7 +488,7 @@ module ActiveRecord
487
488
  end
488
489
 
489
490
  begin
490
- stmt.execute(*binds.map { |col, val| type_cast(val, col) })
491
+ stmt.execute(*type_casted_binds.map { |_, val| val })
491
492
  rescue Mysql::Error => e
492
493
  # Older versions of MySQL leave the prepared statement in a bad
493
494
  # place when an error occurs. To support older mysql versions, we
@@ -2,6 +2,13 @@ module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  class PostgreSQLColumn < Column
4
4
  module ArrayParser
5
+
6
+ DOUBLE_QUOTE = '"'
7
+ BACKSLASH = "\\"
8
+ COMMA = ','
9
+ BRACKET_OPEN = '{'
10
+ BRACKET_CLOSE = '}'
11
+
5
12
  private
6
13
  # Loads pg_array_parser if available. String parsing can be
7
14
  # performed quicker by a native extension, which will not create
@@ -12,18 +19,18 @@ module ActiveRecord
12
19
  include PgArrayParser
13
20
  rescue LoadError
14
21
  def parse_pg_array(string)
15
- parse_data(string, 0)
22
+ parse_data(string)
16
23
  end
17
24
  end
18
25
 
19
- def parse_data(string, index)
20
- local_index = index
26
+ def parse_data(string)
27
+ local_index = 0
21
28
  array = []
22
29
  while(local_index < string.length)
23
30
  case string[local_index]
24
- when '{'
31
+ when BRACKET_OPEN
25
32
  local_index,array = parse_array_contents(array, string, local_index + 1)
26
- when '}'
33
+ when BRACKET_CLOSE
27
34
  return array
28
35
  end
29
36
  local_index += 1
@@ -33,9 +40,9 @@ module ActiveRecord
33
40
  end
34
41
 
35
42
  def parse_array_contents(array, string, index)
36
- is_escaping = false
37
- is_quoted = false
38
- was_quoted = false
43
+ is_escaping = false
44
+ is_quoted = false
45
+ was_quoted = false
39
46
  current_item = ''
40
47
 
41
48
  local_index = index
@@ -47,29 +54,29 @@ module ActiveRecord
47
54
  else
48
55
  if is_quoted
49
56
  case token
50
- when '"'
57
+ when DOUBLE_QUOTE
51
58
  is_quoted = false
52
59
  was_quoted = true
53
- when "\\"
60
+ when BACKSLASH
54
61
  is_escaping = true
55
62
  else
56
63
  current_item << token
57
64
  end
58
65
  else
59
66
  case token
60
- when "\\"
67
+ when BACKSLASH
61
68
  is_escaping = true
62
- when ','
69
+ when COMMA
63
70
  add_item_to_array(array, current_item, was_quoted)
64
71
  current_item = ''
65
72
  was_quoted = false
66
- when '"'
73
+ when DOUBLE_QUOTE
67
74
  is_quoted = true
68
- when '{'
75
+ when BRACKET_OPEN
69
76
  internal_items = []
70
77
  local_index,internal_items = parse_array_contents(internal_items, string, local_index + 1)
71
78
  array.push(internal_items)
72
- when '}'
79
+ when BRACKET_CLOSE
73
80
  add_item_to_array(array, current_item, was_quoted)
74
81
  return local_index,array
75
82
  else
@@ -84,9 +91,8 @@ module ActiveRecord
84
91
  end
85
92
 
86
93
  def add_item_to_array(array, current_item, quoted)
87
- return if !quoted && current_item.length == 0
88
-
89
- if !quoted && current_item == 'NULL'
94
+ if current_item.length == 0
95
+ elsif !quoted && current_item == 'NULL'
90
96
  array.push nil
91
97
  else
92
98
  array.push current_item
@@ -17,8 +17,8 @@ module ActiveRecord
17
17
  return string unless String === string
18
18
 
19
19
  case string
20
- when 'infinity'; 1.0 / 0.0
21
- when '-infinity'; -1.0 / 0.0
20
+ when 'infinity'; Float::INFINITY
21
+ when '-infinity'; -Float::INFINITY
22
22
  when / BC$/
23
23
  super("-" + string.sub(/ BC$/, ""))
24
24
  else
@@ -35,11 +35,11 @@ module ActiveRecord
35
35
  end
36
36
  end
37
37
 
38
- def hstore_to_string(object, array_member = false)
38
+ def hstore_to_string(object)
39
39
  if Hash === object
40
- string = object.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(',')
41
- string = escape_hstore(string) if array_member
42
- string
40
+ object.map { |k,v|
41
+ "#{escape_hstore(k)}=>#{escape_hstore(v)}"
42
+ }.join ','
43
43
  else
44
44
  object
45
45
  end
@@ -49,10 +49,10 @@ module ActiveRecord
49
49
  if string.nil?
50
50
  nil
51
51
  elsif String === string
52
- Hash[string.scan(HstorePair).map { |k, v|
52
+ Hash[string.scan(HstorePair).map { |k,v|
53
53
  v = v.upcase == 'NULL' ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
54
54
  k = k.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
55
- [k, v]
55
+ [k,v]
56
56
  }]
57
57
  else
58
58
  string
@@ -67,7 +67,7 @@ module ActiveRecord
67
67
  end
68
68
  end
69
69
 
70
- def array_to_string(value, column, adapter, should_be_quoted = false)
70
+ def array_to_string(value, column, adapter)
71
71
  casted_values = value.map do |val|
72
72
  if String === val
73
73
  if val == "NULL"
@@ -119,7 +119,7 @@ module ActiveRecord
119
119
  end
120
120
 
121
121
  def string_to_array(string, oid)
122
- parse_pg_array(string).map{|val| oid.type_cast val}
122
+ parse_pg_array(string).map {|val| type_cast_array(oid, val)}
123
123
  end
124
124
 
125
125
  private
@@ -142,16 +142,20 @@ module ActiveRecord
142
142
  end
143
143
  end
144
144
 
145
- ARRAY_ESCAPE = "\\" * 2 * 2 # escape the backslash twice for PG arrays
146
-
147
145
  def quote_and_escape(value)
148
146
  case value
149
- when "NULL", Numeric
147
+ when "NULL"
150
148
  value
151
149
  else
152
- value = value.gsub(/\\/, ARRAY_ESCAPE)
153
- value.gsub!(/"/,"\\\"")
154
- "\"#{value}\""
150
+ "\"#{value.gsub(/"/,"\\\"")}\""
151
+ end
152
+ end
153
+
154
+ def type_cast_array(oid, value)
155
+ if ::Array === value
156
+ value.map {|item| type_cast_array(oid, item)}
157
+ else
158
+ oid.type_cast value
155
159
  end
156
160
  end
157
161
  end
@@ -46,8 +46,8 @@ module ActiveRecord
46
46
 
47
47
  # Executes a SELECT query and returns an array of rows. Each row is an
48
48
  # array of field values.
49
- def select_rows(sql, name = nil, binds = [])
50
- exec_query(sql, name, binds).rows
49
+ def select_rows(sql, name = nil)
50
+ select_raw(sql, name).last
51
51
  end
52
52
 
53
53
  # Executes an INSERT query and returns the new record's ID
@@ -134,32 +134,31 @@ module ActiveRecord
134
134
  end
135
135
 
136
136
  def exec_query(sql, name = 'SQL', binds = [])
137
- log(sql, name, binds) do
138
- result = without_prepared_statement?(binds) ? exec_no_cache(sql, binds) :
139
- exec_cache(sql, binds)
140
-
141
- types = {}
142
- fields = result.fields
143
- fields.each_with_index do |fname, i|
144
- ftype = result.ftype i
145
- fmod = result.fmod i
146
- types[fname] = get_oid_type(ftype, fmod, fname)
147
- end
148
-
149
- ret = ActiveRecord::Result.new(fields, result.values, types)
150
- result.clear
151
- return ret
137
+ result = without_prepared_statement?(binds) ? exec_no_cache(sql, name, binds) :
138
+ exec_cache(sql, name, binds)
139
+
140
+ types = {}
141
+ fields = result.fields
142
+ fields.each_with_index do |fname, i|
143
+ ftype = result.ftype i
144
+ fmod = result.fmod i
145
+ types[fname] = type_map.fetch(ftype, fmod) { |oid, mod|
146
+ warn "unknown OID: #{fname}(#{oid}) (#{sql})"
147
+ OID::Identity.new
148
+ }
152
149
  end
150
+
151
+ ret = ActiveRecord::Result.new(fields, result.values, types)
152
+ result.clear
153
+ return ret
153
154
  end
154
155
 
155
156
  def exec_delete(sql, name = 'SQL', binds = [])
156
- log(sql, name, binds) do
157
- result = without_prepared_statement?(binds) ? exec_no_cache(sql, binds) :
158
- exec_cache(sql, binds)
159
- affected = result.cmd_tuples
160
- result.clear
161
- affected
162
- end
157
+ result = without_prepared_statement?(binds) ? exec_no_cache(sql, name, binds) :
158
+ exec_cache(sql, name, binds)
159
+ affected = result.cmd_tuples
160
+ result.clear
161
+ affected
163
162
  end
164
163
  alias :exec_update :exec_delete
165
164
 
@@ -215,25 +214,6 @@ module ActiveRecord
215
214
  def rollback_db_transaction
216
215
  execute "ROLLBACK"
217
216
  end
218
-
219
- def outside_transaction?
220
- message = "#outside_transaction? is deprecated. This method was only really used " \
221
- "internally, but you can use #transaction_open? instead."
222
- ActiveSupport::Deprecation.warn message
223
- @connection.transaction_status == PGconn::PQTRANS_IDLE
224
- end
225
-
226
- def create_savepoint
227
- execute("SAVEPOINT #{current_savepoint_name}")
228
- end
229
-
230
- def rollback_to_savepoint
231
- execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
232
- end
233
-
234
- def release_savepoint
235
- execute("RELEASE SAVEPOINT #{current_savepoint_name}")
236
- end
237
217
  end
238
218
  end
239
219
  end
@@ -6,10 +6,6 @@ module ActiveRecord
6
6
  module OID
7
7
  class Type
8
8
  def type; end
9
-
10
- def type_cast_for_write(value)
11
- value
12
- end
13
9
  end
14
10
 
15
11
  class Identity < Type
@@ -31,9 +27,6 @@ module ActiveRecord
31
27
  class Bytea < Type
32
28
  def type_cast(value)
33
29
  return if value.nil?
34
- # This is a flawed heuristic, but it avoids truncation;
35
- # we really shouldn’t be calling this with already-unescaped values
36
- return value if value.dup.force_encoding("BINARY") =~ /\x00/
37
30
  PGconn.unescape_bytea value
38
31
  end
39
32
  end
@@ -232,11 +225,19 @@ module ActiveRecord
232
225
  end
233
226
 
234
227
  class Hstore < Type
228
+ def type_cast_for_write(value)
229
+ ConnectionAdapters::PostgreSQLColumn.hstore_to_string value
230
+ end
231
+
235
232
  def type_cast(value)
236
233
  return if value.nil?
237
234
 
238
235
  ConnectionAdapters::PostgreSQLColumn.string_to_hstore value
239
236
  end
237
+
238
+ def accessor
239
+ ActiveRecord::Store::StringKeyedHashAccessor
240
+ end
240
241
  end
241
242
 
242
243
  class Cidr < Type
@@ -248,11 +249,19 @@ module ActiveRecord
248
249
  end
249
250
 
250
251
  class Json < Type
252
+ def type_cast_for_write(value)
253
+ ConnectionAdapters::PostgreSQLColumn.json_to_string value
254
+ end
255
+
251
256
  def type_cast(value)
252
257
  return if value.nil?
253
258
 
254
259
  ConnectionAdapters::PostgreSQLColumn.string_to_json value
255
260
  end
261
+
262
+ def accessor
263
+ ActiveRecord::Store::StringKeyedHashAccessor
264
+ end
256
265
  end
257
266
 
258
267
  class TypeMap
@@ -292,17 +301,15 @@ module ActiveRecord
292
301
  end
293
302
  end
294
303
 
295
- TYPE_MAP = TypeMap.new # :nodoc:
296
-
297
- # When the PG adapter connects, the pg_type table is queried. The
304
+ # When the PG adapter connects, the pg_type table is queried. The
298
305
  # key of this hash maps to the `typname` column from the table.
299
- # TYPE_MAP is then dynamically built with oids as the key and type
306
+ # type_map is then dynamically built with oids as the key and type
300
307
  # objects as values.
301
308
  NAMES = Hash.new { |h,k| # :nodoc:
302
309
  h[k] = OID::Identity.new
303
310
  }
304
311
 
305
- # Register an OID type named +name+ with a typcasting object in
312
+ # Register an OID type named +name+ with a typecasting object in
306
313
  # +type+. +name+ should correspond to the `typname` column in
307
314
  # the `pg_type` table.
308
315
  def self.register_type(name, type)