sequel 3.44.0 → 3.45.0

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.
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