sequel 0.4.5 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,576 +0,0 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
2
-
3
- Sequel::Model.db = MODEL_DB = MockDatabase.new
4
-
5
- require File.join(File.dirname(__FILE__), "model/base_spec")
6
- require File.join(File.dirname(__FILE__), "model/caching_spec")
7
- require File.join(File.dirname(__FILE__), "model/hooks_spec")
8
- require File.join(File.dirname(__FILE__), "model/record_spec")
9
- require File.join(File.dirname(__FILE__), "model/schema_spec")
10
- require File.join(File.dirname(__FILE__), "model/relations_spec")
11
- require File.join(File.dirname(__FILE__), "model/plugins_spec")
12
- require File.join(File.dirname(__FILE__), "model/validations_spec")
13
-
14
- describe Sequel::Model do
15
-
16
- it "should have class method aliased as model" do
17
- Sequel::Model.instance_methods.should include("model")
18
-
19
- model_a = Class.new Sequel::Model
20
- model_a.new.model.should be(model_a)
21
- end
22
-
23
- it "should be associated with a dataset" do
24
- model_a = Class.new(Sequel::Model) { set_dataset MODEL_DB[:as] }
25
-
26
- model_a.dataset.should be_a_kind_of(MockDataset)
27
- model_a.dataset.opts[:from].should == [:as]
28
-
29
- model_b = Class.new(Sequel::Model) { set_dataset MODEL_DB[:bs] }
30
-
31
- model_b.dataset.should be_a_kind_of(MockDataset)
32
- model_b.dataset.opts[:from].should == [:bs]
33
-
34
- model_a.dataset.opts[:from].should == [:as]
35
- end
36
-
37
- end
38
-
39
- describe Sequel::Model, "dataset & schema" do
40
-
41
- before do
42
- @model = Class.new(Sequel::Model(:items))
43
- end
44
-
45
- it "creates dynamic model subclass with set table name" do
46
- @model.table_name.should == :items
47
- end
48
-
49
- it "defaults to primary key of id" do
50
- @model.primary_key.should == :id
51
- end
52
-
53
- it "allow primary key change" do
54
- @model.set_primary_key :ssn
55
- @model.primary_key.should == :ssn
56
- end
57
-
58
- it "allows dataset change" do
59
- @model.set_dataset(MODEL_DB[:foo])
60
- @model.table_name.should == :foo
61
- end
62
-
63
- it "sets schema with implicit table name" do
64
- @model.set_schema do
65
- primary_key :ssn, :string
66
- end
67
- @model.primary_key.should == :ssn
68
- @model.table_name.should == :items
69
- end
70
-
71
- it "sets schema with explicit table name" do
72
- @model.set_schema :foo do
73
- primary_key :id
74
- end
75
- @model.primary_key.should == :id
76
- @model.table_name.should == :foo
77
- end
78
-
79
- it "puts the lotion in the basket or it gets the hose again" do
80
- # just kidding!
81
- end
82
- end
83
-
84
- describe Sequel::Model, "constructor" do
85
-
86
- before(:each) do
87
- @m = Class.new(Sequel::Model)
88
- end
89
-
90
- it "should accept a hash" do
91
- m = @m.new(:a => 1, :b => 2)
92
- m.values.should == {:a => 1, :b => 2}
93
- m.should be_new
94
- end
95
-
96
- it "should accept a block and yield itself to the block" do
97
- block_called = false
98
- m = @m.new {|i| block_called = true; i.should be_a_kind_of(@m); i.values[:a] = 1}
99
-
100
- block_called.should be_true
101
- m.values[:a].should == 1
102
- end
103
-
104
- end
105
-
106
- describe Sequel::Model, "new" do
107
-
108
- before(:each) do
109
- @m = Class.new(Sequel::Model) do
110
- set_dataset MODEL_DB[:items]
111
- end
112
- end
113
-
114
- it "should be marked as new?" do
115
- o = @m.new
116
- o.should be_new
117
- o.should be_new_record
118
- end
119
-
120
- it "should not be marked as new? once it is saved" do
121
- o = @m.new(:x => 1)
122
- o.should be_new
123
- o.save
124
- o.should_not be_new
125
- o.should_not be_new_record
126
- end
127
-
128
- it "should use the last inserted id as primary key if not in values" do
129
- d = @m.dataset
130
- def d.insert(*args)
131
- super
132
- 1234
133
- end
134
-
135
- def d.first
136
- {:x => 1, :id => 1234}
137
- end
138
-
139
- o = @m.new(:x => 1)
140
- o.save
141
- o.id.should == 1234
142
-
143
- o = @m.new(:x => 1, :id => 333)
144
- o.save
145
- o.id.should == 333
146
- end
147
-
148
- end
149
-
150
- describe Sequel::Model, ".subset" do
151
-
152
- before(:each) do
153
- MODEL_DB.reset
154
-
155
- @c = Class.new(Sequel::Model(:items))
156
- end
157
-
158
- it "should create a filter on the underlying dataset" do
159
- proc {@c.new_only}.should raise_error(NoMethodError)
160
-
161
- @c.subset(:new_only) {:age == 'new'}
162
-
163
- @c.new_only.sql.should == "SELECT * FROM items WHERE (age = 'new')"
164
- @c.dataset.new_only.sql.should == "SELECT * FROM items WHERE (age = 'new')"
165
-
166
- @c.subset(:pricey) {:price > 100}
167
-
168
- @c.pricey.sql.should == "SELECT * FROM items WHERE (price > 100)"
169
- @c.dataset.pricey.sql.should == "SELECT * FROM items WHERE (price > 100)"
170
-
171
- # check if subsets are composable
172
- @c.pricey.new_only.sql.should == "SELECT * FROM items WHERE (price > 100) AND (age = 'new')"
173
- @c.new_only.pricey.sql.should == "SELECT * FROM items WHERE (age = 'new') AND (price > 100)"
174
- end
175
-
176
- end
177
-
178
- describe Sequel::Model, ".find" do
179
-
180
- before(:each) do
181
- MODEL_DB.reset
182
-
183
- @c = Class.new(Sequel::Model(:items))
184
-
185
- $cache_dataset_row = {:name => 'sharon', :id => 1}
186
- @dataset = @c.dataset
187
- $sqls = []
188
- @dataset.extend(Module.new {
189
- def fetch_rows(sql)
190
- $sqls << sql
191
- yield $cache_dataset_row
192
- end
193
- })
194
- end
195
-
196
- it "should return the first record matching the given filter" do
197
- @c.find(:name => 'sharon').should be_a_kind_of(@c)
198
- $sqls.last.should == "SELECT * FROM items WHERE (name = 'sharon') LIMIT 1"
199
-
200
- @c.find {"name LIKE 'abc%'".lit}.should be_a_kind_of(@c)
201
- $sqls.last.should == "SELECT * FROM items WHERE name LIKE 'abc%' LIMIT 1"
202
- end
203
-
204
- it "should accept filter blocks" do
205
- @c.find {:id == 1}.should be_a_kind_of(@c)
206
- $sqls.last.should == "SELECT * FROM items WHERE (id = 1) LIMIT 1"
207
-
208
- @c.find {:x > 1 && :y < 2}.should be_a_kind_of(@c)
209
- $sqls.last.should == "SELECT * FROM items WHERE ((x > 1) AND (y < 2)) LIMIT 1"
210
- end
211
-
212
- end
213
-
214
- describe Sequel::Model, ".fetch" do
215
-
216
- before(:each) do
217
- MODEL_DB.reset
218
- @c = Class.new(Sequel::Model(:items))
219
- end
220
-
221
- it "should return instances of Model" do
222
- @c.fetch("SELECT * FROM items").first.should be_a_kind_of(@c)
223
- end
224
-
225
- it "should return true for .empty? and not raise an error on empty selection" do
226
- rows = @c.fetch("SELECT * FROM items WHERE FALSE")
227
- @c.class_def(:fetch_rows) {|sql| yield({:count => 0})}
228
- proc {rows.empty?}.should_not raise_error
229
- end
230
-
231
- end
232
-
233
- describe Sequel::Model, "magic methods" do
234
-
235
- before(:each) do
236
- @c = Class.new(Sequel::Dataset) do
237
- @@sqls = []
238
-
239
- def self.sqls; @@sqls; end
240
-
241
- def fetch_rows(sql)
242
- @@sqls << sql
243
- yield({:id => 123, :name => 'hey'})
244
- end
245
- end
246
-
247
- @m = Class.new(Sequel::Model(@c.new(nil).from(:items)))
248
- end
249
-
250
- it "should support order_by_xxx" do
251
- @m.order_by_name.should be_a_kind_of(@c)
252
- @m.order_by_name.sql.should == "SELECT * FROM items ORDER BY name"
253
- end
254
-
255
- it "should support group_by_xxx" do
256
- @m.group_by_name.should be_a_kind_of(@c)
257
- @m.group_by_name.sql.should == "SELECT * FROM items GROUP BY name"
258
- end
259
-
260
- it "should support count_by_xxx" do
261
- @m.count_by_name.should be_a_kind_of(@c)
262
- @m.count_by_name.sql.should == "SELECT name, count(name) AS count FROM items GROUP BY name ORDER BY count"
263
- end
264
-
265
- it "should support filter_by_xxx" do
266
- @m.filter_by_name('sharon').should be_a_kind_of(@c)
267
- @m.filter_by_name('sharon').sql.should == "SELECT * FROM items WHERE (name = 'sharon')"
268
- end
269
-
270
- it "should support all_by_xxx" do
271
- all = @m.all_by_name('sharon')
272
- all.class.should == Array
273
- all.size.should == 1
274
- all.first.should be_a_kind_of(@m)
275
- all.first.values.should == {:id => 123, :name => 'hey'}
276
- @c.sqls.should == ["SELECT * FROM items WHERE (name = 'sharon')"]
277
- end
278
-
279
- it "should support find_by_xxx" do
280
- @m.find_by_name('sharon').should be_a_kind_of(@m)
281
- @m.find_by_name('sharon').values.should == {:id => 123, :name => 'hey'}
282
- @c.sqls.should == ["SELECT * FROM items WHERE (name = 'sharon') LIMIT 1"] * 2
283
- end
284
-
285
- it "should support first_by_xxx" do
286
- @m.first_by_name('sharon').should be_a_kind_of(@m)
287
- @m.first_by_name('sharon').values.should == {:id => 123, :name => 'hey'}
288
- @c.sqls.should == ["SELECT * FROM items ORDER BY name LIMIT 1"] * 2
289
- end
290
-
291
- it "should support last_by_xxx" do
292
- @m.last_by_name('sharon').should be_a_kind_of(@m)
293
- @m.last_by_name('sharon').values.should == {:id => 123, :name => 'hey'}
294
- @c.sqls.should == ["SELECT * FROM items ORDER BY name DESC LIMIT 1"] * 2
295
- end
296
-
297
- end
298
-
299
- describe Sequel::Model, ".find_or_create" do
300
-
301
- before(:each) do
302
- MODEL_DB.reset
303
- @c = Class.new(Sequel::Model(:items)) do
304
- no_primary_key
305
- end
306
- end
307
-
308
- it "should find the record" do
309
- @c.find_or_create(:x => 1)
310
- MODEL_DB.sqls.should == ["SELECT * FROM items WHERE (x = 1) LIMIT 1"]
311
-
312
- MODEL_DB.reset
313
- end
314
-
315
- it "should create the record if not found" do
316
- @c.meta_def(:find) do |*args|
317
- dataset.filter(*args).first
318
- nil
319
- end
320
-
321
- @c.find_or_create(:x => 1)
322
- MODEL_DB.sqls.should == [
323
- "SELECT * FROM items WHERE (x = 1) LIMIT 1",
324
- "INSERT INTO items (x) VALUES (1)"
325
- ]
326
- end
327
- end
328
-
329
- describe Sequel::Model, ".delete_all" do
330
-
331
- before(:each) do
332
- MODEL_DB.reset
333
- @c = Class.new(Sequel::Model(:items)) do
334
- no_primary_key
335
- end
336
-
337
- @c.dataset.meta_def(:delete) {MODEL_DB << delete_sql}
338
- end
339
-
340
- it "should delete all records in the dataset" do
341
- @c.delete_all
342
- MODEL_DB.sqls.should == ["DELETE FROM items"]
343
- end
344
-
345
- end
346
-
347
- describe Sequel::Model, ".destroy_all" do
348
-
349
- before(:each) do
350
- MODEL_DB.reset
351
- @c = Class.new(Sequel::Model(:items)) do
352
- no_primary_key
353
- end
354
-
355
- @c.dataset.meta_def(:delete) {MODEL_DB << delete_sql}
356
- end
357
-
358
- it "should delete all records in the dataset" do
359
- @c.destroy_all
360
- MODEL_DB.sqls.should == ["DELETE FROM items"]
361
- end
362
-
363
- it "should call dataset destroy method if *_destroy hooks exist" do
364
- @c.dataset.stub!(:destroy).and_return(true)
365
- @c.should_receive(:has_hooks?).with(:before_destroy).and_return(true)
366
- @c.destroy_all
367
- end
368
-
369
- it "should call dataset delete method if no hooks are present" do
370
- @c.dataset.stub!(:delete).and_return(true)
371
- @c.should_receive(:has_hooks?).with(:before_destroy).and_return(false)
372
- @c.should_receive(:has_hooks?).with(:after_destroy).and_return(false)
373
- @c.destroy_all
374
- end
375
-
376
- end
377
-
378
- describe Sequel::Model, ".join" do
379
-
380
- before(:each) do
381
- MODEL_DB.reset
382
- @c = Class.new(Sequel::Model(:items)) do
383
- no_primary_key
384
- end
385
- end
386
-
387
- it "should format proper SQL" do
388
- @c.join(:atts, :item_id => :id).sql.should == \
389
- "SELECT items.* FROM items INNER JOIN atts ON (atts.item_id = items.id)"
390
- end
391
-
392
- end
393
-
394
- describe Sequel::Model, ".all" do
395
-
396
- before(:each) do
397
- MODEL_DB.reset
398
- @c = Class.new(Sequel::Model(:items)) do
399
- no_primary_key
400
- end
401
-
402
- @c.dataset.meta_def(:all) {1234}
403
- end
404
-
405
- it "should return all records in the dataset" do
406
- @c.all.should == 1234
407
- end
408
-
409
- end
410
-
411
- class DummyModelBased < Sequel::Model(:blog)
412
- end
413
-
414
- describe Sequel::Model, "(:tablename)" do
415
-
416
- it "should allow reopening of descendant classes" do
417
- proc do
418
- eval "class DummyModelBased < Sequel::Model(:blog); end"
419
- end.should_not raise_error
420
- end
421
-
422
- end
423
-
424
- describe Sequel::Model, ".create" do
425
-
426
- before(:each) do
427
- MODEL_DB.reset
428
- @c = Class.new(Sequel::Model(:items))
429
- end
430
-
431
- it "should be able to create rows in the associated table" do
432
- o = @c.create(:x => 1)
433
- o.class.should == @c
434
- MODEL_DB.sqls.should == ['INSERT INTO items (x) VALUES (1)', "SELECT * FROM items WHERE (id IN ('INSERT INTO items (x) VALUES (1)')) LIMIT 1"]
435
- end
436
-
437
- it "should be able to create rows without any values specified" do
438
- o = @c.create
439
- o.class.should == @c
440
- MODEL_DB.sqls.should == ["INSERT INTO items DEFAULT VALUES", "SELECT * FROM items WHERE (id IN ('INSERT INTO items DEFAULT VALUES')) LIMIT 1"]
441
- end
442
-
443
- end
444
-
445
- describe Sequel::Model, "A model class without a primary key" do
446
-
447
- before(:each) do
448
- MODEL_DB.reset
449
- @c = Class.new(Sequel::Model(:items)) do
450
- no_primary_key
451
- end
452
- end
453
-
454
- it "should be able to insert records without selecting them back" do
455
- i = nil
456
- proc {i = @c.create(:x => 1)}.should_not raise_error
457
- i.class.should be(@c)
458
- i.values.to_hash.should == {:x => 1}
459
-
460
- MODEL_DB.sqls.should == ['INSERT INTO items (x) VALUES (1)']
461
- end
462
-
463
- it "should raise when deleting" do
464
- o = @c.new
465
- proc {o.delete}.should raise_error
466
- end
467
-
468
- it "should insert a record when saving" do
469
- o = @c.new(:x => 2)
470
- o.should be_new
471
- o.save
472
- MODEL_DB.sqls.should == ['INSERT INTO items (x) VALUES (2)']
473
- end
474
-
475
- end
476
-
477
- describe Sequel::Model, "attribute accessors" do
478
-
479
- before(:each) do
480
- MODEL_DB.reset
481
-
482
- @c = Class.new(Sequel::Model(:items)) do
483
- def columns
484
- [:id, :x, :y]
485
- end
486
- end
487
- end
488
-
489
- it "should be created dynamically" do
490
- o = @c.new
491
-
492
- o.should_not be_respond_to(:x)
493
- o.x.should be_nil
494
- o.should be_respond_to(:x)
495
-
496
- o.should_not be_respond_to(:x=)
497
- o.x = 34
498
- o.x.should == 34
499
- o.should be_respond_to(:x=)
500
- end
501
-
502
- it "should raise for a column that doesn't exist in the dataset" do
503
- o = @c.new
504
-
505
- proc {o.x}.should_not raise_error
506
- proc {o.xx}.should raise_error(Sequel::Error)
507
-
508
- proc {o.x = 3}.should_not raise_error
509
- proc {o.yy = 4}.should raise_error(Sequel::Error)
510
-
511
- proc {o.yy?}.should raise_error(NoMethodError)
512
- end
513
-
514
- it "should not raise for a column not in the dataset, but for which there's a value" do
515
- o = @c.new
516
-
517
- proc {o.xx}.should raise_error(Sequel::Error)
518
- proc {o.yy}.should raise_error(Sequel::Error)
519
-
520
- o.values[:xx] = 123
521
- o.values[:yy] = nil
522
-
523
- proc {o.xx; o.yy}.should_not raise_error(Sequel::Error)
524
-
525
- o.xx.should == 123
526
- o.yy.should == nil
527
-
528
- proc {o.xx = 3}.should raise_error(Sequel::Error)
529
- end
530
-
531
- end
532
-
533
- describe Sequel::Model, ".[]" do
534
-
535
- before(:each) do
536
- MODEL_DB.reset
537
-
538
- @c = Class.new(Sequel::Model(:items))
539
-
540
- $cache_dataset_row = {:name => 'sharon', :id => 1}
541
- @dataset = @c.dataset
542
- $sqls = []
543
- @dataset.extend(Module.new {
544
- def fetch_rows(sql)
545
- $sqls << sql
546
- yield $cache_dataset_row
547
- end
548
- })
549
- end
550
-
551
- it "should return the first record for the given pk" do
552
- @c[1].should be_a_kind_of(@c)
553
- $sqls.last.should == "SELECT * FROM items WHERE (id = 1) LIMIT 1"
554
- @c[9999].should be_a_kind_of(@c)
555
- $sqls.last.should == "SELECT * FROM items WHERE (id = 9999) LIMIT 1"
556
- end
557
-
558
- it "should raise for boolean argument (mistaken comparison)" do
559
- # This in order to prevent stuff like Model[:a == 'b']
560
- proc {@c[:a == 1]}.should raise_error(Sequel::Error)
561
- proc {@c[:a != 1]}.should raise_error(Sequel::Error)
562
- end
563
-
564
- it "should work correctly for custom primary key" do
565
- @c.set_primary_key :name
566
- @c['sharon'].should be_a_kind_of(@c)
567
- $sqls.last.should == "SELECT * FROM items WHERE (name = 'sharon') LIMIT 1"
568
- end
569
-
570
- it "should work correctly for composite primary key" do
571
- @c.set_primary_key [:node_id, :kind]
572
- @c[3921, 201].should be_a_kind_of(@c)
573
- $sqls.last.should =~ \
574
- /^SELECT \* FROM items WHERE (\(node_id = 3921\) AND \(kind = 201\))|(\(kind = 201\) AND \(node_id = 3921\)) LIMIT 1$/
575
- end
576
- end