sequel 3.44.0 → 3.45.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/CHANGELOG +44 -0
  2. data/Rakefile +12 -4
  3. data/doc/reflection.rdoc +3 -3
  4. data/doc/release_notes/3.45.0.txt +179 -0
  5. data/doc/schema_modification.rdoc +1 -1
  6. data/doc/transactions.rdoc +23 -0
  7. data/lib/sequel/adapters/db2.rb +1 -0
  8. data/lib/sequel/adapters/ibmdb.rb +19 -3
  9. data/lib/sequel/adapters/jdbc.rb +15 -0
  10. data/lib/sequel/adapters/jdbc/derby.rb +1 -5
  11. data/lib/sequel/adapters/jdbc/h2.rb +1 -0
  12. data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -1
  13. data/lib/sequel/adapters/jdbc/jtds.rb +5 -0
  14. data/lib/sequel/adapters/jdbc/mysql.rb +5 -0
  15. data/lib/sequel/adapters/jdbc/oracle.rb +7 -1
  16. data/lib/sequel/adapters/jdbc/sqlite.rb +1 -1
  17. data/lib/sequel/adapters/jdbc/transactions.rb +28 -1
  18. data/lib/sequel/adapters/mysql.rb +4 -0
  19. data/lib/sequel/adapters/mysql2.rb +5 -1
  20. data/lib/sequel/adapters/oracle.rb +18 -0
  21. data/lib/sequel/adapters/postgres.rb +11 -1
  22. data/lib/sequel/adapters/shared/access.rb +14 -2
  23. data/lib/sequel/adapters/shared/cubrid.rb +1 -11
  24. data/lib/sequel/adapters/shared/db2.rb +11 -6
  25. data/lib/sequel/adapters/shared/mssql.rb +10 -10
  26. data/lib/sequel/adapters/shared/mysql.rb +11 -1
  27. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +17 -1
  28. data/lib/sequel/adapters/shared/oracle.rb +16 -15
  29. data/lib/sequel/adapters/shared/postgres.rb +91 -59
  30. data/lib/sequel/adapters/shared/sqlite.rb +1 -4
  31. data/lib/sequel/adapters/tinytds.rb +15 -0
  32. data/lib/sequel/connection_pool/threaded.rb +1 -1
  33. data/lib/sequel/core.rb +10 -0
  34. data/lib/sequel/database/connecting.rb +2 -0
  35. data/lib/sequel/database/misc.rb +46 -4
  36. data/lib/sequel/database/query.rb +33 -14
  37. data/lib/sequel/database/schema_methods.rb +0 -5
  38. data/lib/sequel/dataset/misc.rb +9 -0
  39. data/lib/sequel/dataset/mutation.rb +9 -7
  40. data/lib/sequel/dataset/sql.rb +13 -0
  41. data/lib/sequel/exceptions.rb +3 -0
  42. data/lib/sequel/extensions/connection_validator.rb +1 -1
  43. data/lib/sequel/extensions/date_arithmetic.rb +0 -8
  44. data/lib/sequel/extensions/eval_inspect.rb +2 -0
  45. data/lib/sequel/extensions/named_timezones.rb +18 -2
  46. data/lib/sequel/extensions/pg_array.rb +5 -1
  47. data/lib/sequel/extensions/pg_array_ops.rb +2 -0
  48. data/lib/sequel/extensions/pg_hstore.rb +2 -0
  49. data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
  50. data/lib/sequel/extensions/pg_json.rb +3 -1
  51. data/lib/sequel/extensions/pg_range.rb +2 -0
  52. data/lib/sequel/extensions/pg_range_ops.rb +2 -0
  53. data/lib/sequel/extensions/pg_row.rb +2 -0
  54. data/lib/sequel/extensions/pg_row_ops.rb +2 -0
  55. data/lib/sequel/extensions/query.rb +18 -22
  56. data/lib/sequel/model/associations.rb +3 -4
  57. data/lib/sequel/model/base.rb +2 -0
  58. data/lib/sequel/plugins/force_encoding.rb +2 -0
  59. data/lib/sequel/plugins/json_serializer.rb +155 -39
  60. data/lib/sequel/plugins/serialization.rb +14 -2
  61. data/lib/sequel/plugins/unlimited_update.rb +31 -0
  62. data/lib/sequel/plugins/validation_class_methods.rb +6 -4
  63. data/lib/sequel/plugins/xml_serializer.rb +133 -30
  64. data/lib/sequel/sql.rb +2 -0
  65. data/lib/sequel/timezones.rb +4 -0
  66. data/lib/sequel/version.rb +1 -1
  67. data/spec/adapters/mysql_spec.rb +0 -11
  68. data/spec/adapters/postgres_spec.rb +86 -54
  69. data/spec/adapters/spec_helper.rb +6 -0
  70. data/spec/core/connection_pool_spec.rb +16 -0
  71. data/spec/core/database_spec.rb +77 -1
  72. data/spec/core/dataset_spec.rb +30 -15
  73. data/spec/core/expression_filters_spec.rb +55 -13
  74. data/spec/core/mock_adapter_spec.rb +4 -0
  75. data/spec/core/schema_spec.rb +0 -2
  76. data/spec/core/spec_helper.rb +5 -0
  77. data/spec/core_extensions_spec.rb +33 -28
  78. data/spec/extensions/constraint_validations_spec.rb +2 -2
  79. data/spec/extensions/core_refinements_spec.rb +12 -12
  80. data/spec/extensions/json_serializer_spec.rb +137 -31
  81. data/spec/extensions/named_timezones_spec.rb +10 -0
  82. data/spec/extensions/pg_auto_parameterize_spec.rb +5 -0
  83. data/spec/extensions/pg_json_spec.rb +14 -0
  84. data/spec/extensions/pg_row_spec.rb +11 -0
  85. data/spec/extensions/pretty_table_spec.rb +2 -2
  86. data/spec/extensions/query_spec.rb +11 -8
  87. data/spec/extensions/serialization_spec.rb +20 -0
  88. data/spec/extensions/spec_helper.rb +8 -2
  89. data/spec/extensions/sql_expr_spec.rb +1 -1
  90. data/spec/extensions/unlimited_update_spec.rb +20 -0
  91. data/spec/extensions/xml_serializer_spec.rb +68 -16
  92. data/spec/integration/dataset_test.rb +28 -0
  93. data/spec/integration/spec_helper.rb +6 -0
  94. data/spec/integration/transaction_test.rb +39 -0
  95. data/spec/model/model_spec.rb +1 -1
  96. data/spec/sequel_coverage.rb +15 -0
  97. metadata +8 -3
@@ -287,6 +287,7 @@ module Sequel
287
287
  end
288
288
  end
289
289
 
290
+ # :nocov:
290
291
  if Sequel.core_extensions?
291
292
  class Symbol
292
293
  include Sequel::Postgres::HStoreOpMethods
@@ -300,3 +301,4 @@ if defined?(Sequel::CoreRefinements)
300
301
  end
301
302
  end
302
303
  end
304
+ # :nocov:
@@ -98,7 +98,7 @@ module Sequel
98
98
  # parsing does not yield an array or hash.
99
99
  def self.parse_json(s)
100
100
  begin
101
- value = JSON.parse(s)
101
+ value = Sequel.parse_json(s)
102
102
  rescue JSON::ParserError=>e
103
103
  raise Sequel.convert_exception_class(e, Sequel::InvalidValue)
104
104
  end
@@ -192,6 +192,7 @@ module Sequel
192
192
  Database.register_extension(:pg_json, Postgres::JSONDatabaseMethods)
193
193
  end
194
194
 
195
+ # :nocov:
195
196
  if Sequel.core_extensions?
196
197
  class Array
197
198
  # Return a Sequel::Postgres::JSONArray proxy to the receiver.
@@ -227,3 +228,4 @@ if defined?(Sequel::CoreRefinements)
227
228
  end
228
229
  end
229
230
  end
231
+ # :nocov:
@@ -503,6 +503,7 @@ module Sequel
503
503
  Database.register_extension(:pg_range, Postgres::PGRange::DatabaseMethods)
504
504
  end
505
505
 
506
+ # :nocov:
506
507
  if Sequel.core_extensions?
507
508
  class Range
508
509
  # Create a new PGRange using the receiver as the input range,
@@ -522,3 +523,4 @@ if defined?(Sequel::CoreRefinements)
522
523
  end
523
524
  end
524
525
  end
526
+ # :nocov:
@@ -144,6 +144,7 @@ module Sequel
144
144
  end
145
145
  end
146
146
 
147
+ # :nocov:
147
148
  if Sequel.core_extensions?
148
149
  class Symbol
149
150
  include Sequel::Postgres::RangeOpMethods
@@ -157,3 +158,4 @@ if defined?(Sequel::CoreRefinements)
157
158
  end
158
159
  end
159
160
  end
161
+ # :nocov:
@@ -572,6 +572,7 @@ module Sequel
572
572
  Database.register_extension(:pg_row, Postgres::PGRow::DatabaseMethods)
573
573
  end
574
574
 
575
+ # :nocov:
575
576
  if Sequel.core_extensions?
576
577
  class Array
577
578
  # Wraps the receiver in an anonymous Sequel::Postgres::PGRow::ArrayRow instance.
@@ -590,3 +591,4 @@ if defined?(Sequel::CoreRefinements)
590
591
  end
591
592
  end
592
593
  end
594
+ # :nocov:
@@ -176,6 +176,7 @@ module Sequel
176
176
  end
177
177
  end
178
178
 
179
+ # :nocov:
179
180
  if Sequel.core_extensions?
180
181
  class Symbol
181
182
  include Sequel::Postgres::PGRowOp::ExpressionMethods
@@ -189,3 +190,4 @@ if defined?(Sequel::CoreRefinements)
189
190
  end
190
191
  end
191
192
  end
193
+ # :nocov:
@@ -1,12 +1,10 @@
1
1
  # The query extension adds Sequel::Dataset#query which allows
2
2
  # a different way to construct queries instead of the usual
3
- # method chaining.
3
+ # method chaining. See Sequel::Dataset#query for details.
4
4
  #
5
5
  # To load the extension, do:
6
6
  #
7
7
  # Sequel.extension :query
8
- #
9
- # This extension uses Object#extend at runtime, which can hurt performance.
10
8
 
11
9
  module Sequel
12
10
  class Database
@@ -17,8 +15,9 @@ module Sequel
17
15
  end
18
16
 
19
17
  class Dataset
20
- # Translates a query block into a dataset. Query blocks can be useful
21
- # when expressing complex SELECT statements, e.g.:
18
+ # Translates a query block into a dataset. Query blocks are an
19
+ # alternative to Sequel's usual method chaining, by using
20
+ # instance_eval with a proxy object:
22
21
  #
23
22
  # dataset = DB[:items].query do
24
23
  # select :x, :y, :z
@@ -29,28 +28,25 @@ module Sequel
29
28
  # Which is the same as:
30
29
  #
31
30
  # dataset = DB[:items].select(:x, :y, :z).filter{(x > 1) & (y > 2)}.reverse(:z)
32
- #
33
- # Note that inside a call to query, you cannot call each, insert, update,
34
- # or delete (or any method that calls those), or Sequel will raise an
35
- # error.
36
31
  def query(&block)
37
- copy = clone({})
38
- copy.extend(QueryBlockCopy)
39
- copy.instance_eval(&block)
40
- clone(copy.opts)
32
+ query = Query.new(self)
33
+ query.instance_eval(&block)
34
+ query.dataset
41
35
  end
42
36
 
43
- # Module used by Dataset#query that has the effect of making all
44
- # dataset methods into !-style methods that modify the receiver.
45
- module QueryBlockCopy
46
- %w'each insert update delete'.each do |meth|
47
- define_method(meth){|*args| raise Error, "##{meth} cannot be invoked inside a query block."}
37
+ # Proxy object used by Dataset#query.
38
+ class Query < Sequel::BasicObject
39
+ # The current dataset in the query. This changes on each method call.
40
+ attr_reader :dataset
41
+
42
+ def initialize(dataset)
43
+ @dataset = dataset
48
44
  end
49
45
 
50
- # Merge the given options into the receiver's options and return the receiver
51
- # instead of cloning the receiver.
52
- def clone(opts = {})
53
- @opts.merge!(opts)
46
+ # Replace the query's dataset with dataset returned by the method call.
47
+ def method_missing(method, *args, &block)
48
+ @dataset = @dataset.send(method, *args, &block)
49
+ raise(Sequel::Error, "method #{method.inspect} did not return a dataset") unless @dataset.is_a?(Dataset)
54
50
  self
55
51
  end
56
52
  end
@@ -254,6 +254,7 @@ module Sequel
254
254
  private
255
255
 
256
256
  if defined?(RUBY_ENGINE) && RUBY_ENGINE != 'ruby'
257
+ # :nocov:
257
258
  # On non-GVL rubies, assume the need to synchronize access. Store the key
258
259
  # in a special sub-hash that always uses this method to synchronize access.
259
260
  def cached_fetch(key)
@@ -270,6 +271,7 @@ module Sequel
270
271
  h = self[:cache]
271
272
  Sequel.synchronize{h[key] = value}
272
273
  end
274
+ # :nocov:
273
275
  else
274
276
  # On MRI, use a plain fetch, since the GVL will synchronize access.
275
277
  def cached_fetch(key)
@@ -1749,10 +1751,7 @@ module Sequel
1749
1751
  #
1750
1752
  # Artist.eager(:albums => {proc{|ds| ds.where{year > 1990}}=>{:tracks => :genre}})
1751
1753
  module DatasetMethods
1752
- # Add the <tt>eager!</tt> and <tt>eager_graph!</tt> mutation methods to the dataset.
1753
- def self.extended(obj)
1754
- obj.def_mutation_method(:eager, :eager_graph)
1755
- end
1754
+ Sequel::Dataset.def_mutation_method(:eager, :eager_graph, :module=>self)
1756
1755
 
1757
1756
  # If the expression is in the form <tt>x = y</tt> where +y+ is a <tt>Sequel::Model</tt>
1758
1757
  # instance, array of <tt>Sequel::Model</tt> instances, or a <tt>Sequel::Model</tt> dataset,
@@ -780,7 +780,9 @@ module Sequel
780
780
  if RUBY_VERSION >= '1.9'
781
781
  plugin.const_defined?(submod, false)
782
782
  else
783
+ # :nocov:
783
784
  plugin.const_defined?(submod)
785
+ # :nocov:
784
786
  end
785
787
  end
786
788
 
@@ -74,5 +74,7 @@ module Sequel
74
74
  end
75
75
  end
76
76
  else
77
+ # :nocov:
77
78
  raise LoadError, 'ForceEncoding plugin only works on Ruby 1.9+'
79
+ # :nocov:
78
80
  end
@@ -36,30 +36,54 @@ module Sequel
36
36
  # album.to_json(:root => true)
37
37
  # # => '{"album":{"id":1,"name":"RF","artist_id":2}}'
38
38
  #
39
+ # Additionally, +to_json+ also exists as a class and dataset method, both
40
+ # of which return all objects in the dataset:
41
+ #
42
+ # Album.to_json
43
+ # Album.filter(:artist_id=>1).to_json(:include=>:tags)
44
+ #
45
+ # If you have an existing array of model instances you want to convert to
46
+ # JSON, you can call the class to_json method with the :array option:
47
+ #
48
+ # Album.to_json(:array=>[Album[1], Album[2]])
49
+ #
39
50
  # In addition to creating JSON, this plugin also enables Sequel::Model
40
- # objects to be automatically created when JSON is parsed:
51
+ # classes to create instances directly from JSON using the from_json class
52
+ # method:
41
53
  #
42
54
  # json = album.to_json
43
- # album = JSON.parse(json)
55
+ # album = Album.from_json(json)
56
+ #
57
+ # The array_from_json class method exists to parse arrays of model instances
58
+ # from json:
59
+ #
60
+ # json = Album.filter(:artist_id=>1).to_json
61
+ # albums = Album.array_from_json(json)
62
+ #
63
+ # These does not necessarily round trip, since doing so would let users
64
+ # create model objects with arbitrary values. By default, from_json will
65
+ # call set with the values in the hash. If you want to specify the allowed
66
+ # fields, you can use the :fields option, which will call set_fields with
67
+ # the given fields:
68
+ #
69
+ # Album.from_json(album.to_json, :fields=>%w'id name')
44
70
  #
45
- # In addition, you can update existing model objects directly from JSON
46
- # using +from_json+:
71
+ # If you want to update an existing instance, you can use the from_json
72
+ # instance method:
47
73
  #
48
74
  # album.from_json(json)
49
75
  #
50
- # This works by parsing the JSON (which should return a hash), and then
51
- # calling +set+ with the returned hash.
76
+ # Both of these allow creation of cached associated objects, if you provide
77
+ # the :associations option:
52
78
  #
53
- # Additionally, +to_json+ also exists as a class and dataset method, both
54
- # of which return all objects in the dataset:
79
+ # album.from_json(json, :associations=>:artist)
55
80
  #
56
- # Album.to_json
57
- # Album.filter(:artist_id=>1).to_json(:include=>:tags)
81
+ # You can even provide options when setting up the associated objects:
58
82
  #
59
- # If you have an existing array of model instances you want to convert to
60
- # JSON, you can call the class to_json method with the :array option:
83
+ # album.from_json(json, :associations=>{:artist=>{:fields=>%w'id name', :associations=>:tags}})
61
84
  #
62
- # Album.to_json(:array=>[Album[1], Album[2]])
85
+ # If the json is trusted and should be allowed to set all column and association
86
+ # values, you can use the :all_columns and :all_associations options.
63
87
  #
64
88
  # Note that active_support/json makes incompatible changes to the to_json API,
65
89
  # and breaks some aspects of the json_serializer plugin. You can undo the damage
@@ -116,29 +140,39 @@ module Sequel
116
140
  # The default opts to use when serializing model objects to JSON.
117
141
  attr_reader :json_serializer_opts
118
142
 
119
- # Create a new model object from the hash provided by parsing
120
- # JSON. Handles column values (stored in +values+), associations
121
- # (stored in +associations+), and other values (by calling a
122
- # setter method). If an entry in the hash is not a column or
123
- # an association, and no setter method exists, raises an Error.
124
- def json_create(hash)
125
- obj = new
126
- cols = columns.map{|x| x.to_s}
127
- assocs = associations.map{|x| x.to_s}
128
- meths = obj.send(:setter_methods, nil, nil)
129
- hash.delete(JSON.create_id)
130
- hash.each do |k, v|
131
- if assocs.include?(k)
132
- obj.associations[k.to_sym] = v
133
- elsif meths.include?("#{k}=")
134
- obj.send("#{k}=", v)
135
- elsif cols.include?(k)
136
- obj.values[k.to_sym] = v
137
- else
138
- raise Error, "Entry in JSON hash not an association or column and no setter method exists: #{k}"
139
- end
143
+ # Attempt to parse a single instance from the given JSON string,
144
+ # with options passed to InstanceMethods#from_json_node.
145
+ def from_json(json, opts={})
146
+ v = Sequel.parse_json(json)
147
+ case v
148
+ when self
149
+ v
150
+ when Hash
151
+ new.from_json_node(v, opts)
152
+ else
153
+ raise Error, "parsed json doesn't return a hash or instance of #{self}"
154
+ end
155
+ end
156
+
157
+ # Attempt to parse an array of instances from the given JSON string,
158
+ # with options passed to InstanceMethods#from_json_node.
159
+ def array_from_json(json, opts={})
160
+ v = Sequel.parse_json(json)
161
+ if v.is_a?(Array)
162
+ raise(Error, 'parsed json returned an array containing non-hashes') unless v.all?{|ve| ve.is_a?(Hash) || ve.is_a?(self)}
163
+ v.map{|ve| ve.is_a?(self) ? ve : new.from_json_node(ve, opts)}
164
+ else
165
+ raise(Error, 'parsed json did not return an array')
140
166
  end
141
- obj
167
+ end
168
+
169
+ # Exists for compatibility with old json library which allows creation
170
+ # of arbitrary ruby objects by JSON.parse. Creates a new instance
171
+ # and populates it using InstanceMethods#from_json_node with the
172
+ # :all_columns and :all_associations options. Not recommended for usage
173
+ # in new code, consider calling the from_json method directly with the JSON string.
174
+ def json_create(hash, opts={})
175
+ new.from_json_node(hash, {:all_columns=>true, :all_associations=>true}.merge(opts))
142
176
  end
143
177
 
144
178
  # Call the dataset +to_json+ method.
@@ -157,14 +191,96 @@ module Sequel
157
191
 
158
192
  module InstanceMethods
159
193
  # Parse the provided JSON, which should return a hash,
160
- # and call +set+ with that hash.
194
+ # and process the hash with from_json_node.
161
195
  def from_json(json, opts={})
162
- h = JSON.parse(json)
196
+ from_json_node(Sequel.parse_json(json), opts)
197
+ end
198
+
199
+ # Using the provided hash, update the instance with data contained in the hash. By default, just
200
+ # calls set with the hash values.
201
+ #
202
+ # Options:
203
+ # :all_associations :: Indicates that all associations supported by the model should be tried.
204
+ # This option also cascades to associations if used. It is better to use the
205
+ # :associations option instead of this option. This option only exists for
206
+ # backwards compatibility.
207
+ # :all_columns :: Overrides the setting logic allowing all setter methods be used,
208
+ # even if access to the setter method is restricted.
209
+ # This option cascades to associations if used, and can be reset in those associations
210
+ # using the :all_columns=>false or :fields options. This option is considered a
211
+ # security risk, and only exists for backwards compatibility. It is better to use
212
+ # the :fields option appropriately instead of this option, or no option at all.
213
+ # :associations :: Indicates that the associations cache should be updated by creating
214
+ # a new associated object using data from the hash. Should be a Symbol
215
+ # for a single association, an array of symbols for multiple associations,
216
+ # or a hash with symbol keys and dependent association option hash values.
217
+ # :fields :: Changes the behavior to call set_fields using the provided fields, instead of calling set.
218
+ def from_json_node(hash, opts={})
219
+ unless hash.is_a?(Hash)
220
+ raise Error, "parsed json doesn't return a hash"
221
+ end
222
+ hash.delete(JSON.create_id)
223
+
224
+ unless assocs = opts[:associations]
225
+ if opts[:all_associations]
226
+ assocs = {}
227
+ model.associations.each{|v| assocs[v] = {:all_associations=>true}}
228
+ end
229
+ end
230
+
231
+ if assocs
232
+ assocs = case assocs
233
+ when Symbol
234
+ {assocs=>{}}
235
+ when Array
236
+ assocs_tmp = {}
237
+ assocs.each{|v| assocs_tmp[v] = {}}
238
+ assocs_tmp
239
+ when Hash
240
+ assocs
241
+ else
242
+ raise Error, ":associations should be Symbol, Array, or Hash if present"
243
+ end
244
+
245
+ if opts[:all_columns]
246
+ assocs.each_value do |assoc_opts|
247
+ assoc_opts[:all_columns] = true unless assoc_opts.has_key?(:fields) || assoc_opts.has_key?(:all_columns)
248
+ end
249
+ end
250
+
251
+ assocs.each do |assoc, assoc_opts|
252
+ if assoc_values = hash.delete(assoc.to_s)
253
+ unless r = model.association_reflection(assoc)
254
+ raise Error, "Association #{assoc} is not defined for #{model}"
255
+ end
256
+
257
+ associations[assoc] = if r.returns_array?
258
+ raise Error, "Attempt to populate array association with a non-array" unless assoc_values.is_a?(Array)
259
+ assoc_values.map{|v| v.is_a?(r.associated_class) ? v : r.associated_class.new.from_json_node(v, assoc_opts)}
260
+ else
261
+ raise Error, "Attempt to populate non-array association with an array" if assoc_values.is_a?(Array)
262
+ assoc_values.is_a?(r.associated_class) ? assoc_values : r.associated_class.new.from_json_node(assoc_values, assoc_opts)
263
+ end
264
+ end
265
+ end
266
+ end
267
+
163
268
  if fields = opts[:fields]
164
- set_fields(h, fields, opts)
269
+ set_fields(hash, fields, opts)
270
+ elsif opts[:all_columns]
271
+ meths = methods.collect{|x| x.to_s}.grep(Model::SETTER_METHOD_REGEXP) - Model::RESTRICTED_SETTER_METHODS
272
+ hash.each do |k, v|
273
+ if meths.include?(setter_meth = "#{k}=")
274
+ send(setter_meth, v)
275
+ else
276
+ raise Error, "Entry in JSON does not have a matching setter method: #{k}"
277
+ end
278
+ end
165
279
  else
166
- set(h)
280
+ set(hash)
167
281
  end
282
+
283
+ self
168
284
  end
169
285
 
170
286
  # Return a string in JSON format. Accepts the following
@@ -82,9 +82,21 @@ module Sequel
82
82
  def self.register_format(format, serializer, deserializer)
83
83
  REGISTERED_FORMATS[format] = [serializer, deserializer]
84
84
  end
85
- register_format(:marshal, lambda{|v| [Marshal.dump(v)].pack('m')}, lambda{|v| Marshal.load(v.unpack('m')[0]) rescue Marshal.load(v)})
85
+ register_format(:marshal, lambda{|v| [Marshal.dump(v)].pack('m')},
86
+ lambda do |v|
87
+ begin
88
+ Marshal.load(v.unpack('m')[0])
89
+ rescue => e
90
+ begin
91
+ # Backwards compatibility for unpacked marshal output.
92
+ Marshal.load(v)
93
+ rescue
94
+ raise e
95
+ end
96
+ end
97
+ end)
86
98
  register_format(:yaml, lambda{|v| v.to_yaml}, lambda{|v| YAML.load(v)})
87
- register_format(:json, lambda{|v| v.to_json}, lambda{|v| JSON.parse(v)})
99
+ register_format(:json, lambda{|v| v.to_json}, lambda{|v| Sequel.parse_json(v)})
88
100
 
89
101
  module ClassMethods
90
102
  # A hash with column name symbols and callable values, with the value