sequel 2.4.0 → 2.5.0

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