sequel 3.10.0 → 3.11.0

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