sequel 5.24.0 → 5.29.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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +58 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/doc/cheat_sheet.rdoc +1 -0
  6. data/doc/postgresql.rdoc +2 -2
  7. data/doc/release_notes/5.25.0.txt +32 -0
  8. data/doc/release_notes/5.26.0.txt +35 -0
  9. data/doc/release_notes/5.27.0.txt +21 -0
  10. data/doc/release_notes/5.28.0.txt +16 -0
  11. data/doc/release_notes/5.29.0.txt +22 -0
  12. data/doc/testing.rdoc +11 -6
  13. data/lib/sequel/adapters/jdbc/postgresql.rb +6 -0
  14. data/lib/sequel/adapters/postgres.rb +5 -1
  15. data/lib/sequel/adapters/shared/mssql.rb +4 -2
  16. data/lib/sequel/adapters/shared/mysql.rb +1 -1
  17. data/lib/sequel/adapters/shared/postgres.rb +15 -0
  18. data/lib/sequel/adapters/shared/sqlite.rb +7 -2
  19. data/lib/sequel/adapters/tinytds.rb +1 -1
  20. data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
  21. data/lib/sequel/database/schema_generator.rb +1 -1
  22. data/lib/sequel/database/transactions.rb +3 -3
  23. data/lib/sequel/dataset/features.rb +6 -0
  24. data/lib/sequel/dataset/misc.rb +2 -2
  25. data/lib/sequel/dataset/query.rb +15 -2
  26. data/lib/sequel/dataset/sql.rb +17 -4
  27. data/lib/sequel/extensions/any_not_empty.rb +45 -0
  28. data/lib/sequel/extensions/exclude_or_null.rb +68 -0
  29. data/lib/sequel/extensions/pg_array_ops.rb +10 -6
  30. data/lib/sequel/extensions/pg_enum.rb +4 -1
  31. data/lib/sequel/extensions/pg_json.rb +1 -1
  32. data/lib/sequel/extensions/pg_json_ops.rb +124 -0
  33. data/lib/sequel/extensions/pg_range.rb +9 -0
  34. data/lib/sequel/extensions/sql_comments.rb +2 -2
  35. data/lib/sequel/model/base.rb +12 -5
  36. data/lib/sequel/plugins/association_multi_add_remove.rb +83 -0
  37. data/lib/sequel/plugins/caching.rb +3 -0
  38. data/lib/sequel/plugins/csv_serializer.rb +26 -9
  39. data/lib/sequel/plugins/dirty.rb +3 -9
  40. data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
  41. data/lib/sequel/plugins/json_serializer.rb +15 -4
  42. data/lib/sequel/plugins/nested_attributes.rb +7 -0
  43. data/lib/sequel/plugins/sharding.rb +11 -5
  44. data/lib/sequel/plugins/throw_failures.rb +1 -1
  45. data/lib/sequel/plugins/typecast_on_load.rb +3 -2
  46. data/lib/sequel/sql.rb +4 -1
  47. data/lib/sequel/version.rb +1 -1
  48. data/spec/adapters/postgres_spec.rb +82 -17
  49. data/spec/adapters/sqlite_spec.rb +1 -1
  50. data/spec/bin_spec.rb +1 -1
  51. data/spec/core/database_spec.rb +1 -1
  52. data/spec/core/dataset_spec.rb +0 -3
  53. data/spec/core/expression_filters_spec.rb +26 -7
  54. data/spec/core/spec_helper.rb +1 -1
  55. data/spec/core_extensions_spec.rb +1 -1
  56. data/spec/extensions/any_not_empty_spec.rb +23 -0
  57. data/spec/extensions/association_multi_add_remove_spec.rb +1041 -0
  58. data/spec/extensions/caller_logging_spec.rb +1 -1
  59. data/spec/extensions/dirty_spec.rb +33 -0
  60. data/spec/extensions/empty_failure_backtraces_spec.rb +60 -0
  61. data/spec/extensions/exclude_or_null_spec.rb +15 -0
  62. data/spec/extensions/json_serializer_spec.rb +10 -0
  63. data/spec/extensions/named_timezones_spec.rb +5 -5
  64. data/spec/extensions/nested_attributes_spec.rb +48 -0
  65. data/spec/extensions/pg_array_ops_spec.rb +3 -3
  66. data/spec/extensions/pg_json_ops_spec.rb +67 -0
  67. data/spec/extensions/pg_range_spec.rb +35 -21
  68. data/spec/extensions/sharding_spec.rb +8 -0
  69. data/spec/extensions/spec_helper.rb +1 -1
  70. data/spec/guards_helper.rb +1 -1
  71. data/spec/integration/associations_test.rb +1 -1
  72. data/spec/integration/dataset_test.rb +57 -17
  73. data/spec/integration/plugin_test.rb +1 -1
  74. data/spec/integration/schema_test.rb +9 -0
  75. data/spec/integration/spec_helper.rb +7 -1
  76. data/spec/model/plugins_spec.rb +2 -2
  77. data/spec/model/spec_helper.rb +1 -1
  78. data/spec/sequel_warning.rb +1 -0
  79. metadata +35 -3
@@ -42,7 +42,7 @@ describe "caller_logging extension" do
42
42
 
43
43
  it "should not log caller information if all callers lines are filtered" do
44
44
  @db.caller_logging_ignore = /./
45
- exec_sql("SELECT * FROM items"); line = __LINE__
45
+ exec_sql("SELECT * FROM items")
46
46
  @log_stream.rewind
47
47
  lines = @log_stream.read.split("\n")
48
48
  lines.length.must_equal 1
@@ -162,6 +162,39 @@ describe "Sequel::Plugins::Dirty" do
162
162
  @o.save
163
163
  @o.column_changes.must_equal({})
164
164
  end
165
+
166
+ it "should work with the typecast_on_load plugin" do
167
+ @c.instance_variable_set(:@db_schema, :initial=>{:type=>:integer})
168
+ @c.plugin :typecast_on_load, :initial
169
+
170
+ @o = @c.call(:initial=>'1')
171
+ @o.column_changes.must_equal({})
172
+ @o.save
173
+ @o.previous_changes.must_equal({})
174
+ end
175
+
176
+ it "should have column_changes work with the typecast_on_load in after hooks" do
177
+ @c.instance_variable_set(:@db_schema, :initial=>{:type=>:integer})
178
+ @c.plugin :typecast_on_load, :initial
179
+
180
+ @o = @c.new
181
+ @o.initial = 1
182
+ @o.column_changes.must_equal({:initial=>[nil, 1]})
183
+ column_changes_in_after_save = nil
184
+ @o.define_singleton_method(:after_save) do
185
+ column_changes_in_after_save = column_changes
186
+ super()
187
+ end
188
+ @db.fetch = {:initial=>1}
189
+ @o.save
190
+ column_changes_in_after_save.must_equal({:initial=>[nil, 1]})
191
+
192
+ @o.initial = 2
193
+ @o.column_changes.must_equal({:initial=>[1, 2]})
194
+ @o.save
195
+ column_changes_in_after_save.must_equal({:initial=>[1, 2]})
196
+ @o.previous_changes.must_equal({:initial=>[1, 2]})
197
+ end
165
198
  end
166
199
 
167
200
  describe "with existing instance" do
@@ -0,0 +1,60 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe "empty_failure_backtraces plugin" do
4
+ before do
5
+ @c = Class.new(Sequel::Model(:items)) do
6
+ plugin :empty_failure_backtraces
7
+ columns :x
8
+ set_primary_key :x
9
+ unrestrict_primary_key
10
+ def before_create
11
+ super
12
+ cancel_action 'bc' if x == 2
13
+ end
14
+ def before_destroy
15
+ super
16
+ cancel_action 'bd' if x == 2
17
+ end
18
+ def validate
19
+ super
20
+ errors.add(:x, "3") if x == 3
21
+ end
22
+ end
23
+ DB.reset
24
+ end
25
+
26
+ it "should work normally if no exceptions are thrown/raised" do
27
+ o = @c.create(:x=>1)
28
+ o.must_be_kind_of @c
29
+ o.valid?.must_equal true
30
+ o.destroy.must_equal o
31
+ end
32
+
33
+ it "should work normally when not rescuing exceptions internally when calling save" do
34
+ @c.new.set(:x => 2).save(:raise_on_failure=>false).must_be_nil
35
+ @c.raise_on_save_failure = false
36
+ @c.create(:x => 2).must_be_nil
37
+ @c.load(:x => 2).destroy(:raise_on_failure=>false).must_be_nil
38
+ end
39
+
40
+ it "should work normally when not rescuing exceptions internally when calling valid?" do
41
+ @c.send(:define_method, :before_validation){cancel_action "bv"}
42
+ @c.new(:x => 2).valid?.must_equal false
43
+ end
44
+
45
+ it "should raise exceptions with empty backtraces" do
46
+ begin
47
+ @c.create(:x => 2)
48
+ rescue Sequel::HookFailed => e
49
+ e.backtrace.must_be_empty
50
+ 1
51
+ end.must_equal 1
52
+
53
+ begin
54
+ @c.create(:x => 3)
55
+ rescue Sequel::ValidationFailed => e
56
+ e.backtrace.must_be_empty
57
+ 1
58
+ end.must_equal 1
59
+ end
60
+ end
@@ -0,0 +1,15 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe "exclude_or_null extension" do
4
+ before do
5
+ @ds = Sequel.mock[:t].extension(:exclude_or_null)
6
+ end
7
+
8
+ it "should add condition where a is false or NULL" do
9
+ @ds.exclude_or_null(:a).sql.must_equal "SELECT * FROM t WHERE NOT coalesce(a, 'f')"
10
+ end
11
+
12
+ it "should not effect normal exclude" do
13
+ @ds.exclude(:a).sql.must_equal "SELECT * FROM t WHERE NOT a"
14
+ end
15
+ end
@@ -187,6 +187,16 @@ describe "Sequel::Plugins::JsonSerializer" do
187
187
  Album.array_from_json(Album.dataset.to_json(:only=>:name)).must_equal [Album.load(:name=>@album.name)]
188
188
  end
189
189
 
190
+ it "should support setting json_serializer_opts for datasets" do
191
+ Album.dataset = Album.dataset.with_fetch(:id=>1, :name=>'RF', :artist_id=>2)
192
+ Album.array_from_json(Album.dataset.json_serializer_opts(:only=>:name).to_json).must_equal [Album.load(:name=>@album.name)]
193
+ Album.plugin :json_serializer, :only=>:id
194
+ Album.array_from_json(Album.dataset.json_serializer_opts(:only=>:name).to_json).must_equal [Album.load(:name=>@album.name)]
195
+ Album.array_from_json(Album.dataset.json_serializer_opts(:only=>:name).to_json(:only=>:artist_id)).must_equal [Album.load(:artist_id=>2)]
196
+ json = Album.dataset.json_serializer_opts(:only=>:name, :root=>true).to_json(:only=>:artist_id)
197
+ Album.array_from_json(JSON.parse(json)['albums'].to_json).must_equal [Album.load(:artist_id=>2)]
198
+ end
199
+
190
200
  it "should have dataset to_json method work with eager_graph datasets" do
191
201
  ds = Album.dataset.eager_graph(:artist).with_fetch(:id=>1, :name=>'RF', :artist_id=>2, :artist_id_0=>2, :artist_name=>'YM')
192
202
  Sequel.parse_json(ds.to_json(:only=>:name, :include=>{:artist=>{:only=>:name}})).must_equal [{"name"=>"RF", "artist"=>{"name"=>"YM"}}]
@@ -158,12 +158,12 @@ describe "Sequel named_timezones extension with Time class" do
158
158
  dt = Sequel.database_to_application_timestamp('2009-06-01 06:20:30-0400')
159
159
  dt.must_be_instance_of Time
160
160
  dt.must_equal Time.new(2009,6,1,3,20,30,-25200)
161
- dt.utc_offset.must_equal -25200
161
+ dt.utc_offset.must_equal(-25200)
162
162
 
163
163
  dt = Sequel.database_to_application_timestamp('2009-06-01 10:20:30+0000')
164
164
  dt.must_be_instance_of Time
165
165
  dt.must_equal Time.new(2009,6,1,3,20,30,-25200)
166
- dt.utc_offset.must_equal -25200
166
+ dt.utc_offset.must_equal(-25200)
167
167
  end
168
168
 
169
169
  it "should raise an error for ambiguous timezones by default" do
@@ -175,19 +175,19 @@ describe "Sequel named_timezones extension with Time class" do
175
175
  Sequel.database_to_application_timestamp('2004-10-31T01:30:00').must_equal Time.new(2004, 10, 30, 22, 30, 0, -25200)
176
176
  dt = Sequel.database_to_application_timestamp('2004-10-31T01:30:00')
177
177
  dt.must_equal Time.new(2004, 10, 30, 22, 30, 0, -25200)
178
- dt.utc_offset.must_equal -25200
178
+ dt.utc_offset.must_equal(-25200)
179
179
  end
180
180
 
181
181
  it "should assume datetimes coming out of the database that don't have an offset as coming from database_timezone" do
182
182
  dt = Sequel.database_to_application_timestamp('2009-06-01 06:20:30')
183
183
  dt.must_be_instance_of Time
184
184
  dt.must_equal Time.new(2009,6,1,3,20,30, -25200)
185
- dt.utc_offset.must_equal -25200
185
+ dt.utc_offset.must_equal(-25200)
186
186
 
187
187
  dt = Sequel.database_to_application_timestamp('2009-06-01 10:20:30')
188
188
  dt.must_be_instance_of Time
189
189
  dt.must_equal Time.new(2009,6,1,7,20,30, -25200)
190
- dt.utc_offset.must_equal -25200
190
+ dt.utc_offset.must_equal(-25200)
191
191
  end
192
192
 
193
193
  it "should work with the thread_local_timezones extension" do
@@ -492,6 +492,54 @@ describe "NestedAttributes plugin" do
492
492
  @db.sqls.must_equal ["UPDATE artists SET name = 'Ar' WHERE (id = 10)"]
493
493
  end
494
494
 
495
+ it "should raise a NoExistingObject error if object to be updated no longer exists, if the :require_modification=>true option is used" do
496
+ @Artist.nested_attributes :albums, :require_modification=>true, :destroy=>true
497
+ al = @Album.load(:id=>10, :name=>'Al')
498
+ ar = @Artist.load(:id=>20, :name=>'Ar')
499
+ ar.associations[:albums] = [al]
500
+ ar.set(:albums_attributes=>[{:id=>10, :name=>'L'}])
501
+ @db.sqls.must_equal []
502
+ @db.numrows = [1, 0]
503
+ proc{ar.save}.must_raise Sequel::NoExistingObject
504
+ @db.sqls.must_equal ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "UPDATE albums SET name = 'L' WHERE (id = 10)"]
505
+ end
506
+
507
+ it "should not raise an Error if object to be updated no longer exists, if the :require_modification=>false option is used" do
508
+ @Artist.nested_attributes :albums, :require_modification=>false, :destroy=>true
509
+ al = @Album.load(:id=>10, :name=>'Al')
510
+ ar = @Artist.load(:id=>20, :name=>'Ar')
511
+ ar.associations[:albums] = [al]
512
+ ar.set(:albums_attributes=>[{:id=>10, :name=>'L'}])
513
+ @db.sqls.must_equal []
514
+ @db.numrows = [1, 0]
515
+ ar.save
516
+ @db.sqls.must_equal ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "UPDATE albums SET name = 'L' WHERE (id = 10)"]
517
+ end
518
+
519
+ it "should raise a NoExistingObject error if object to be deleted no longer exists, if the :require_modification=>true option is used" do
520
+ @Artist.nested_attributes :albums, :require_modification=>true, :destroy=>true
521
+ al = @Album.load(:id=>10, :name=>'Al')
522
+ ar = @Artist.load(:id=>20, :name=>'Ar')
523
+ ar.associations[:albums] = [al]
524
+ ar.set(:albums_attributes=>[{:id=>10, :_delete=>'t'}])
525
+ @db.sqls.must_equal []
526
+ @db.numrows = [1, 0]
527
+ proc{ar.save}.must_raise Sequel::NoExistingObject
528
+ @db.sqls.must_equal ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "DELETE FROM albums WHERE (id = 10)"]
529
+ end
530
+
531
+ it "should not raise an Error if object to be deleted no longer exists, if the :require_modification=>false option is used" do
532
+ @Artist.nested_attributes :albums, :require_modification=>false, :destroy=>true
533
+ al = @Album.load(:id=>10, :name=>'Al')
534
+ ar = @Artist.load(:id=>20, :name=>'Ar')
535
+ ar.associations[:albums] = [al]
536
+ ar.set(:albums_attributes=>[{:id=>10, :_delete=>'t'}])
537
+ @db.sqls.must_equal []
538
+ @db.numrows = [1, 0]
539
+ ar.save
540
+ @db.sqls.must_equal ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "DELETE FROM albums WHERE (id = 10)"]
541
+ end
542
+
495
543
  it "should not attempt to validate nested attributes twice for one_to_many associations when creating them" do
496
544
  @Artist.nested_attributes :albums
497
545
  validated = []
@@ -83,9 +83,9 @@ describe "Sequel::Postgres::ArrayOp" do
83
83
  end
84
84
 
85
85
  it "#to_string/join should use the array_to_string function" do
86
- @db.literal(@a.to_string).must_equal "array_to_string(a, '', NULL)"
87
- @db.literal(@a.join).must_equal "array_to_string(a, '', NULL)"
88
- @db.literal(@a.join(':')).must_equal "array_to_string(a, ':', NULL)"
86
+ @db.literal(@a.to_string).must_equal "array_to_string(a, '')"
87
+ @db.literal(@a.join).must_equal "array_to_string(a, '')"
88
+ @db.literal(@a.join(':')).must_equal "array_to_string(a, ':')"
89
89
  @db.literal(@a.join(':', '*')).must_equal "array_to_string(a, ':', '*')"
90
90
  end
91
91
 
@@ -286,4 +286,71 @@ describe "Sequel::Postgres::JSONOp" do
286
286
  it "should allow transforming JSONBHash instances into ArrayOp instances" do
287
287
  @db.literal(Sequel.pg_jsonb('a'=>1).op['a']).must_equal "('{\"a\":1}'::jsonb -> 'a')"
288
288
  end
289
+
290
+ it "#path_exists should use the @? operator" do
291
+ @l[@jb.path_exists('$')].must_equal "(j @? '$')"
292
+ end
293
+
294
+ it "#path_exists result should be a boolean expression" do
295
+ @jb.path_exists('$').must_be_kind_of Sequel::SQL::BooleanExpression
296
+ end
297
+
298
+ it "#path_match should use the @@ operator" do
299
+ @l[@jb.path_match('$')].must_equal "(j @@ '$')"
300
+ end
301
+
302
+ it "#path_match result should be a boolean expression" do
303
+ @jb.path_match('$').must_be_kind_of Sequel::SQL::BooleanExpression
304
+ end
305
+
306
+ it "#path_exists! should use the jsonb_path_exists function" do
307
+ @l[@jb.path_exists!('$')].must_equal "jsonb_path_exists(j, '$')"
308
+ @l[@jb.path_exists!('$', '{"x":2}')].must_equal "jsonb_path_exists(j, '$', '{\"x\":2}')"
309
+ @l[@jb.path_exists!('$', x: 2)].must_equal "jsonb_path_exists(j, '$', '{\"x\":2}')"
310
+ @l[@jb.path_exists!('$', {x: 2}, true)].must_equal "jsonb_path_exists(j, '$', '{\"x\":2}', true)"
311
+ end
312
+
313
+ it "#path_exists! result should be a boolean expression" do
314
+ @jb.path_exists!('$').must_be_kind_of Sequel::SQL::BooleanExpression
315
+ end
316
+
317
+ it "#path_match! should use the jsonb_path_match function" do
318
+ @l[@jb.path_match!('$')].must_equal "jsonb_path_match(j, '$')"
319
+ @l[@jb.path_match!('$', '{"x":2}')].must_equal "jsonb_path_match(j, '$', '{\"x\":2}')"
320
+ @l[@jb.path_match!('$', x: 2)].must_equal "jsonb_path_match(j, '$', '{\"x\":2}')"
321
+ @l[@jb.path_match!('$', {x: 2}, true)].must_equal "jsonb_path_match(j, '$', '{\"x\":2}', true)"
322
+ end
323
+
324
+ it "#path_match! result should be a boolean expression" do
325
+ @jb.path_match!('$').must_be_kind_of Sequel::SQL::BooleanExpression
326
+ end
327
+
328
+ it "#path_query should use the jsonb_path_query function" do
329
+ @l[@jb.path_query('$')].must_equal "jsonb_path_query(j, '$')"
330
+ @l[@jb.path_query('$', '{"x":2}')].must_equal "jsonb_path_query(j, '$', '{\"x\":2}')"
331
+ @l[@jb.path_query('$', x: 2)].must_equal "jsonb_path_query(j, '$', '{\"x\":2}')"
332
+ @l[@jb.path_query('$', {x: 2}, true)].must_equal "jsonb_path_query(j, '$', '{\"x\":2}', true)"
333
+ end
334
+
335
+ it "#path_query_array should use the jsonb_path_query_array function" do
336
+ @l[@jb.path_query_array('$')].must_equal "jsonb_path_query_array(j, '$')"
337
+ @l[@jb.path_query_array('$', '{"x":2}')].must_equal "jsonb_path_query_array(j, '$', '{\"x\":2}')"
338
+ @l[@jb.path_query_array('$', x: 2)].must_equal "jsonb_path_query_array(j, '$', '{\"x\":2}')"
339
+ @l[@jb.path_query_array('$', {x: 2}, true)].must_equal "jsonb_path_query_array(j, '$', '{\"x\":2}', true)"
340
+ end
341
+
342
+ it "#path_query_array result should be a JSONBOp" do
343
+ @l[@jb.path_query_array('$').path_query_array('$')].must_equal "jsonb_path_query_array(jsonb_path_query_array(j, '$'), '$')"
344
+ end
345
+
346
+ it "#path_query_first should use the jsonb_path_query_first function" do
347
+ @l[@jb.path_query_first('$')].must_equal "jsonb_path_query_first(j, '$')"
348
+ @l[@jb.path_query_first('$', '{"x":2}')].must_equal "jsonb_path_query_first(j, '$', '{\"x\":2}')"
349
+ @l[@jb.path_query_first('$', x: 2)].must_equal "jsonb_path_query_first(j, '$', '{\"x\":2}')"
350
+ @l[@jb.path_query_first('$', {x: 2}, true)].must_equal "jsonb_path_query_first(j, '$', '{\"x\":2}', true)"
351
+ end
352
+
353
+ it "#path_query_first result should be a JSONBOp" do
354
+ @l[@jb.path_query_first('$').path_query_first('$')].must_equal "jsonb_path_query_first(jsonb_path_query_first(j, '$'), '$')"
355
+ end
289
356
  end
@@ -52,13 +52,13 @@ describe "pg_range extension" do
52
52
  end
53
53
 
54
54
  it "should literalize endless Range instances to strings correctly" do
55
- @db.literal(eval('1..')).must_equal "'[1,]'"
56
- @db.literal(eval('1...')).must_equal "'[1,)'"
55
+ @db.literal(eval('(1..)')).must_equal "'[1,]'"
56
+ @db.literal(eval('(1...)')).must_equal "'[1,)'"
57
57
  end if endless_range_support
58
58
 
59
59
  it "should literalize startless Range instances to strings correctly" do
60
- @db.literal(eval('..1')).must_equal "'[,1]'"
61
- @db.literal(eval('...1')).must_equal "'[,1)'"
60
+ @db.literal(eval('(..1)')).must_equal "'[,1]'"
61
+ @db.literal(eval('(...1)')).must_equal "'[,1)'"
62
62
  end if startless_range_support
63
63
 
64
64
  it "should literalize startless, endless Range instances to strings correctly" do
@@ -90,13 +90,13 @@ describe "pg_range extension" do
90
90
  end
91
91
 
92
92
  it "should support using endless Range instances as bound variables" do
93
- @db.bound_variable_arg(eval('1..'), nil).must_equal "[1,]"
94
- @db.bound_variable_arg(eval('1...'), nil).must_equal "[1,)"
93
+ @db.bound_variable_arg(eval('(1..)'), nil).must_equal "[1,]"
94
+ @db.bound_variable_arg(eval('(1...)'), nil).must_equal "[1,)"
95
95
  end if endless_range_support
96
96
 
97
97
  it "should support using startless Range instances as bound variables" do
98
- @db.bound_variable_arg(eval('..1'), nil).must_equal "[,1]"
99
- @db.bound_variable_arg(eval('...1'), nil).must_equal "[,1)"
98
+ @db.bound_variable_arg(eval('(..1)'), nil).must_equal "[,1]"
99
+ @db.bound_variable_arg(eval('(...1)'), nil).must_equal "[,1)"
100
100
  end if startless_range_support
101
101
 
102
102
  it "should support using startless, endless Range instances as bound variables" do
@@ -113,7 +113,7 @@ describe "pg_range extension" do
113
113
  end
114
114
 
115
115
  it "should support using arrays of endless Range instances as bound variables" do
116
- @db.bound_variable_arg([eval('1..'), eval('2..')], nil).must_equal '{"[1,]","[2,]"}'
116
+ @db.bound_variable_arg([eval('(1..)'), eval('(2..)')], nil).must_equal '{"[1,]","[2,]"}'
117
117
  end if endless_range_support
118
118
 
119
119
  it "should support using PGRange instances as bound variables" do
@@ -136,6 +136,20 @@ describe "pg_range extension" do
136
136
  s[1][1][:ruby_default].must_equal Sequel::Postgres::PGRange.new(1, 5, :exclude_end=>true, :db_type=>'int4range')
137
137
  end
138
138
 
139
+ it "should work correctly in hashes" do
140
+ h = Hash.new(1)
141
+ h[@R.new(1, 2)] = 2
142
+ h[@R.new(nil, nil, :empty => true)] = 3
143
+ h[@R.new(1, 2)].must_equal 2
144
+ h[@R.new(1, 3)].must_equal 1
145
+ h[@R.new(2, 2)].must_equal 1
146
+ h[@R.new(1, 2, :exclude_begin => true)].must_equal 1
147
+ h[@R.new(1, 2, :exclude_end => true)].must_equal 1
148
+ h[@R.new(1, 2, :db_type => :int)].must_equal 1
149
+ h[@R.new(nil, nil, :empty => true)].must_equal 3
150
+ h[@R.new(nil, nil, :empty => true, :db_type => :int)].must_equal 1
151
+ end
152
+
139
153
  describe "database typecasting" do
140
154
  before do
141
155
  @o = @R.new(1, 2, :db_type=>'int4range')
@@ -456,21 +470,21 @@ describe "pg_range extension" do
456
470
  end
457
471
 
458
472
  it "should consider PGRanges equal with a endless Range they represent" do
459
- @R.new(1, nil).must_be :==, eval('1..')
460
- @R.new(1, nil, :exclude_end=>true).must_be :==, eval('1...')
461
- @R.new(1, nil).wont_be :==, eval('1...')
462
- @R.new(1, nil, :exclude_end=>true).wont_be :==, eval('1..')
463
- @R.new(1, nil).wont_be :==, eval('2..')
464
- @R.new(1, nil, :exclude_end=>true).wont_be :==, eval('2...')
473
+ @R.new(1, nil).must_be :==, eval('(1..)')
474
+ @R.new(1, nil, :exclude_end=>true).must_be :==, eval('(1...)')
475
+ @R.new(1, nil).wont_be :==, eval('(1...)')
476
+ @R.new(1, nil, :exclude_end=>true).wont_be :==, eval('(1..)')
477
+ @R.new(1, nil).wont_be :==, eval('(2..)')
478
+ @R.new(1, nil, :exclude_end=>true).wont_be :==, eval('(2...)')
465
479
  end if endless_range_support
466
480
 
467
481
  it "should consider PGRanges equal with a startless Range they represent" do
468
- @R.new(nil, 1).must_be :==, eval('..1')
469
- @R.new(nil, 1, :exclude_end=>true).must_be :==, eval('...1')
470
- @R.new(nil, 1).wont_be :==, eval('...1')
471
- @R.new(nil, 1, :exclude_end=>true).wont_be :==, eval('..1')
472
- @R.new(nil, 1).wont_be :==, eval('..2')
473
- @R.new(nil, 1, :exclude_end=>true).wont_be :==, eval('...2')
482
+ @R.new(nil, 1).must_be :==, eval('(..1)')
483
+ @R.new(nil, 1, :exclude_end=>true).must_be :==, eval('(...1)')
484
+ @R.new(nil, 1).wont_be :==, eval('(...1)')
485
+ @R.new(nil, 1, :exclude_end=>true).wont_be :==, eval('(..1)')
486
+ @R.new(nil, 1).wont_be :==, eval('(..2)')
487
+ @R.new(nil, 1, :exclude_end=>true).wont_be :==, eval('(...2)')
474
488
  end if startless_range_support
475
489
 
476
490
  it "should consider PGRanges equal with a startless, endless Range they represent" do
@@ -186,4 +186,12 @@ describe "sharding plugin" do
186
186
  ["UPDATE albums SET artist_id = 2, name = 'RF' WHERE (id = 1) -- s1", "UPDATE albums SET name = 'RF', artist_id = 2 WHERE (id = 1) -- s1"].must_include(sqls.slice!(2))
187
187
  sqls.must_equal ["SELECT * FROM albums LIMIT 1 -- s2", "BEGIN -- s1", "COMMIT -- s1"]
188
188
  end
189
+
190
+ it "should have objects retrieved from a specific shard using with_server from server_block extension" do
191
+ album = @db.extension(:server_block).with_server(:s1) do
192
+ @Album.first
193
+ end
194
+ album.update(:name=>'MO')
195
+ @db.sqls.must_equal ["SELECT * FROM albums LIMIT 1 -- s1", "UPDATE albums SET name = 'MO' WHERE (id = 1) -- s1"]
196
+ end
189
197
  end
@@ -7,7 +7,7 @@ end
7
7
 
8
8
  ENV['MT_NO_PLUGINS'] = '1' # Work around stupid autoloading of plugins
9
9
  gem 'minitest'
10
- require 'minitest/autorun'
10
+ require 'minitest/global_expectations/autorun'
11
11
  require 'minitest/hooks/default'
12
12
  require 'minitest/shared_description'
13
13
 
@@ -1,6 +1,6 @@
1
1
  ENV['MT_NO_PLUGINS'] = '1' # Work around stupid autoloading of plugins
2
2
  gem 'minitest'
3
- require 'minitest/autorun'
3
+ require 'minitest/global_expectations/autorun'
4
4
  require 'minitest/hooks/default'
5
5
  require 'minitest/shared_description'
6
6