sequel 0.4.5 → 0.5

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.
@@ -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