sequel 3.10.0 → 3.11.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 (87) hide show
  1. data/CHANGELOG +68 -0
  2. data/COPYING +1 -1
  3. data/README.rdoc +87 -27
  4. data/bin/sequel +2 -4
  5. data/doc/association_basics.rdoc +1383 -0
  6. data/doc/dataset_basics.rdoc +106 -0
  7. data/doc/opening_databases.rdoc +45 -16
  8. data/doc/querying.rdoc +210 -0
  9. data/doc/release_notes/3.11.0.txt +254 -0
  10. data/doc/virtual_rows.rdoc +217 -31
  11. data/lib/sequel/adapters/ado.rb +28 -12
  12. data/lib/sequel/adapters/ado/mssql.rb +33 -1
  13. data/lib/sequel/adapters/amalgalite.rb +13 -8
  14. data/lib/sequel/adapters/db2.rb +1 -2
  15. data/lib/sequel/adapters/dbi.rb +7 -4
  16. data/lib/sequel/adapters/do.rb +14 -15
  17. data/lib/sequel/adapters/do/postgres.rb +4 -5
  18. data/lib/sequel/adapters/do/sqlite.rb +9 -0
  19. data/lib/sequel/adapters/firebird.rb +5 -10
  20. data/lib/sequel/adapters/informix.rb +2 -4
  21. data/lib/sequel/adapters/jdbc.rb +111 -49
  22. data/lib/sequel/adapters/jdbc/mssql.rb +1 -2
  23. data/lib/sequel/adapters/jdbc/mysql.rb +11 -0
  24. data/lib/sequel/adapters/jdbc/oracle.rb +4 -7
  25. data/lib/sequel/adapters/jdbc/postgresql.rb +8 -1
  26. data/lib/sequel/adapters/jdbc/sqlite.rb +12 -0
  27. data/lib/sequel/adapters/mysql.rb +14 -5
  28. data/lib/sequel/adapters/odbc.rb +2 -4
  29. data/lib/sequel/adapters/odbc/mssql.rb +2 -4
  30. data/lib/sequel/adapters/openbase.rb +1 -2
  31. data/lib/sequel/adapters/oracle.rb +4 -8
  32. data/lib/sequel/adapters/postgres.rb +4 -11
  33. data/lib/sequel/adapters/shared/mssql.rb +22 -9
  34. data/lib/sequel/adapters/shared/mysql.rb +33 -30
  35. data/lib/sequel/adapters/shared/oracle.rb +0 -5
  36. data/lib/sequel/adapters/shared/postgres.rb +13 -11
  37. data/lib/sequel/adapters/shared/sqlite.rb +56 -10
  38. data/lib/sequel/adapters/sqlite.rb +16 -9
  39. data/lib/sequel/connection_pool.rb +6 -1
  40. data/lib/sequel/connection_pool/single.rb +1 -0
  41. data/lib/sequel/core.rb +6 -1
  42. data/lib/sequel/database.rb +52 -23
  43. data/lib/sequel/database/schema_generator.rb +6 -0
  44. data/lib/sequel/database/schema_methods.rb +5 -5
  45. data/lib/sequel/database/schema_sql.rb +1 -1
  46. data/lib/sequel/dataset.rb +4 -190
  47. data/lib/sequel/dataset/actions.rb +323 -1
  48. data/lib/sequel/dataset/features.rb +18 -2
  49. data/lib/sequel/dataset/graph.rb +7 -0
  50. data/lib/sequel/dataset/misc.rb +119 -0
  51. data/lib/sequel/dataset/mutation.rb +64 -0
  52. data/lib/sequel/dataset/prepared_statements.rb +6 -0
  53. data/lib/sequel/dataset/query.rb +272 -6
  54. data/lib/sequel/dataset/sql.rb +186 -394
  55. data/lib/sequel/model.rb +4 -2
  56. data/lib/sequel/model/associations.rb +31 -14
  57. data/lib/sequel/model/base.rb +32 -13
  58. data/lib/sequel/model/exceptions.rb +8 -4
  59. data/lib/sequel/model/plugins.rb +3 -13
  60. data/lib/sequel/plugins/active_model.rb +26 -7
  61. data/lib/sequel/plugins/instance_filters.rb +98 -0
  62. data/lib/sequel/plugins/many_through_many.rb +1 -1
  63. data/lib/sequel/plugins/optimistic_locking.rb +25 -9
  64. data/lib/sequel/version.rb +1 -1
  65. data/spec/adapters/mssql_spec.rb +26 -0
  66. data/spec/adapters/mysql_spec.rb +33 -4
  67. data/spec/adapters/postgres_spec.rb +24 -1
  68. data/spec/adapters/spec_helper.rb +6 -0
  69. data/spec/adapters/sqlite_spec.rb +28 -0
  70. data/spec/core/connection_pool_spec.rb +17 -5
  71. data/spec/core/database_spec.rb +101 -1
  72. data/spec/core/dataset_spec.rb +42 -4
  73. data/spec/core/schema_spec.rb +13 -0
  74. data/spec/extensions/active_model_spec.rb +34 -11
  75. data/spec/extensions/caching_spec.rb +2 -0
  76. data/spec/extensions/instance_filters_spec.rb +55 -0
  77. data/spec/extensions/spec_helper.rb +2 -0
  78. data/spec/integration/dataset_test.rb +12 -1
  79. data/spec/integration/model_test.rb +12 -0
  80. data/spec/integration/plugin_test.rb +61 -1
  81. data/spec/integration/schema_test.rb +14 -3
  82. data/spec/model/base_spec.rb +27 -0
  83. data/spec/model/plugins_spec.rb +0 -22
  84. data/spec/model/record_spec.rb +32 -1
  85. data/spec/model/spec_helper.rb +2 -0
  86. metadata +14 -3
  87. data/lib/sequel/dataset/convenience.rb +0 -326
@@ -299,6 +299,15 @@ context "DB#create_table" do
299
299
  @db.sqls.should == ["CREATE TABLE cats (name text, UNIQUE (name))"]
300
300
  end
301
301
 
302
+ specify "should not raise on index error for unsupported index definitions if ignore_index_errors is used" do
303
+ proc {
304
+ @db.create_table(:cats, :ignore_index_errors=>true) do
305
+ text :name
306
+ full_text_index :name
307
+ end
308
+ }.should_not raise_error
309
+ end
310
+
302
311
  specify "should raise on full-text index definitions" do
303
312
  proc {
304
313
  @db.create_table(:cats) do
@@ -812,8 +821,12 @@ context "Schema Parser" do
812
821
  @db.schema(:float).first.last[:type].should == :float
813
822
  @db.schema(:double).first.last[:type].should == :float
814
823
  @db.schema(:"double precision").first.last[:type].should == :float
824
+ @db.schema(:number).first.last[:type].should == :decimal
815
825
  @db.schema(:numeric).first.last[:type].should == :decimal
816
826
  @db.schema(:decimal).first.last[:type].should == :decimal
827
+ @db.schema(:"number(10,0)").first.last[:type].should == :integer
828
+ @db.schema(:"numeric(10, 10)").first.last[:type].should == :decimal
829
+ @db.schema(:"decimal(10,1)").first.last[:type].should == :decimal
817
830
  @db.schema(:money).first.last[:type].should == :decimal
818
831
  @db.schema(:bytea).first.last[:type].should == :blob
819
832
  @db.schema(:blob).first.last[:type].should == :blob
@@ -8,15 +8,18 @@ describe "ActiveModel plugin" do
8
8
  s = f.read
9
9
  else
10
10
  begin
11
+ require 'rubygems'
11
12
  require 'active_model'
12
13
  rescue LoadError
13
- puts "0 failures, 0 errors"
14
+ puts "0 failures, 0 errors, skipping tests"
14
15
  else
15
16
  require 'test/unit'
16
17
  require "test/unit/ui/console/testrunner"
17
18
  class AMLintTest < Test::Unit::TestCase
18
19
  def setup
19
20
  @c = Class.new(Sequel::Model) do
21
+ set_primary_key :id
22
+ columns :id, :id2
20
23
  def delete; end
21
24
  end
22
25
  @c.plugin :active_model
@@ -25,22 +28,42 @@ describe "ActiveModel plugin" do
25
28
  end
26
29
  include ActiveModel::Lint::Tests
27
30
 
28
- def test_to_model
31
+ # Should return self, not a proxy object
32
+ def test__to_model
29
33
  assert_equal @m.to_model.object_id.should, @m.object_id
30
34
  end
31
-
32
- def test_new_record
33
- assert_equal true, @m.new_record?
34
- assert_equal false, @o.new_record?
35
+
36
+ def test__to_key
37
+ assert_equal nil, @m.to_key
38
+ @o.id = 1
39
+ assert_equal [1], @o.to_key
40
+ @c.set_primary_key [:id2, :id]
41
+ @o.id2 = 2
42
+ assert_equal [2, 1], @o.to_key
43
+ @o.destroy
44
+ assert_equal nil, @o.to_key
45
+ end
46
+
47
+ def test__to_param
48
+ assert_equal nil, @m.to_param
49
+ @o.id = 1
50
+ assert_equal '1', @o.to_param
51
+ @c.set_primary_key [:id2, :id]
52
+ @o.id2 = 2
53
+ assert_equal '2-1', @o.to_param
54
+ @o.meta_def(:to_param_joiner){'|'}
55
+ assert_equal '2|1', @o.to_param
56
+ @o.destroy
57
+ assert_equal nil, @o.to_param
35
58
  end
36
59
 
37
- def test_destroyed
38
- assert_equal false, @m.destroyed?
39
- assert_equal false, @o.destroyed?
60
+ def test__persisted?
61
+ assert_equal false, @m.persisted?
62
+ assert_equal true, @o.persisted?
40
63
  @m.destroy
41
64
  @o.destroy
42
- assert_equal true, @m.destroyed?
43
- assert_equal true, @o.destroyed?
65
+ assert_equal false, @m.persisted?
66
+ assert_equal false, @o.persisted?
44
67
  end
45
68
  end
46
69
  Test::Unit::UI::Console::TestRunner.run(AMLintTest)
@@ -57,10 +57,12 @@ describe Sequel::Model, "caching" do
57
57
  def update(values)
58
58
  $sqls << update_sql(values)
59
59
  $cache_dataset_row.merge!(values)
60
+ 1
60
61
  end
61
62
 
62
63
  def delete
63
64
  $sqls << delete_sql
65
+ 1
64
66
  end
65
67
  })
66
68
 
@@ -0,0 +1,55 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ describe "instance_filters plugin" do
4
+ before do
5
+ @c = Class.new(Sequel::Model(:people)) do
6
+ end
7
+ @sql = sql = ''
8
+ @v = v = [1]
9
+ @c.dataset.quote_identifiers = false
10
+ @c.dataset.meta_def(:update) do |opts|
11
+ sql.replace(update_sql(opts))
12
+ return v.first
13
+ end
14
+ @c.dataset.meta_def(:delete) do
15
+ sql.replace(delete_sql)
16
+ return v.first
17
+ end
18
+ @c.columns :id, :name, :num
19
+ @c.plugin :instance_filters
20
+ @p = @c.load(:id=>1, :name=>'John', :num=>1)
21
+ end
22
+
23
+ specify "should raise an error when updating a stale record" do
24
+ @p.update(:name=>'Bob')
25
+ @sql.should == "UPDATE people SET name = 'Bob' WHERE (id = 1)"
26
+ @p.instance_filter(:name=>'Jim')
27
+ @v.replace([0])
28
+ proc{@p.update(:name=>'Joe')}.should raise_error(Sequel::Plugins::InstanceFilters::Error)
29
+ @sql.should == "UPDATE people SET name = 'Joe' WHERE ((id = 1) AND (name = 'Jim'))"
30
+ end
31
+
32
+ specify "should raise an error when destroying a stale record" do
33
+ @p.destroy
34
+ @sql.should == "DELETE FROM people WHERE (id = 1)"
35
+ @p.instance_filter(:name=>'Jim')
36
+ @v.replace([0])
37
+ proc{@p.destroy}.should raise_error(Sequel::Plugins::InstanceFilters::Error)
38
+ @sql.should == "DELETE FROM people WHERE ((id = 1) AND (name = 'Jim'))"
39
+ end
40
+
41
+ specify "should apply all instance filters" do
42
+ @p.instance_filter(:name=>'Jim')
43
+ @p.instance_filter{num > 2}
44
+ @p.update(:name=>'Bob')
45
+ @sql.should == "UPDATE people SET name = 'Bob' WHERE ((id = 1) AND (name = 'Jim') AND (num > 2))"
46
+ end
47
+
48
+ specify "should drop instance filters after updating" do
49
+ @p.instance_filter(:name=>'Joe')
50
+ @p.update(:name=>'Joe')
51
+ @sql.should == "UPDATE people SET name = 'Joe' WHERE ((id = 1) AND (name = 'Joe'))"
52
+ @p.update(:name=>'Bob')
53
+ @sql.should == "UPDATE people SET name = 'Bob' WHERE (id = 1)"
54
+ end
55
+ end
@@ -18,10 +18,12 @@ class MockDataset < Sequel::Dataset
18
18
 
19
19
  def update(*args)
20
20
  @db.execute update_sql(*args)
21
+ 1
21
22
  end
22
23
 
23
24
  def delete(*args)
24
25
  @db.execute delete_sql(*args)
26
+ 1
25
27
  end
26
28
 
27
29
  def fetch_rows(sql)
@@ -38,11 +38,18 @@ describe "Simple Dataset operations" do
38
38
  @ds.filter(1=>1).delete.should == 1
39
39
  @ds.count.should == 0
40
40
  end
41
-
41
+
42
42
  specify "should update correctly" do
43
43
  @ds.update(:number=>:number+1).should == 1
44
44
  @ds.all.should == [{:id=>1, :number=>11}]
45
45
  end
46
+
47
+ cspecify "should have update return the number of matched rows", [:mysql, :mysql], [:do, :mysql], [:ado] do
48
+ @ds.update(:number=>:number).should == 1
49
+ @ds.filter(:id=>1).update(:number=>:number).should == 1
50
+ @ds.filter(:id=>2).update(:number=>:number).should == 0
51
+ @ds.all.should == [{:id=>1, :number=>10}]
52
+ end
46
53
 
47
54
  specify "should fetch all results correctly" do
48
55
  @ds.all.should == [{:id=>1, :number=>10}]
@@ -52,6 +59,10 @@ describe "Simple Dataset operations" do
52
59
  @ds.first.should == {:id=>1, :number=>10}
53
60
  end
54
61
 
62
+ specify "should have distinct work with limit" do
63
+ @ds.limit(1).distinct.all.should == [{:id=>1, :number=>10}]
64
+ end
65
+
55
66
  specify "should fetch correctly with a limit" do
56
67
  @ds.order(:id).limit(2).all.should == [{:id=>1, :number=>10}]
57
68
  @ds.insert(:number=>20)
@@ -75,6 +75,18 @@ describe "Sequel::Model basic support" do
75
75
  i.save(:num)
76
76
  Item.all.should == [Item.load(:id=>1, :name=>'K', :num=>2)]
77
77
  end
78
+
79
+ specify "#save should check that the only a single row is modified, unless require_modification is false" do
80
+ i = Item.create(:name=>'a')
81
+ i.require_modification = true
82
+ i.delete
83
+ proc{i.save}.should raise_error(Sequel::NoExistingObject)
84
+ proc{i.delete}.should raise_error(Sequel::NoExistingObject)
85
+
86
+ i.require_modification = false
87
+ i.save
88
+ i.delete
89
+ end
78
90
 
79
91
  specify ".to_hash should return a hash keyed on primary key if no argument provided" do
80
92
  i = Item.create(:name=>'J')
@@ -47,7 +47,7 @@ describe "Class Table Inheritance Plugin" do
47
47
  clear_sqls
48
48
  end
49
49
  after do
50
- @db.drop_table :executives, :managers, :staff, :employees
50
+ @db.drop_table :staff, :executives, :managers, :employees
51
51
  [:Executive, :Manager, :Staff, :Employee].each{|s| Object.send(:remove_const, s)}
52
52
  end
53
53
 
@@ -752,3 +752,63 @@ if INTEGRATION_DB.dataset.supports_cte?
752
752
  end
753
753
  end
754
754
  end
755
+
756
+ describe "Instance Filters plugin" do
757
+ before do
758
+ @db = INTEGRATION_DB
759
+ @db.create_table!(:items) do
760
+ primary_key :id
761
+ String :name
762
+ Integer :cost
763
+ Integer :number
764
+ end
765
+ class ::Item < Sequel::Model(@db)
766
+ plugin :instance_filters
767
+ end
768
+ @i = Item.create(:name=>'J', :number=>1, :cost=>2)
769
+ @i.instance_filter(:number=>1)
770
+ @i.set(:name=>'K')
771
+ end
772
+ after do
773
+ @db.drop_table(:items)
774
+ Object.send(:remove_const, :Item)
775
+ end
776
+
777
+ specify "should not raise an error if saving only updates one row" do
778
+ @i.save
779
+ @i.refresh.name.should == 'K'
780
+ end
781
+
782
+ specify "should raise error if saving doesn't update a row" do
783
+ @i.this.update(:number=>2)
784
+ proc{@i.save}.should raise_error(Sequel::Error)
785
+ end
786
+
787
+ specify "should apply all instance filters" do
788
+ @i.instance_filter{cost <= 2}
789
+ @i.this.update(:number=>2)
790
+ proc{@i.save}.should raise_error(Sequel::Error)
791
+ @i.this.update(:number=>1, :cost=>3)
792
+ proc{@i.save}.should raise_error(Sequel::Error)
793
+ @i.this.update(:cost=>2)
794
+ @i.save
795
+ @i.refresh.name.should == 'K'
796
+ end
797
+
798
+ specify "should clear instance filters after successful save" do
799
+ @i.save
800
+ @i.this.update(:number=>2)
801
+ @i.update(:name=>'L')
802
+ @i.refresh.name.should == 'L'
803
+ end
804
+
805
+ specify "should not raise an error if deleting only deletes one row" do
806
+ @i.destroy
807
+ proc{@i.refresh}.should raise_error(Sequel::Error, 'Record not found')
808
+ end
809
+
810
+ specify "should raise error if destroying doesn't delete a row" do
811
+ @i.this.update(:number=>2)
812
+ proc{@i.destroy}.should raise_error(Sequel::Error)
813
+ end
814
+ end
@@ -87,10 +87,10 @@ describe "Database schema parser" do
87
87
  INTEGRATION_DB.schema(:items).first.last[:type].should == :integer
88
88
  INTEGRATION_DB.create_table!(:items){Float :number}
89
89
  INTEGRATION_DB.schema(:items).first.last[:type].should == :float
90
- INTEGRATION_DB.create_table!(:items){BigDecimal :number}
91
- INTEGRATION_DB.schema(:items).first.last[:type].should == :decimal
92
- INTEGRATION_DB.create_table!(:items){Numeric :number}
90
+ INTEGRATION_DB.create_table!(:items){BigDecimal :number, :size=>[11, 2]}
93
91
  INTEGRATION_DB.schema(:items).first.last[:type].should == :decimal
92
+ INTEGRATION_DB.create_table!(:items){Numeric :number, :size=>[12, 0]}
93
+ INTEGRATION_DB.schema(:items).first.last[:type].should == :integer
94
94
  INTEGRATION_DB.create_table!(:items){String :number}
95
95
  INTEGRATION_DB.schema(:items).first.last[:type].should == :string
96
96
  INTEGRATION_DB.create_table!(:items){Date :number}
@@ -159,6 +159,17 @@ describe "Database schema modifiers" do
159
159
  @ds.columns!.should == [:number]
160
160
  end
161
161
 
162
+ specify "should rename tables correctly" do
163
+ @db.drop_table(:items) rescue nil
164
+ @db.create_table!(:items2){Integer :number}
165
+ @db.rename_table(:items2, :items)
166
+ @db.table_exists?(:items).should == true
167
+ @db.table_exists?(:items2).should == false
168
+ @db.schema(:items, :reload=>true).map{|x| x.first}.should == [:number]
169
+ @ds.insert([10])
170
+ @ds.columns!.should == [:number]
171
+ end
172
+
162
173
  specify "should allow creating indexes with tables" do
163
174
  @db.create_table!(:items){Integer :number; index :number}
164
175
  @db.table_exists?(:items).should == true
@@ -327,6 +327,33 @@ describe Sequel::Model, ".strict_param_setting" do
327
327
  end
328
328
  end
329
329
 
330
+ describe Sequel::Model, ".require_modification" do
331
+ before do
332
+ @ds1 = MODEL_DB[:items]
333
+ @ds1.meta_def(:provides_accurate_rows_matched?){false}
334
+ @ds2 = MODEL_DB[:items]
335
+ @ds2.meta_def(:provides_accurate_rows_matched?){true}
336
+ end
337
+ after do
338
+ Sequel::Model.require_modification = nil
339
+ end
340
+
341
+ it "should depend on whether the dataset provides an accurate number of rows matched by default" do
342
+ Class.new(Sequel::Model(@ds1)).require_modification.should == false
343
+ Class.new(Sequel::Model(@ds2)).require_modification.should == true
344
+ end
345
+
346
+ it "should obey global setting regardless of dataset support if set" do
347
+ Sequel::Model.require_modification = true
348
+ Class.new(Sequel::Model(@ds1)).require_modification.should == true
349
+ Class.new(Sequel::Model(@ds2)).require_modification.should == true
350
+
351
+ Sequel::Model.require_modification = false
352
+ Class.new(Sequel::Model(@ds1)).require_modification.should == false
353
+ Class.new(Sequel::Model(@ds2)).require_modification.should == false
354
+ end
355
+ end
356
+
330
357
  describe Sequel::Model, ".[] optimization" do
331
358
  before do
332
359
  @c = Class.new(Sequel::Model(:a))
@@ -163,39 +163,17 @@ describe Sequel::Model, ".plugin" do
163
163
  m.get_stamp.should == t
164
164
  end
165
165
 
166
- it "should define a plugin_opts instance method if the plugin has an InstanceMethods module" do
167
- @c.plugin :timestamped, 1, 2=>3
168
- @c.new.timestamped_opts.should == [1, {2=>3}]
169
- end
170
-
171
166
  it "should extend the class with a ClassMethods module if the plugin includes it" do
172
167
  @c.plugin @t
173
168
  @c.def.should == 234
174
169
  end
175
170
 
176
- it "should define a plugin_opts class method if the plugin has a ClassMethods module" do
177
- @c.plugin :timestamped, 1, 2=>3
178
- @c.timestamped_opts.should == [1, {2=>3}]
179
- end
180
-
181
171
  it "should extend the class's dataset with a DatasetMethods module if the plugin includes it" do
182
172
  @c.plugin @t
183
173
  @c.dataset.ghi.should == 345
184
174
  @c.ghi.should == 345
185
175
  end
186
176
 
187
- it "should define a plugin_opts dataset method if the plugin has a DatasetMethods module" do
188
- @c.plugin :timestamped, 1, 2=>3
189
- @c.dataset.timestamped_opts.should == [1, {2=>3}]
190
- end
191
-
192
- it "should use a single arg for the plugin_opts method if only a single arg was given" do
193
- @c.plugin :timestamped, 1
194
- @c.new.timestamped_opts.should == 1
195
- @c.timestamped_opts.should == 1
196
- @c.dataset.timestamped_opts.should == 1
197
- end
198
-
199
177
  it "should save the DatasetMethods module and apply it later if the class doesn't have a dataset" do
200
178
  c = Class.new(Sequel::Model)
201
179
  c.plugin @t
@@ -97,6 +97,22 @@ describe "Model#save" do
97
97
  MODEL_DB.sqls.should == ["UPDATE items SET x = 1 WHERE (id = 3)"]
98
98
  end
99
99
 
100
+ it "should raise a NoExistingObject exception if the dataset update call doesn't return 1, unless require_modification is false" do
101
+ o = @c.load(:id => 3, :x => 1)
102
+ o.this.meta_def(:update){|*a| 0}
103
+ proc{o.save}.should raise_error(Sequel::NoExistingObject)
104
+ o.this.meta_def(:update){|*a| 2}
105
+ proc{o.save}.should raise_error(Sequel::NoExistingObject)
106
+ o.this.meta_def(:update){|*a| 1}
107
+ proc{o.save}.should_not raise_error
108
+
109
+ o.require_modification = false
110
+ o.this.meta_def(:update){|*a| 0}
111
+ proc{o.save}.should_not raise_error
112
+ o.this.meta_def(:update){|*a| 2}
113
+ proc{o.save}.should_not raise_error
114
+ end
115
+
100
116
  it "should update only the given columns if given" do
101
117
  o = @c.load(:id => 3, :x => 1, :y => nil)
102
118
  o.save(:y)
@@ -788,7 +804,7 @@ describe Sequel::Model, "#destroy" do
788
804
  MODEL_DB.reset
789
805
  @model = Class.new(Sequel::Model(:items))
790
806
  @model.columns :id
791
- @model.dataset.meta_def(:delete) {MODEL_DB.execute delete_sql}
807
+ @model.dataset.meta_def(:delete){MODEL_DB.execute delete_sql;1}
792
808
 
793
809
  @instance = @model.load(:id => 1234)
794
810
  end
@@ -797,6 +813,21 @@ describe Sequel::Model, "#destroy" do
797
813
  @model.send(:define_method, :after_destroy){3}
798
814
  @instance.destroy.should == @instance
799
815
  end
816
+
817
+ it "should raise a NoExistingObject exception if the dataset delete call doesn't return 1" do
818
+ @instance.this.meta_def(:delete){|*a| 0}
819
+ proc{@instance.delete}.should raise_error(Sequel::NoExistingObject)
820
+ @instance.this.meta_def(:delete){|*a| 2}
821
+ proc{@instance.delete}.should raise_error(Sequel::NoExistingObject)
822
+ @instance.this.meta_def(:delete){|*a| 1}
823
+ proc{@instance.delete}.should_not raise_error
824
+
825
+ @instance.require_modification = false
826
+ @instance.this.meta_def(:delete){|*a| 0}
827
+ proc{@instance.delete}.should_not raise_error
828
+ @instance.this.meta_def(:delete){|*a| 2}
829
+ proc{@instance.delete}.should_not raise_error
830
+ end
800
831
 
801
832
  it "should run within a transaction if use_transactions is true" do
802
833
  @instance.use_transactions = true