sequel 0.4.4.2 → 0.4.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.
@@ -0,0 +1,59 @@
1
+ module Sequel::Plugins
2
+
3
+ module Timestamped
4
+ def self.apply(m, opts)
5
+ m.class_def(:get_stamp) {@values[:stamp]}
6
+ m.meta_def(:stamp_opts) {opts}
7
+ m.before_save {@values[:stamp] = Time.now}
8
+ end
9
+
10
+ module InstanceMethods
11
+ def abc; timestamped_opts; end
12
+ end
13
+
14
+ module ClassMethods
15
+ def deff; timestamped_opts; end
16
+ end
17
+
18
+ # ??
19
+ # module DatasetMethods
20
+ # def ghi; timestamped_opts; end
21
+ # end
22
+ end
23
+
24
+ end
25
+
26
+ describe Sequel::Model, "using a plugin" do
27
+
28
+ it "should fail if the plugin is not found" do
29
+ proc do
30
+ c = Class.new(Sequel::Model) do
31
+ is :something_or_other
32
+ end
33
+ end.should raise_error(LoadError)
34
+ end
35
+
36
+ it "should apply the plugin to the class" do
37
+ c = nil
38
+ proc do
39
+ c = Class.new(Sequel::Model) do
40
+ is :timestamped, :a => 1, :b => 2
41
+ end
42
+ end.should_not raise_error(LoadError)
43
+
44
+ c.should respond_to(:stamp_opts)
45
+ c.stamp_opts.should == {:a => 1, :b => 2}
46
+
47
+ m = c.new
48
+ m.should respond_to(:get_stamp)
49
+ m.should respond_to(:abc)
50
+ m.abc.should == {:a => 1, :b => 2}
51
+ t = Time.now
52
+ m[:stamp] = t
53
+ m.get_stamp.should == t
54
+
55
+ c.should respond_to(:deff)
56
+ c.deff.should == {:a => 1, :b => 2}
57
+ end
58
+
59
+ end
@@ -0,0 +1,360 @@
1
+ describe "Model#save" do
2
+
3
+ before(:each) do
4
+ MODEL_DB.reset
5
+
6
+ @c = Class.new(Sequel::Model(:items)) do
7
+ def columns
8
+ [:id, :x, :y]
9
+ end
10
+ end
11
+ end
12
+
13
+ it "should insert a record for a new model instance" do
14
+ o = @c.new(:x => 1)
15
+ o.save
16
+
17
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
18
+ end
19
+
20
+ it "should update a record for an existing model instance" do
21
+ o = @c.new(:id => 3, :x => 1)
22
+ o.save
23
+
24
+ MODEL_DB.sqls.first.should =~
25
+ /UPDATE items SET (id = 3, x = 1|x = 1, id = 3) WHERE \(id = 3\)/
26
+ end
27
+
28
+ it "should update only the given columns if given" do
29
+ o = @c.new(:id => 3, :x => 1, :y => nil)
30
+ o.save(:y)
31
+
32
+ MODEL_DB.sqls.first.should == "UPDATE items SET y = NULL WHERE (id = 3)"
33
+ end
34
+
35
+ it "should mark saved columns as not changed" do
36
+ o = @c.new(:id => 3, :x => 1, :y => nil)
37
+ o[:y] = 4
38
+ o.changed_columns.should == [:y]
39
+ o.save(:x)
40
+ o.changed_columns.should == [:y]
41
+ o.save(:y)
42
+ o.changed_columns.should == []
43
+ end
44
+
45
+ end
46
+
47
+ describe "Model#save_changes" do
48
+
49
+ before(:each) do
50
+ MODEL_DB.reset
51
+
52
+ @c = Class.new(Sequel::Model(:items)) do
53
+ def columns
54
+ [:id, :x, :y]
55
+ end
56
+ end
57
+ end
58
+
59
+ it "should do nothing if no changed columns" do
60
+ o = @c.new(:id => 3, :x => 1, :y => nil)
61
+ o.save_changes
62
+
63
+ MODEL_DB.sqls.should be_empty
64
+ end
65
+
66
+ it "should update only changed columns" do
67
+ o = @c.new(:id => 3, :x => 1, :y => nil)
68
+ o.x = 2
69
+
70
+ o.save_changes
71
+ MODEL_DB.sqls.should == ["UPDATE items SET x = 2 WHERE (id = 3)"]
72
+ o.save_changes
73
+ o.save_changes
74
+ MODEL_DB.sqls.should == ["UPDATE items SET x = 2 WHERE (id = 3)"]
75
+ MODEL_DB.reset
76
+
77
+ o.y = 4
78
+ o.save_changes
79
+ MODEL_DB.sqls.should == ["UPDATE items SET y = 4 WHERE (id = 3)"]
80
+ o.save_changes
81
+ o.save_changes
82
+ MODEL_DB.sqls.should == ["UPDATE items SET y = 4 WHERE (id = 3)"]
83
+ end
84
+
85
+ end
86
+
87
+ describe "Model#set" do
88
+
89
+ before(:each) do
90
+ MODEL_DB.reset
91
+
92
+ @c = Class.new(Sequel::Model(:items)) do
93
+ def columns
94
+ [:id, :x, :y]
95
+ end
96
+ end
97
+ end
98
+
99
+ it "should generate an update statement" do
100
+ o = @c.new(:id => 1)
101
+ o.set(:x => 1)
102
+ MODEL_DB.sqls.first.should == "UPDATE items SET x = 1 WHERE (id = 1)"
103
+ end
104
+
105
+ it "should update attribute values" do
106
+ o = @c.new(:id => 1)
107
+ o.x.should be_nil
108
+ o.set(:x => 1)
109
+ o.x.should == 1
110
+ end
111
+
112
+ it "should be aliased by #update" do
113
+ o = @c.new(:id => 1)
114
+ o.update(:x => 1)
115
+ MODEL_DB.sqls.first.should == "UPDATE items SET x = 1 WHERE (id = 1)"
116
+ end
117
+ end
118
+
119
+
120
+ describe "Model#new?" do
121
+
122
+ before(:each) do
123
+ MODEL_DB.reset
124
+
125
+ @c = Class.new(Sequel::Model(:items)) do
126
+ end
127
+ end
128
+
129
+ it "should be true for a new instance" do
130
+ n = @c.new(:x => 1)
131
+ n.should be_new
132
+ end
133
+
134
+ it "should be false after saving" do
135
+ n = @c.new(:x => 1)
136
+ n.save
137
+ n.should_not be_new
138
+ end
139
+
140
+ it "should alias new_record? to new?" do
141
+ n = @c.new(:x => 1)
142
+ n.should respond_to(:new_record?)
143
+ n.should be_new_record
144
+ n.save
145
+ n.should_not be_new_record
146
+ end
147
+
148
+ end
149
+
150
+ describe Sequel::Model, "w/ primary key" do
151
+
152
+ it "should default to ':id'" do
153
+ model_a = Class.new Sequel::Model
154
+ model_a.primary_key.should be_equal(:id)
155
+ end
156
+
157
+ it "should be changed through 'set_primary_key'" do
158
+ model_a = Class.new(Sequel::Model) { set_primary_key :a }
159
+ model_a.primary_key.should be_equal(:a)
160
+ end
161
+
162
+ it "should support multi argument composite keys" do
163
+ model_a = Class.new(Sequel::Model) { set_primary_key :a, :b }
164
+ model_a.primary_key.should be_eql([:a, :b])
165
+ end
166
+
167
+ it "should accept single argument composite keys" do
168
+ model_a = Class.new(Sequel::Model) { set_primary_key [:a, :b] }
169
+ model_a.primary_key.should be_eql([:a, :b])
170
+ end
171
+
172
+ end
173
+
174
+ describe Sequel::Model, "w/o primary key" do
175
+ it "should return nil for primary key" do
176
+ Class.new(Sequel::Model) { no_primary_key }.primary_key.should be_nil
177
+ end
178
+
179
+ it "should raise a Sequel::Error on 'this'" do
180
+ instance = Class.new(Sequel::Model) { no_primary_key }.new
181
+ proc { instance.this }.should raise_error(Sequel::Error)
182
+ end
183
+ end
184
+
185
+ describe Sequel::Model, "with this" do
186
+
187
+ before { @example = Class.new Sequel::Model(:examples) }
188
+
189
+ it "should return a dataset identifying the record" do
190
+ instance = @example.new :id => 3
191
+ instance.this.sql.should be_eql("SELECT * FROM examples WHERE (id = 3) LIMIT 1")
192
+ end
193
+
194
+ it "should support arbitary primary keys" do
195
+ @example.set_primary_key :a
196
+
197
+ instance = @example.new :a => 3
198
+ instance.this.sql.should be_eql("SELECT * FROM examples WHERE (a = 3) LIMIT 1")
199
+ end
200
+
201
+ it "should support composite primary keys" do
202
+ @example.set_primary_key :x, :y
203
+ instance = @example.new :x => 4, :y => 5
204
+
205
+ parts = [
206
+ 'SELECT * FROM examples WHERE %s LIMIT 1',
207
+ '(x = 4) AND (y = 5)',
208
+ '(y = 5) AND (x = 4)'
209
+ ].map { |expr| Regexp.escape expr }
210
+ regexp = Regexp.new parts.first % "(?:#{parts[1]}|#{parts[2]})"
211
+
212
+ instance.this.sql.should match(regexp)
213
+ end
214
+
215
+ end
216
+
217
+ describe "Model#pk" do
218
+
219
+ before(:each) do
220
+ @m = Class.new(Sequel::Model)
221
+ end
222
+
223
+ it "should be default return the value of the :id column" do
224
+ m = @m.new(:id => 111, :x => 2, :y => 3)
225
+ m.pk.should == 111
226
+ end
227
+
228
+ it "should be return the primary key value for custom primary key" do
229
+ @m.set_primary_key :x
230
+ m = @m.new(:id => 111, :x => 2, :y => 3)
231
+ m.pk.should == 2
232
+ end
233
+
234
+ it "should be return the primary key value for composite primary key" do
235
+ @m.set_primary_key [:y, :x]
236
+ m = @m.new(:id => 111, :x => 2, :y => 3)
237
+ m.pk.should == [3, 2]
238
+ end
239
+
240
+ it "should raise if no primary key" do
241
+ @m.set_primary_key nil
242
+ m = @m.new(:id => 111, :x => 2, :y => 3)
243
+ proc {m.pk}.should raise_error(Sequel::Error)
244
+
245
+ @m.no_primary_key
246
+ m = @m.new(:id => 111, :x => 2, :y => 3)
247
+ proc {m.pk}.should raise_error(Sequel::Error)
248
+ end
249
+
250
+ end
251
+
252
+ describe "Model#pk_hash" do
253
+
254
+ before(:each) do
255
+ @m = Class.new(Sequel::Model)
256
+ end
257
+
258
+ it "should be default return the value of the :id column" do
259
+ m = @m.new(:id => 111, :x => 2, :y => 3)
260
+ m.pk_hash.should == {:id => 111}
261
+ end
262
+
263
+ it "should be return the primary key value for custom primary key" do
264
+ @m.set_primary_key :x
265
+ m = @m.new(:id => 111, :x => 2, :y => 3)
266
+ m.pk_hash.should == {:x => 2}
267
+ end
268
+
269
+ it "should be return the primary key value for composite primary key" do
270
+ @m.set_primary_key [:y, :x]
271
+ m = @m.new(:id => 111, :x => 2, :y => 3)
272
+ m.pk_hash.should == {:y => 3, :x => 2}
273
+ end
274
+
275
+ it "should raise if no primary key" do
276
+ @m.set_primary_key nil
277
+ m = @m.new(:id => 111, :x => 2, :y => 3)
278
+ proc {m.pk_hash}.should raise_error(Sequel::Error)
279
+
280
+ @m.no_primary_key
281
+ m = @m.new(:id => 111, :x => 2, :y => 3)
282
+ proc {m.pk_hash}.should raise_error(Sequel::Error)
283
+ end
284
+ end
285
+
286
+ describe Sequel::Model, "create_with_params" do
287
+
288
+ before(:each) do
289
+ MODEL_DB.reset
290
+
291
+ @c = Class.new(Sequel::Model(:items)) do
292
+ def self.columns; [:x, :y]; end
293
+ end
294
+ end
295
+
296
+ it "should filter the given params using the model columns" do
297
+ @c.create_with_params(:x => 1, :z => 2)
298
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
299
+
300
+ MODEL_DB.reset
301
+ @c.create_with_params(:y => 1, :abc => 2)
302
+ MODEL_DB.sqls.first.should == "INSERT INTO items (y) VALUES (1)"
303
+ end
304
+
305
+ it "should be aliased by create_with" do
306
+ @c.create_with(:x => 1, :z => 2)
307
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
308
+
309
+ MODEL_DB.reset
310
+ @c.create_with(:y => 1, :abc => 2)
311
+ MODEL_DB.sqls.first.should == "INSERT INTO items (y) VALUES (1)"
312
+ end
313
+
314
+ end
315
+
316
+ describe Sequel::Model, "#destroy" do
317
+
318
+ before(:each) do
319
+ MODEL_DB.reset
320
+ @model = Class.new(Sequel::Model(:items))
321
+ @model.dataset.meta_def(:delete) {MODEL_DB.execute delete_sql}
322
+
323
+ @instance = @model.new(:id => 1234)
324
+ #@model.stub!(:delete).and_return(:true)
325
+ end
326
+
327
+ it "should run within a transaction" do
328
+ @model.db.should_receive(:transaction)
329
+ @instance.destroy
330
+ end
331
+
332
+ it "should run before_destroy and after_destroy hooks" do
333
+ @model.before_destroy {MODEL_DB.execute('before blah')}
334
+ @model.after_destroy {MODEL_DB.execute('after blah')}
335
+ @instance.destroy
336
+
337
+ MODEL_DB.sqls.should == [
338
+ "before blah",
339
+ "DELETE FROM items WHERE (id = 1234)",
340
+ "after blah"
341
+ ]
342
+ end
343
+ end
344
+
345
+ describe Sequel::Model, "#exists?" do
346
+
347
+ before(:each) do
348
+ @model = Class.new(Sequel::Model(:items))
349
+ @model_a = @model.new
350
+ end
351
+
352
+ it "should returns true when current instance exists" do
353
+ @model_a.exists?.should be_true
354
+ end
355
+
356
+ it "should return false when the current instance does not exist" do
357
+ pending("how would this be false?")
358
+ end
359
+
360
+ end
@@ -0,0 +1,148 @@
1
+ describe Sequel::Model, "one_to_one" do
2
+
3
+ before(:each) do
4
+ MODEL_DB.reset
5
+
6
+ @c1 = Class.new(Sequel::Model(:attributes)) do
7
+ end
8
+
9
+ @c2 = Class.new(Sequel::Model(:nodes)) do
10
+ end
11
+
12
+ @dataset = @c2.dataset
13
+
14
+ $sqls = []
15
+ @dataset.extend(Module.new {
16
+ def fetch_rows(sql)
17
+ $sqls << sql
18
+ yield({:hey => 1})
19
+ end
20
+
21
+ def update(values)
22
+ $sqls << update_sql(values)
23
+ end
24
+ }
25
+ )
26
+ end
27
+
28
+ it "should use implicit key if omitted" do
29
+ @c2.one_to_one :parent, :from => @c2
30
+
31
+ d = @c2.new(:id => 1, :parent_id => 234)
32
+ p = d.parent
33
+ p.class.should == @c2
34
+ p.values.should == {:hey => 1}
35
+
36
+ $sqls.should == ["SELECT * FROM nodes WHERE (id = 234) LIMIT 1"]
37
+ end
38
+
39
+ it "should use explicit key if given" do
40
+ @c2.one_to_one :parent, :from => @c2, :key => :blah
41
+
42
+ d = @c2.new(:id => 1, :blah => 567)
43
+ p = d.parent
44
+ p.class.should == @c2
45
+ p.values.should == {:hey => 1}
46
+
47
+ $sqls.should == ["SELECT * FROM nodes WHERE (id = 567) LIMIT 1"]
48
+ end
49
+
50
+ it "should support plain dataset in the from option" do
51
+ @c2.one_to_one :parent, :from => MODEL_DB[:xyz]
52
+
53
+ d = @c2.new(:id => 1, :parent_id => 789)
54
+ p = d.parent
55
+ p.class.should == Hash
56
+
57
+ MODEL_DB.sqls.should == ["SELECT * FROM xyz WHERE (id = 789) LIMIT 1"]
58
+ end
59
+
60
+ it "should support table name in the from option" do
61
+ @c2.one_to_one :parent, :from => :abc
62
+
63
+ d = @c2.new(:id => 1, :parent_id => 789)
64
+ p = d.parent
65
+ p.class.should == Hash
66
+
67
+ MODEL_DB.sqls.should == ["SELECT * FROM abc WHERE (id = 789) LIMIT 1"]
68
+ end
69
+
70
+ it "should return nil if key value is nil" do
71
+ @c2.one_to_one :parent, :from => @c2
72
+
73
+ d = @c2.new(:id => 1)
74
+ d.parent.should == nil
75
+ end
76
+
77
+ it "should define a setter method" do
78
+ @c2.one_to_one :parent, :from => @c2
79
+
80
+ d = @c2.new(:id => 1)
81
+ d.parent = {:id => 4321}
82
+ d.values.should == {:id => 1, :parent_id => 4321}
83
+ $sqls.last.should == "UPDATE nodes SET parent_id = 4321 WHERE (id = 1)"
84
+
85
+ d.parent = nil
86
+ d.values.should == {:id => 1, :parent_id => nil}
87
+ $sqls.last.should == "UPDATE nodes SET parent_id = NULL WHERE (id = 1)"
88
+
89
+ e = @c2.new(:id => 6677)
90
+ d.parent = e
91
+ d.values.should == {:id => 1, :parent_id => 6677}
92
+ $sqls.last.should == "UPDATE nodes SET parent_id = 6677 WHERE (id = 1)"
93
+ end
94
+
95
+ it "should warn with a depreciation notice if :class option was used" do
96
+ pending("write this spec")
97
+ end
98
+
99
+ end
100
+
101
+ describe Sequel::Model, "one_to_many" do
102
+
103
+ before(:each) do
104
+ MODEL_DB.reset
105
+
106
+ @c1 = Class.new(Sequel::Model(:attributes)) do
107
+ end
108
+
109
+ @c2 = Class.new(Sequel::Model(:nodes)) do
110
+ end
111
+ end
112
+
113
+ it "should define a getter method" do
114
+ @c2.one_to_many :attributes, :from => @c1, :key => :node_id
115
+
116
+ n = @c2.new(:id => 1234)
117
+ a = n.attributes
118
+ a.should be_a_kind_of(Sequel::Dataset)
119
+ a.sql.should == 'SELECT * FROM attributes WHERE (node_id = 1234)'
120
+ end
121
+
122
+ it "should support plain dataset in the from option" do
123
+ @c2.one_to_many :attributes, :from => MODEL_DB[:xyz], :key => :node_id
124
+
125
+ n = @c2.new(:id => 1234)
126
+ a = n.attributes
127
+ a.should be_a_kind_of(Sequel::Dataset)
128
+ a.sql.should == 'SELECT * FROM xyz WHERE (node_id = 1234)'
129
+ end
130
+
131
+ it "should support table name in the from option" do
132
+ @c2.one_to_many :attributes, :from => :abc, :key => :node_id
133
+
134
+ n = @c2.new(:id => 1234)
135
+ a = n.attributes
136
+ a.should be_a_kind_of(Sequel::Dataset)
137
+ a.sql.should == 'SELECT * FROM abc WHERE (node_id = 1234)'
138
+ end
139
+
140
+ it "should warn with a depreciation notice if :class option was used" do
141
+ pending("write this spec")
142
+ end
143
+
144
+ it "should warn with a depreciation notice if :on option was used" do
145
+ pending("write this spec")
146
+ end
147
+
148
+ end