sequel 2.4.0 → 2.5.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 (38) hide show
  1. data/CHANGELOG +34 -0
  2. data/Rakefile +1 -1
  3. data/lib/sequel_core.rb +16 -7
  4. data/lib/sequel_core/adapters/ado.rb +6 -2
  5. data/lib/sequel_core/adapters/db2.rb +1 -1
  6. data/lib/sequel_core/adapters/jdbc.rb +2 -2
  7. data/lib/sequel_core/adapters/jdbc/postgresql.rb +22 -10
  8. data/lib/sequel_core/adapters/mysql.rb +2 -2
  9. data/lib/sequel_core/adapters/odbc.rb +6 -2
  10. data/lib/sequel_core/adapters/postgres.rb +25 -14
  11. data/lib/sequel_core/adapters/shared/mysql.rb +15 -35
  12. data/lib/sequel_core/adapters/shared/postgres.rb +137 -77
  13. data/lib/sequel_core/adapters/sqlite.rb +2 -2
  14. data/lib/sequel_core/core_ext.rb +11 -7
  15. data/lib/sequel_core/database.rb +18 -1
  16. data/lib/sequel_core/dataset.rb +23 -7
  17. data/lib/sequel_core/dataset/convenience.rb +1 -1
  18. data/lib/sequel_core/dataset/sql.rb +46 -31
  19. data/lib/sequel_core/exceptions.rb +4 -0
  20. data/lib/sequel_core/schema/generator.rb +43 -3
  21. data/lib/sequel_core/schema/sql.rb +52 -26
  22. data/lib/sequel_model.rb +2 -5
  23. data/lib/sequel_model/associations.rb +3 -3
  24. data/lib/sequel_model/base.rb +19 -13
  25. data/lib/sequel_model/record.rb +19 -11
  26. data/lib/sequel_model/schema.rb +10 -4
  27. data/lib/sequel_model/validations.rb +20 -7
  28. data/spec/adapters/mysql_spec.rb +1 -1
  29. data/spec/adapters/postgres_spec.rb +64 -9
  30. data/spec/integration/dataset_test.rb +32 -0
  31. data/spec/sequel_core/core_sql_spec.rb +38 -0
  32. data/spec/sequel_core/database_spec.rb +16 -1
  33. data/spec/sequel_core/dataset_spec.rb +66 -1
  34. data/spec/sequel_core/schema_generator_spec.rb +23 -3
  35. data/spec/sequel_core/schema_spec.rb +175 -4
  36. data/spec/sequel_model/record_spec.rb +47 -0
  37. data/spec/sequel_model/validations_spec.rb +70 -0
  38. metadata +2 -2
@@ -999,4 +999,19 @@ context "Database#server_opts" do
999
999
  opts = {:host=>1, :database=>2, :servers=>{:server1=>2}}
1000
1000
  proc{MockDatabase.new(opts).send(:server_opts, :server1)}.should raise_error(Sequel::Error)
1001
1001
  end
1002
- end
1002
+ end
1003
+
1004
+ context "Database#raise_error" do
1005
+ specify "should reraise if the exception class is not in opts[:classes]" do
1006
+ e = Class.new(StandardError)
1007
+ proc{MockDatabase.new.send(:raise_error, e.new(''), :classes=>[])}.should raise_error(e)
1008
+ end
1009
+
1010
+ specify "should convert the exception to a DatabaseError if the exception class is not in opts[:classes]" do
1011
+ proc{MockDatabase.new.send(:raise_error, Interrupt.new(''), :classes=>[Interrupt])}.should raise_error(Sequel::DatabaseError)
1012
+ end
1013
+
1014
+ specify "should convert the exception to a DatabaseError if opts[:classes] if not present" do
1015
+ proc{MockDatabase.new.send(:raise_error, Interrupt.new(''))}.should raise_error(Sequel::DatabaseError)
1016
+ end
1017
+ end
@@ -161,6 +161,16 @@ context "A simple dataset" do
161
161
  @dataset.select_sql(:sql => 'xxx yyy zzz').should ==
162
162
  "xxx yyy zzz"
163
163
  end
164
+
165
+ specify "should use the :sql option for all sql methods" do
166
+ sql = "X"
167
+ ds = Sequel::Dataset.new(nil, :sql=>sql)
168
+ ds.sql.should == sql
169
+ ds.select_sql.should == sql
170
+ ds.insert_sql.should == sql
171
+ ds.delete_sql.should == sql
172
+ ds.update_sql.should == sql
173
+ end
164
174
  end
165
175
 
166
176
  context "A dataset with multiple tables in its FROM clause" do
@@ -1135,6 +1145,12 @@ context "Dataset#count" do
1135
1145
  @dataset.limit(5).count.should == 1
1136
1146
  @c.sql.should == "SELECT COUNT(*) FROM (SELECT * FROM test LIMIT 5) t1 LIMIT 1"
1137
1147
  end
1148
+
1149
+ it "should work on a graphed_dataset" do
1150
+ @dataset.should_receive(:columns).twice.and_return([:a])
1151
+ @dataset.graph(@dataset, [:a], :table_alias=>:test2).count.should == 1
1152
+ @c.sql.should == 'SELECT COUNT(*) FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1'
1153
+ end
1138
1154
  end
1139
1155
 
1140
1156
 
@@ -1754,6 +1770,11 @@ context "Dataset#single_value" do
1754
1770
  specify "should return nil if no records" do
1755
1771
  @e.single_value.should be_nil
1756
1772
  end
1773
+
1774
+ it "should work on a graphed_dataset" do
1775
+ @d.should_receive(:columns).twice.and_return([:a])
1776
+ @d.graph(@d, [:a], :table_alias=>:test2).single_value.should == 'SELECT test.a, test2.a AS test2_a FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1'
1777
+ end
1757
1778
  end
1758
1779
 
1759
1780
  context "Dataset#get" do
@@ -3084,4 +3105,48 @@ context "Sequel::Dataset#server" do
3084
3105
  ['DELETE FROM items', :d],
3085
3106
  ['UPDATE items SET a = (a + 1)', :u]]
3086
3107
  end
3087
- end
3108
+ end
3109
+
3110
+ context "Sequel::Dataset #set_defaults" do
3111
+ before do
3112
+ @ds = Sequel::Dataset.new(nil).from(:items).set_defaults(:x=>1)
3113
+ end
3114
+
3115
+ specify "should set the default values for inserts" do
3116
+ @ds.insert_sql.should == "INSERT INTO items (x) VALUES (1)"
3117
+ @ds.insert_sql(:x=>2).should == "INSERT INTO items (x) VALUES (2)"
3118
+ @ds.insert_sql(:y=>2).should =~ /INSERT INTO items \([xy], [xy]\) VALUES \([21], [21]\)/
3119
+ @ds.set_defaults(:y=>2).insert_sql.should =~ /INSERT INTO items \([xy], [xy]\) VALUES \([21], [21]\)/
3120
+ @ds.set_defaults(:x=>2).insert_sql.should == "INSERT INTO items (x) VALUES (2)"
3121
+ end
3122
+
3123
+ specify "should set the default values for updates" do
3124
+ @ds.update_sql.should == "UPDATE items SET x = 1"
3125
+ @ds.update_sql(:x=>2).should == "UPDATE items SET x = 2"
3126
+ @ds.update_sql(:y=>2).should =~ /UPDATE items SET (x = 1|y = 2), (x = 1|y = 2)/
3127
+ @ds.set_defaults(:y=>2).update_sql.should =~ /UPDATE items SET (x = 1|y = 2), (x = 1|y = 2)/
3128
+ @ds.set_defaults(:x=>2).update_sql.should == "UPDATE items SET x = 2"
3129
+ end
3130
+ end
3131
+
3132
+ context "Sequel::Dataset #set_overrides" do
3133
+ before do
3134
+ @ds = Sequel::Dataset.new(nil).from(:items).set_overrides(:x=>1)
3135
+ end
3136
+
3137
+ specify "should override the given values for inserts" do
3138
+ @ds.insert_sql.should == "INSERT INTO items (x) VALUES (1)"
3139
+ @ds.insert_sql(:x=>2).should == "INSERT INTO items (x) VALUES (1)"
3140
+ @ds.insert_sql(:y=>2).should =~ /INSERT INTO items \([xy], [xy]\) VALUES \([21], [21]\)/
3141
+ @ds.set_overrides(:y=>2).insert_sql.should =~ /INSERT INTO items \([xy], [xy]\) VALUES \([21], [21]\)/
3142
+ @ds.set_overrides(:x=>2).insert_sql.should == "INSERT INTO items (x) VALUES (1)"
3143
+ end
3144
+
3145
+ specify "should override the given values for updates" do
3146
+ @ds.update_sql.should == "UPDATE items SET x = 1"
3147
+ @ds.update_sql(:x=>2).should == "UPDATE items SET x = 1"
3148
+ @ds.update_sql(:y=>2).should =~ /UPDATE items SET (x = 1|y = 2), (x = 1|y = 2)/
3149
+ @ds.set_overrides(:y=>2).update_sql.should =~ /UPDATE items SET (x = 1|y = 2), (x = 1|y = 2)/
3150
+ @ds.set_overrides(:x=>2).update_sql.should == "UPDATE items SET x = 1"
3151
+ end
3152
+ end
@@ -12,6 +12,8 @@ describe Sequel::Schema::Generator do
12
12
  index :title
13
13
  index [:title, :body]
14
14
  foreign_key :node_id, :nodes
15
+ primary_key [:title, :parent_id], :name => :cpk
16
+ foreign_key [:node_id, :prop_id], :nodes_props, :name => :cfk
15
17
  end
16
18
  @columns, @indexes = @generator.create_info
17
19
  end
@@ -23,7 +25,7 @@ describe Sequel::Schema::Generator do
23
25
  end
24
26
 
25
27
  it "counts primary key, column and constraint definitions as columns" do
26
- @columns.size.should == 7
28
+ @columns.size.should == 9
27
29
  end
28
30
 
29
31
  it "places primary key first" do
@@ -53,6 +55,7 @@ describe Sequel::Schema::Generator do
53
55
  it "uses table for foreign key columns, if specified" do
54
56
  @columns[6][:table].should == :nodes
55
57
  @columns[3][:table].should == nil
58
+ @columns[8][:table].should == :nodes_props
56
59
  end
57
60
 
58
61
  it "finds columns" do
@@ -70,6 +73,17 @@ describe Sequel::Schema::Generator do
70
73
  @columns[5][:name].should == :xxx
71
74
  @columns[5][:type].should == :check
72
75
  @columns[5][:check].should be_a_kind_of(Proc)
76
+
77
+ @columns[7][:name].should == :cpk
78
+ @columns[7][:type].should == :check
79
+ @columns[7][:constraint_type].should == :primary_key
80
+ @columns[7][:columns].should == [ :title, :parent_id ]
81
+
82
+ @columns[8][:name].should == :cfk
83
+ @columns[8][:type].should == :check
84
+ @columns[8][:constraint_type].should == :foreign_key
85
+ @columns[8][:columns].should == [ :node_id, :prop_id ]
86
+ @columns[8][:table].should == :nodes_props
73
87
  end
74
88
 
75
89
  it "creates indexes" do
@@ -95,8 +109,11 @@ describe Sequel::Schema::AlterTableGenerator do
95
109
  add_index :blah, :where => {:something => true}
96
110
  add_constraint :con1, ':fred > 100'
97
111
  drop_constraint :con2
112
+ add_unique_constraint [:aaa, :bbb, :ccc], :name => :con3
98
113
  add_primary_key :id
99
114
  add_foreign_key :node_id, :nodes
115
+ add_primary_key [:aaa, :bbb]
116
+ add_foreign_key [:node_id, :prop_id], :nodes_props
100
117
  end
101
118
  end
102
119
 
@@ -113,10 +130,13 @@ describe Sequel::Schema::AlterTableGenerator do
113
130
  {:op => :add_index, :columns => [:geom], :type => :spatial},
114
131
  {:op => :add_index, :columns => [:blah], :type => :hash},
115
132
  {:op => :add_index, :columns => [:blah], :where => {:something => true}},
116
- {:op => :add_constraint, :type => :check, :name => :con1, :check => [':fred > 100']},
133
+ {:op => :add_constraint, :type => :check, :constraint_type => :check, :name => :con1, :check => [':fred > 100']},
117
134
  {:op => :drop_constraint, :name => :con2},
135
+ {:op => :add_constraint, :type => :check, :constraint_type => :unique, :name => :con3, :columns => [:aaa, :bbb, :ccc]},
118
136
  {:op => :add_column, :name => :id, :type => :integer, :primary_key=>true, :auto_increment=>true},
119
- {:op => :add_column, :name => :node_id, :type => :integer, :table=>:nodes}
137
+ {:op => :add_column, :name => :node_id, :type => :integer, :table=>:nodes},
138
+ {:op => :add_constraint, :type => :check, :constraint_type => :primary_key, :columns => [:aaa, :bbb]},
139
+ {:op => :add_constraint, :type => :check, :constraint_type => :foreign_key, :columns => [:node_id, :prop_id], :table => :nodes_props}
120
140
  ]
121
141
  end
122
142
  end
@@ -103,11 +103,11 @@ context "DB#create_table" do
103
103
  @db.sqls.should == ["CREATE TABLE cats (name varchar(51))"]
104
104
  end
105
105
 
106
- specify "should accept varchar size as sql function" do
106
+ specify "should use double precision for double type" do
107
107
  @db.create_table(:cats) do
108
- column :name, :varchar[102]
108
+ double :name
109
109
  end
110
- @db.sqls.should == ["CREATE TABLE cats (name varchar(102))"]
110
+ @db.sqls.should == ["CREATE TABLE cats (name double precision)"]
111
111
  end
112
112
 
113
113
  specify "should accept foreign keys without options" do
@@ -181,6 +181,40 @@ context "DB#create_table" do
181
181
  @db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects ON DELETE SET DEFAULT)"]
182
182
  @db.sqls.clear
183
183
  end
184
+
185
+ specify "should accept foreign keys with ON UPDATE clause" do
186
+ @db.create_table(:cats) do
187
+ foreign_key :project_id, :table => :projects, :on_update => :restrict
188
+ end
189
+ @db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects ON UPDATE RESTRICT)"]
190
+
191
+ @db.sqls.clear
192
+ @db.create_table(:cats) do
193
+ foreign_key :project_id, :table => :projects, :on_update => :cascade
194
+ end
195
+ @db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects ON UPDATE CASCADE)"]
196
+
197
+ @db.sqls.clear
198
+ @db.create_table(:cats) do
199
+ foreign_key :project_id, :table => :projects, :on_update => :no_action
200
+ end
201
+ @db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects ON UPDATE NO ACTION)"]
202
+ @db.sqls.clear
203
+
204
+ @db.sqls.clear
205
+ @db.create_table(:cats) do
206
+ foreign_key :project_id, :table => :projects, :on_update => :set_null
207
+ end
208
+ @db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects ON UPDATE SET NULL)"]
209
+ @db.sqls.clear
210
+
211
+ @db.sqls.clear
212
+ @db.create_table(:cats) do
213
+ foreign_key :project_id, :table => :projects, :on_update => :set_default
214
+ end
215
+ @db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects ON UPDATE SET DEFAULT)"]
216
+ @db.sqls.clear
217
+ end
184
218
 
185
219
  specify "should accept inline index definition" do
186
220
  @db.create_table(:cats) do
@@ -210,7 +244,7 @@ context "DB#create_table" do
210
244
  text :name
211
245
  unique :name
212
246
  end
213
- @db.sqls.should == ["CREATE TABLE cats (name text)", "CREATE UNIQUE INDEX cats_name_index ON cats (name)"]
247
+ @db.sqls.should == ["CREATE TABLE cats (name text, UNIQUE (name))", "CREATE UNIQUE INDEX cats_name_index ON cats (name)"]
214
248
  end
215
249
 
216
250
  specify "should raise on full-text index definitions" do
@@ -311,6 +345,92 @@ context "DB#create_table" do
311
345
  end
312
346
  @db.sqls.should == ["CREATE TABLE cats (CONSTRAINT blah_blah CHECK ((x > 0) AND (y < 1)))"]
313
347
  end
348
+
349
+ specify "should accept composite primary keys" do
350
+ @db.create_table(:cats) do
351
+ integer :a
352
+ integer :b
353
+ primary_key [:a, :b]
354
+ end
355
+ @db.sqls.should == ["CREATE TABLE cats (a integer, b integer, PRIMARY KEY (a, b))"]
356
+ end
357
+
358
+ specify "should accept named composite primary keys" do
359
+ @db.create_table(:cats) do
360
+ integer :a
361
+ integer :b
362
+ primary_key [:a, :b], :name => :cpk
363
+ end
364
+ @db.sqls.should == ["CREATE TABLE cats (a integer, b integer, CONSTRAINT cpk PRIMARY KEY (a, b))"]
365
+ end
366
+
367
+ specify "should accept composite foreign keys" do
368
+ @db.create_table(:cats) do
369
+ integer :a
370
+ integer :b
371
+ foreign_key [:a, :b], :abc
372
+ end
373
+ @db.sqls.should == ["CREATE TABLE cats (a integer, b integer, FOREIGN KEY (a, b) REFERENCES abc)"]
374
+ end
375
+
376
+ specify "should accept named composite foreign keys" do
377
+ @db.create_table(:cats) do
378
+ integer :a
379
+ integer :b
380
+ foreign_key [:a, :b], :abc, :name => :cfk
381
+ end
382
+ @db.sqls.should == ["CREATE TABLE cats (a integer, b integer, CONSTRAINT cfk FOREIGN KEY (a, b) REFERENCES abc)"]
383
+ end
384
+
385
+ specify "should accept composite foreign keys with arbitrary keys" do
386
+ @db.create_table(:cats) do
387
+ integer :a
388
+ integer :b
389
+ foreign_key [:a, :b], :abc, :key => [:real_a, :real_b]
390
+ end
391
+ @db.sqls.should == ["CREATE TABLE cats (a integer, b integer, FOREIGN KEY (a, b) REFERENCES abc(real_a, real_b))"]
392
+ @db.sqls.clear
393
+
394
+ @db.create_table(:cats) do
395
+ integer :a
396
+ integer :b
397
+ foreign_key [:a, :b], :abc, :key => [:z, :x]
398
+ end
399
+ @db.sqls.should == ["CREATE TABLE cats (a integer, b integer, FOREIGN KEY (a, b) REFERENCES abc(z, x))"]
400
+ end
401
+
402
+ specify "should accept composite foreign keys with on delete and on update clauses" do
403
+ @db.create_table(:cats) do
404
+ integer :a
405
+ integer :b
406
+ foreign_key [:a, :b], :abc, :on_delete => :cascade
407
+ end
408
+ @db.sqls.should == ["CREATE TABLE cats (a integer, b integer, FOREIGN KEY (a, b) REFERENCES abc ON DELETE CASCADE)"]
409
+
410
+ @db.sqls.clear
411
+ @db.create_table(:cats) do
412
+ integer :a
413
+ integer :b
414
+ foreign_key [:a, :b], :abc, :on_update => :no_action
415
+ end
416
+ @db.sqls.should == ["CREATE TABLE cats (a integer, b integer, FOREIGN KEY (a, b) REFERENCES abc ON UPDATE NO ACTION)"]
417
+
418
+ @db.sqls.clear
419
+ @db.create_table(:cats) do
420
+ integer :a
421
+ integer :b
422
+ foreign_key [:a, :b], :abc, :on_delete => :restrict, :on_update => :set_default
423
+ end
424
+ @db.sqls.should == ["CREATE TABLE cats (a integer, b integer, FOREIGN KEY (a, b) REFERENCES abc ON DELETE RESTRICT ON UPDATE SET DEFAULT)"]
425
+
426
+ @db.sqls.clear
427
+ @db.create_table(:cats) do
428
+ integer :a
429
+ integer :b
430
+ foreign_key [:a, :b], :abc, :key => [:x, :y], :on_delete => :set_null, :on_update => :set_null
431
+ end
432
+ @db.sqls.should == ["CREATE TABLE cats (a integer, b integer, FOREIGN KEY (a, b) REFERENCES abc(x, y) ON DELETE SET NULL ON UPDATE SET NULL)"]
433
+ end
314
434
  end
315
435
 
316
436
  context "DB#create_table!" do
@@ -361,6 +481,19 @@ context "DB#alter_table" do
361
481
  @db.sqls.should == ["ALTER TABLE cats ADD CONSTRAINT blah_blah CHECK ((x > 0) AND (y < 1))"]
362
482
  end
363
483
 
484
+ specify "should support add_unique_constraint" do
485
+ @db.alter_table(:cats) do
486
+ add_unique_constraint [:a, :b]
487
+ end
488
+ @db.sqls.should == ["ALTER TABLE cats ADD UNIQUE (a, b)"]
489
+
490
+ @db.sqls.clear
491
+ @db.alter_table(:cats) do
492
+ add_unique_constraint [:a, :b], :name => :ab_uniq
493
+ end
494
+ @db.sqls.should == ["ALTER TABLE cats ADD CONSTRAINT ab_uniq UNIQUE (a, b)"]
495
+ end
496
+
364
497
  specify "should support add_foreign_key" do
365
498
  @db.alter_table(:cats) do
366
499
  add_foreign_key :node_id, :nodes
@@ -368,6 +501,31 @@ context "DB#alter_table" do
368
501
  @db.sqls.should == ["ALTER TABLE cats ADD COLUMN node_id integer REFERENCES nodes"]
369
502
  end
370
503
 
504
+ specify "should support add_foreign_key with composite foreign keys" do
505
+ @db.alter_table(:cats) do
506
+ add_foreign_key [:node_id, :prop_id], :nodes_props
507
+ end
508
+ @db.sqls.should == ["ALTER TABLE cats ADD FOREIGN KEY (node_id, prop_id) REFERENCES nodes_props"]
509
+
510
+ @db.sqls.clear
511
+ @db.alter_table(:cats) do
512
+ add_foreign_key [:node_id, :prop_id], :nodes_props, :name => :cfk
513
+ end
514
+ @db.sqls.should == ["ALTER TABLE cats ADD CONSTRAINT cfk FOREIGN KEY (node_id, prop_id) REFERENCES nodes_props"]
515
+
516
+ @db.sqls.clear
517
+ @db.alter_table(:cats) do
518
+ add_foreign_key [:node_id, :prop_id], :nodes_props, :key => [:nid, :pid]
519
+ end
520
+ @db.sqls.should == ["ALTER TABLE cats ADD FOREIGN KEY (node_id, prop_id) REFERENCES nodes_props(nid, pid)"]
521
+
522
+ @db.sqls.clear
523
+ @db.alter_table(:cats) do
524
+ add_foreign_key [:node_id, :prop_id], :nodes_props, :on_delete => :restrict, :on_update => :cascade
525
+ end
526
+ @db.sqls.should == ["ALTER TABLE cats ADD FOREIGN KEY (node_id, prop_id) REFERENCES nodes_props ON DELETE RESTRICT ON UPDATE CASCADE"]
527
+ end
528
+
371
529
  specify "should support add_index" do
372
530
  @db.alter_table(:cats) do
373
531
  add_index :name
@@ -382,6 +540,19 @@ context "DB#alter_table" do
382
540
  @db.sqls.should == ["ALTER TABLE cats ADD COLUMN id integer PRIMARY KEY AUTOINCREMENT"]
383
541
  end
384
542
 
543
+ specify "should support add_primary_key with composite primary keys" do
544
+ @db.alter_table(:cats) do
545
+ add_primary_key [:id, :type]
546
+ end
547
+ @db.sqls.should == ["ALTER TABLE cats ADD PRIMARY KEY (id, type)"]
548
+
549
+ @db.sqls.clear
550
+ @db.alter_table(:cats) do
551
+ add_primary_key [:id, :type], :name => :cpk
552
+ end
553
+ @db.sqls.should == ["ALTER TABLE cats ADD CONSTRAINT cpk PRIMARY KEY (id, type)"]
554
+ end
555
+
385
556
  specify "should support drop_column" do
386
557
  @db.alter_table(:cats) do
387
558
  drop_column :score
@@ -17,6 +17,19 @@ describe "Model#save" do
17
17
  MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
18
18
  end
19
19
 
20
+ it "should use dataset's insert_select method if present" do
21
+ ds = @c.dataset = @c.dataset.clone
22
+ def ds.insert_select(hash)
23
+ execute("INSERT INTO items (y) VALUES (2)")
24
+ {:y=>2}
25
+ end
26
+ o = @c.new(:x => 1)
27
+ o.save
28
+
29
+ o.values.should == {:y=>2}
30
+ MODEL_DB.sqls.first.should == "INSERT INTO items (y) VALUES (2)"
31
+ end
32
+
20
33
  it "should update a record for an existing model instance" do
21
34
  o = @c.load(:id => 3, :x => 1)
22
35
  o.save
@@ -104,6 +117,40 @@ describe "Model#save_changes" do
104
117
  o.save_changes
105
118
  MODEL_DB.sqls.should == ["UPDATE items SET y = 4 WHERE (id = 3)"]
106
119
  end
120
+
121
+ it "should update columns changed in a before_update hook" do
122
+ o = @c.load(:id => 3, :x => 1, :y => nil)
123
+ @c.before_update{self.x += 1}
124
+ o.save_changes
125
+ MODEL_DB.sqls.should == []
126
+ o.x = 2
127
+ o.save_changes
128
+ MODEL_DB.sqls.should == ["UPDATE items SET x = 3 WHERE (id = 3)"]
129
+ MODEL_DB.reset
130
+ o.save_changes
131
+ MODEL_DB.sqls.should == []
132
+ o.x = 4
133
+ o.save_changes
134
+ MODEL_DB.sqls.should == ["UPDATE items SET x = 5 WHERE (id = 3)"]
135
+ MODEL_DB.reset
136
+ end
137
+
138
+ it "should update columns changed in a before_save hook" do
139
+ o = @c.load(:id => 3, :x => 1, :y => nil)
140
+ @c.before_save{self.x += 1}
141
+ o.save_changes
142
+ MODEL_DB.sqls.should == []
143
+ o.x = 2
144
+ o.save_changes
145
+ MODEL_DB.sqls.should == ["UPDATE items SET x = 3 WHERE (id = 3)"]
146
+ MODEL_DB.reset
147
+ o.save_changes
148
+ MODEL_DB.sqls.should == []
149
+ o.x = 4
150
+ o.save_changes
151
+ MODEL_DB.sqls.should == ["UPDATE items SET x = 5 WHERE (id = 3)"]
152
+ MODEL_DB.reset
153
+ end
107
154
  end
108
155
 
109
156
  describe "Model#update_values" do