sequel 5.24.0 → 5.29.0

Sign up to get free protection for your applications and to get access to all the features.
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