epugh-sequel 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. data/README.rdoc +652 -0
  2. data/VERSION.yml +4 -0
  3. data/bin/sequel +104 -0
  4. data/lib/sequel.rb +1 -0
  5. data/lib/sequel/adapters/ado.rb +85 -0
  6. data/lib/sequel/adapters/db2.rb +132 -0
  7. data/lib/sequel/adapters/dbi.rb +101 -0
  8. data/lib/sequel/adapters/do.rb +197 -0
  9. data/lib/sequel/adapters/do/mysql.rb +38 -0
  10. data/lib/sequel/adapters/do/postgres.rb +92 -0
  11. data/lib/sequel/adapters/do/sqlite.rb +31 -0
  12. data/lib/sequel/adapters/firebird.rb +307 -0
  13. data/lib/sequel/adapters/informix.rb +75 -0
  14. data/lib/sequel/adapters/jdbc.rb +485 -0
  15. data/lib/sequel/adapters/jdbc/h2.rb +62 -0
  16. data/lib/sequel/adapters/jdbc/mysql.rb +56 -0
  17. data/lib/sequel/adapters/jdbc/oracle.rb +23 -0
  18. data/lib/sequel/adapters/jdbc/postgresql.rb +101 -0
  19. data/lib/sequel/adapters/jdbc/sqlite.rb +43 -0
  20. data/lib/sequel/adapters/mysql.rb +370 -0
  21. data/lib/sequel/adapters/odbc.rb +184 -0
  22. data/lib/sequel/adapters/openbase.rb +57 -0
  23. data/lib/sequel/adapters/oracle.rb +140 -0
  24. data/lib/sequel/adapters/postgres.rb +453 -0
  25. data/lib/sequel/adapters/shared/mssql.rb +93 -0
  26. data/lib/sequel/adapters/shared/mysql.rb +341 -0
  27. data/lib/sequel/adapters/shared/oracle.rb +62 -0
  28. data/lib/sequel/adapters/shared/postgres.rb +743 -0
  29. data/lib/sequel/adapters/shared/progress.rb +34 -0
  30. data/lib/sequel/adapters/shared/sqlite.rb +263 -0
  31. data/lib/sequel/adapters/sqlite.rb +243 -0
  32. data/lib/sequel/adapters/utils/date_format.rb +21 -0
  33. data/lib/sequel/adapters/utils/stored_procedures.rb +75 -0
  34. data/lib/sequel/adapters/utils/unsupported.rb +62 -0
  35. data/lib/sequel/connection_pool.rb +258 -0
  36. data/lib/sequel/core.rb +204 -0
  37. data/lib/sequel/core_sql.rb +185 -0
  38. data/lib/sequel/database.rb +687 -0
  39. data/lib/sequel/database/schema_generator.rb +324 -0
  40. data/lib/sequel/database/schema_methods.rb +164 -0
  41. data/lib/sequel/database/schema_sql.rb +324 -0
  42. data/lib/sequel/dataset.rb +422 -0
  43. data/lib/sequel/dataset/convenience.rb +237 -0
  44. data/lib/sequel/dataset/prepared_statements.rb +220 -0
  45. data/lib/sequel/dataset/sql.rb +1105 -0
  46. data/lib/sequel/deprecated.rb +529 -0
  47. data/lib/sequel/exceptions.rb +44 -0
  48. data/lib/sequel/extensions/blank.rb +42 -0
  49. data/lib/sequel/extensions/inflector.rb +288 -0
  50. data/lib/sequel/extensions/pagination.rb +96 -0
  51. data/lib/sequel/extensions/pretty_table.rb +78 -0
  52. data/lib/sequel/extensions/query.rb +48 -0
  53. data/lib/sequel/extensions/string_date_time.rb +47 -0
  54. data/lib/sequel/metaprogramming.rb +44 -0
  55. data/lib/sequel/migration.rb +212 -0
  56. data/lib/sequel/model.rb +142 -0
  57. data/lib/sequel/model/association_reflection.rb +263 -0
  58. data/lib/sequel/model/associations.rb +1024 -0
  59. data/lib/sequel/model/base.rb +911 -0
  60. data/lib/sequel/model/deprecated.rb +188 -0
  61. data/lib/sequel/model/deprecated_hooks.rb +103 -0
  62. data/lib/sequel/model/deprecated_inflector.rb +335 -0
  63. data/lib/sequel/model/deprecated_validations.rb +384 -0
  64. data/lib/sequel/model/errors.rb +37 -0
  65. data/lib/sequel/model/exceptions.rb +7 -0
  66. data/lib/sequel/model/inflections.rb +230 -0
  67. data/lib/sequel/model/plugins.rb +74 -0
  68. data/lib/sequel/object_graph.rb +230 -0
  69. data/lib/sequel/plugins/caching.rb +122 -0
  70. data/lib/sequel/plugins/hook_class_methods.rb +122 -0
  71. data/lib/sequel/plugins/schema.rb +53 -0
  72. data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
  73. data/lib/sequel/plugins/validation_class_methods.rb +373 -0
  74. data/lib/sequel/sql.rb +854 -0
  75. data/lib/sequel/version.rb +11 -0
  76. data/lib/sequel_core.rb +1 -0
  77. data/lib/sequel_model.rb +1 -0
  78. data/spec/adapters/ado_spec.rb +46 -0
  79. data/spec/adapters/firebird_spec.rb +376 -0
  80. data/spec/adapters/informix_spec.rb +96 -0
  81. data/spec/adapters/mysql_spec.rb +875 -0
  82. data/spec/adapters/oracle_spec.rb +272 -0
  83. data/spec/adapters/postgres_spec.rb +692 -0
  84. data/spec/adapters/spec_helper.rb +10 -0
  85. data/spec/adapters/sqlite_spec.rb +550 -0
  86. data/spec/core/connection_pool_spec.rb +526 -0
  87. data/spec/core/core_ext_spec.rb +156 -0
  88. data/spec/core/core_sql_spec.rb +528 -0
  89. data/spec/core/database_spec.rb +1214 -0
  90. data/spec/core/dataset_spec.rb +3513 -0
  91. data/spec/core/expression_filters_spec.rb +363 -0
  92. data/spec/core/migration_spec.rb +261 -0
  93. data/spec/core/object_graph_spec.rb +280 -0
  94. data/spec/core/pretty_table_spec.rb +58 -0
  95. data/spec/core/schema_generator_spec.rb +167 -0
  96. data/spec/core/schema_spec.rb +778 -0
  97. data/spec/core/spec_helper.rb +82 -0
  98. data/spec/core/version_spec.rb +7 -0
  99. data/spec/extensions/blank_spec.rb +67 -0
  100. data/spec/extensions/caching_spec.rb +201 -0
  101. data/spec/extensions/hook_class_methods_spec.rb +470 -0
  102. data/spec/extensions/inflector_spec.rb +122 -0
  103. data/spec/extensions/pagination_spec.rb +99 -0
  104. data/spec/extensions/pretty_table_spec.rb +91 -0
  105. data/spec/extensions/query_spec.rb +85 -0
  106. data/spec/extensions/schema_spec.rb +111 -0
  107. data/spec/extensions/single_table_inheritance_spec.rb +53 -0
  108. data/spec/extensions/spec_helper.rb +90 -0
  109. data/spec/extensions/string_date_time_spec.rb +93 -0
  110. data/spec/extensions/validation_class_methods_spec.rb +1054 -0
  111. data/spec/integration/dataset_test.rb +160 -0
  112. data/spec/integration/eager_loader_test.rb +683 -0
  113. data/spec/integration/prepared_statement_test.rb +130 -0
  114. data/spec/integration/schema_test.rb +183 -0
  115. data/spec/integration/spec_helper.rb +75 -0
  116. data/spec/integration/type_test.rb +96 -0
  117. data/spec/model/association_reflection_spec.rb +93 -0
  118. data/spec/model/associations_spec.rb +1780 -0
  119. data/spec/model/base_spec.rb +494 -0
  120. data/spec/model/caching_spec.rb +217 -0
  121. data/spec/model/dataset_methods_spec.rb +78 -0
  122. data/spec/model/eager_loading_spec.rb +1165 -0
  123. data/spec/model/hooks_spec.rb +472 -0
  124. data/spec/model/inflector_spec.rb +126 -0
  125. data/spec/model/model_spec.rb +588 -0
  126. data/spec/model/plugins_spec.rb +142 -0
  127. data/spec/model/record_spec.rb +1243 -0
  128. data/spec/model/schema_spec.rb +92 -0
  129. data/spec/model/spec_helper.rb +124 -0
  130. data/spec/model/validations_spec.rb +1080 -0
  131. data/spec/rcov.opts +6 -0
  132. data/spec/spec.opts +0 -0
  133. data/spec/spec_config.rb.example +10 -0
  134. metadata +202 -0
@@ -0,0 +1,142 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ module Sequel::Plugins
4
+
5
+ module Timestamped
6
+ def self.apply(m, opts)
7
+ m.meta_def(:stamp_opts) {opts}
8
+ m.send(:define_method, :before_save){@values[:stamp] = Time.now}
9
+ end
10
+
11
+ module InstanceMethods
12
+ def get_stamp(*args); @values[:stamp] end
13
+ def abc; timestamped_opts; end
14
+ end
15
+
16
+ module ClassMethods
17
+ def deff; timestamped_opts; end
18
+ end
19
+
20
+ module DatasetMethods
21
+ def ghi; timestamped_opts; end
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ describe Sequel::Model, "using a plugin" do
28
+
29
+ it "should fail if the plugin is not found" do
30
+ proc do
31
+ c = Class.new(Sequel::Model)
32
+ c.class_eval do
33
+ plugin :something_or_other
34
+ end
35
+ end.should raise_error(LoadError)
36
+ end
37
+
38
+ it "should apply the plugin to the class" do
39
+ c = nil
40
+ proc do
41
+ c = Class.new(Sequel::Model)
42
+ c.class_eval do
43
+ set_dataset MODEL_DB[:items]
44
+ plugin :timestamped, :a => 1, :b => 2
45
+ end
46
+ end.should_not raise_error(LoadError)
47
+
48
+ c.should respond_to(:stamp_opts)
49
+ c.stamp_opts.should == {:a => 1, :b => 2}
50
+
51
+ # instance methods
52
+ m = c.new
53
+ m.should respond_to(:get_stamp)
54
+ m.should respond_to(:abc)
55
+ m.abc.should == {:a => 1, :b => 2}
56
+ t = Time.now
57
+ m[:stamp] = t
58
+ m.get_stamp.should == t
59
+
60
+ # class methods
61
+ c.should respond_to(:deff)
62
+ c.deff.should == {:a => 1, :b => 2}
63
+
64
+ # dataset methods
65
+ c.dataset.should respond_to(:ghi)
66
+ c.dataset.ghi.should == {:a => 1, :b => 2}
67
+
68
+ # dataset methods called on the class
69
+ c.should respond_to(:ghi)
70
+ c.ghi.should == {:a => 1, :b => 2}
71
+ end
72
+
73
+ deprec_specify "should have an .is alias" do
74
+ c = nil
75
+ proc do
76
+ c = Class.new(Sequel::Model)
77
+ c.class_eval do
78
+ set_dataset MODEL_DB[:items]
79
+ is :timestamped, :a => 1, :b => 2
80
+ end
81
+ end.should_not raise_error(LoadError)
82
+
83
+ c.should respond_to(:stamp_opts)
84
+ c.stamp_opts.should == {:a => 1, :b => 2}
85
+
86
+ # instance methods
87
+ m = c.new
88
+ m.should respond_to(:get_stamp)
89
+ m.should respond_to(:abc)
90
+ m.abc.should == {:a => 1, :b => 2}
91
+ t = Time.now
92
+ m[:stamp] = t
93
+ m.get_stamp.should == t
94
+
95
+ # class methods
96
+ c.should respond_to(:deff)
97
+ c.deff.should == {:a => 1, :b => 2}
98
+
99
+ # dataset methods
100
+ c.dataset.should respond_to(:ghi)
101
+ c.dataset.ghi.should == {:a => 1, :b => 2}
102
+
103
+ # dataset methods called on the class
104
+ c.should respond_to(:ghi)
105
+ c.ghi.should == {:a => 1, :b => 2}
106
+ end
107
+
108
+ deprec_specify "should have an .is_a alias" do
109
+ c = nil
110
+ proc do
111
+ c = Class.new(Sequel::Model)
112
+ c.class_eval do
113
+ set_dataset MODEL_DB[:items]
114
+ is_a :timestamped, :a => 1, :b => 2
115
+ end
116
+ end.should_not raise_error(LoadError)
117
+
118
+ c.should respond_to(:stamp_opts)
119
+ c.stamp_opts.should == {:a => 1, :b => 2}
120
+
121
+ # instance methods
122
+ m = c.new
123
+ m.should respond_to(:get_stamp)
124
+ m.should respond_to(:abc)
125
+ m.abc.should == {:a => 1, :b => 2}
126
+ t = Time.now
127
+ m[:stamp] = t
128
+ m.get_stamp.should == t
129
+
130
+ # class methods
131
+ c.should respond_to(:deff)
132
+ c.deff.should == {:a => 1, :b => 2}
133
+
134
+ # dataset methods
135
+ c.dataset.should respond_to(:ghi)
136
+ c.dataset.ghi.should == {:a => 1, :b => 2}
137
+
138
+ # dataset methods called on the class
139
+ c.should respond_to(:ghi)
140
+ c.ghi.should == {:a => 1, :b => 2}
141
+ end
142
+ end
@@ -0,0 +1,1243 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ describe "Model#save" do
4
+
5
+ before(:each) do
6
+ @c = Class.new(Sequel::Model(:items)) do
7
+ columns :id, :x, :y
8
+ end
9
+ MODEL_DB.reset
10
+ end
11
+
12
+ it "should insert a record for a new model instance" do
13
+ o = @c.new(:x => 1)
14
+ o.save
15
+
16
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
17
+ end
18
+
19
+ it "should use dataset's insert_select method if present" do
20
+ ds = @c.dataset = @c.dataset.clone
21
+ def ds.insert_select(hash)
22
+ execute("INSERT INTO items (y) VALUES (2)")
23
+ {:y=>2}
24
+ end
25
+ o = @c.new(:x => 1)
26
+ o.save
27
+
28
+ o.values.should == {:y=>2}
29
+ MODEL_DB.sqls.first.should == "INSERT INTO items (y) VALUES (2)"
30
+ end
31
+
32
+ it "should update a record for an existing model instance" do
33
+ o = @c.load(:id => 3, :x => 1)
34
+ o.save
35
+
36
+ MODEL_DB.sqls.first.should =~
37
+ /UPDATE items SET (id = 3, x = 1|x = 1, id = 3) WHERE \(id = 3\)/
38
+ end
39
+
40
+ it "should update only the given columns if given" do
41
+ o = @c.load(:id => 3, :x => 1, :y => nil)
42
+ o.save(:y)
43
+ MODEL_DB.sqls.first.should == "UPDATE items SET y = NULL WHERE (id = 3)"
44
+ end
45
+
46
+ it "should mark saved columns as not changed" do
47
+ o = @c.load(:id => 3, :x => 1, :y => nil)
48
+ o[:y] = 4
49
+ o.changed_columns.should == [:y]
50
+ o.save(:x)
51
+ o.changed_columns.should == [:y]
52
+ o.save(:y)
53
+ o.changed_columns.should == []
54
+ end
55
+
56
+ it "should store previous value of @new in @was_new and as well as the hash used for updating in @columns_updated until after hooks finish running" do
57
+ res = nil
58
+ @c.send(:define_method, :after_save){ res = [@columns_updated, @was_new]}
59
+ o = @c.new(:x => 1, :y => nil)
60
+ o[:x] = 2
61
+ o.save
62
+ res.should == [nil, true]
63
+ o.after_save
64
+ res.should == [nil, nil]
65
+
66
+ res = nil
67
+ o = @c.load(:id => 23,:x => 1, :y => nil)
68
+ o[:x] = 2
69
+ o.save
70
+ res.should == [{:id => 23,:x => 2, :y => nil}, nil]
71
+ o.after_save
72
+ res.should == [nil, nil]
73
+
74
+ res = nil
75
+ o = @c.load(:id => 23,:x => 2, :y => nil)
76
+ o[:x] = 2
77
+ o[:y] = 22
78
+ o.save(:x)
79
+ res.should == [{:x=>2},nil]
80
+ o.after_save
81
+ res.should == [nil, nil]
82
+ end
83
+
84
+ it "should use Model's save_in_transaction setting by default" do
85
+ @c.use_transactions = true
86
+ @c.load(:id => 3, :x => 1, :y => nil).save(:y)
87
+ MODEL_DB.sqls.should == ["BEGIN", "UPDATE items SET y = NULL WHERE (id = 3)", "COMMIT"]
88
+ MODEL_DB.reset
89
+ @c.use_transactions = false
90
+ @c.load(:id => 3, :x => 1, :y => nil).save(:y)
91
+ MODEL_DB.sqls.should == ["UPDATE items SET y = NULL WHERE (id = 3)"]
92
+ MODEL_DB.reset
93
+ end
94
+
95
+ it "should inherit Model's save_in_transaction setting" do
96
+ @c.use_transactions = true
97
+ Class.new(@c).load(:id => 3, :x => 1, :y => nil).save(:y)
98
+ MODEL_DB.sqls.should == ["BEGIN", "UPDATE items SET y = NULL WHERE (id = 3)", "COMMIT"]
99
+ MODEL_DB.reset
100
+ @c.use_transactions = false
101
+ Class.new(@c).load(:id => 3, :x => 1, :y => nil).save(:y)
102
+ MODEL_DB.sqls.should == ["UPDATE items SET y = NULL WHERE (id = 3)"]
103
+ MODEL_DB.reset
104
+ end
105
+
106
+ it "should use object's save_in_transaction setting" do
107
+ o = @c.load(:id => 3, :x => 1, :y => nil)
108
+ o.use_transactions = false
109
+ @c.use_transactions = true
110
+ o.save(:y)
111
+ MODEL_DB.sqls.should == ["UPDATE items SET y = NULL WHERE (id = 3)"]
112
+ MODEL_DB.reset
113
+ o = @c.load(:id => 3, :x => 1, :y => nil)
114
+ o.use_transactions = true
115
+ @c.use_transactions = false
116
+ o.save(:y)
117
+ MODEL_DB.sqls.should == ["BEGIN", "UPDATE items SET y = NULL WHERE (id = 3)", "COMMIT"]
118
+ MODEL_DB.reset
119
+ end
120
+
121
+ it "should use :transaction option if given" do
122
+ o = @c.load(:id => 3, :x => 1, :y => nil)
123
+ o.use_transactions = true
124
+ o.save(:y, :transaction=>false)
125
+ MODEL_DB.sqls.should == ["UPDATE items SET y = NULL WHERE (id = 3)"]
126
+ MODEL_DB.reset
127
+ o = @c.load(:id => 3, :x => 1, :y => nil)
128
+ o.use_transactions = false
129
+ o.save(:y, :transaction=>true)
130
+ MODEL_DB.sqls.should == ["BEGIN", "UPDATE items SET y = NULL WHERE (id = 3)", "COMMIT"]
131
+ MODEL_DB.reset
132
+ end
133
+ end
134
+
135
+ describe "Model#save_changes" do
136
+
137
+ before(:each) do
138
+ MODEL_DB.reset
139
+
140
+ @c = Class.new(Sequel::Model(:items)) do
141
+ unrestrict_primary_key
142
+ columns :id, :x, :y
143
+ end
144
+ end
145
+
146
+ it "should do nothing if no changed columns" do
147
+ o = @c.new(:id => 3, :x => 1, :y => nil)
148
+ o.save_changes
149
+
150
+ MODEL_DB.sqls.should be_empty
151
+
152
+ o = @c.load(:id => 3, :x => 1, :y => nil)
153
+ o.save_changes
154
+
155
+ MODEL_DB.sqls.should be_empty
156
+ end
157
+
158
+ it "should update only changed columns" do
159
+ o = @c.load(:id => 3, :x => 1, :y => nil)
160
+ o.x = 2
161
+
162
+ o.save_changes
163
+ MODEL_DB.sqls.should == ["UPDATE items SET x = 2 WHERE (id = 3)"]
164
+ o.save_changes
165
+ o.save_changes
166
+ MODEL_DB.sqls.should == ["UPDATE items SET x = 2 WHERE (id = 3)"]
167
+ MODEL_DB.reset
168
+
169
+ o.y = 4
170
+ o.save_changes
171
+ MODEL_DB.sqls.should == ["UPDATE items SET y = 4 WHERE (id = 3)"]
172
+ o.save_changes
173
+ o.save_changes
174
+ MODEL_DB.sqls.should == ["UPDATE items SET y = 4 WHERE (id = 3)"]
175
+ end
176
+
177
+ it "should not consider columns changed if the values did not change" do
178
+ o = @c.load(:id => 3, :x => 1, :y => nil)
179
+ o.x = 1
180
+
181
+ o.save_changes
182
+ MODEL_DB.sqls.should == []
183
+ o.x = 3
184
+ o.save_changes
185
+ MODEL_DB.sqls.should == ["UPDATE items SET x = 3 WHERE (id = 3)"]
186
+ MODEL_DB.reset
187
+
188
+ o[:y] = nil
189
+ o.save_changes
190
+ MODEL_DB.sqls.should == []
191
+ o[:y] = 4
192
+ o.save_changes
193
+ MODEL_DB.sqls.should == ["UPDATE items SET y = 4 WHERE (id = 3)"]
194
+ end
195
+
196
+ it "should update columns changed in a before_update hook" do
197
+ o = @c.load(:id => 3, :x => 1, :y => nil)
198
+ @c.send(:define_method, :before_update){self.x += 1}
199
+ o.save_changes
200
+ MODEL_DB.sqls.should == []
201
+ o.x = 2
202
+ o.save_changes
203
+ MODEL_DB.sqls.should == ["UPDATE items SET x = 3 WHERE (id = 3)"]
204
+ MODEL_DB.reset
205
+ o.save_changes
206
+ MODEL_DB.sqls.should == []
207
+ o.x = 4
208
+ o.save_changes
209
+ MODEL_DB.sqls.should == ["UPDATE items SET x = 5 WHERE (id = 3)"]
210
+ MODEL_DB.reset
211
+ end
212
+
213
+ it "should update columns changed in a before_save hook" do
214
+ o = @c.load(:id => 3, :x => 1, :y => nil)
215
+ @c.send(:define_method, :before_update){self.x += 1}
216
+ o.save_changes
217
+ MODEL_DB.sqls.should == []
218
+ o.x = 2
219
+ o.save_changes
220
+ MODEL_DB.sqls.should == ["UPDATE items SET x = 3 WHERE (id = 3)"]
221
+ MODEL_DB.reset
222
+ o.save_changes
223
+ MODEL_DB.sqls.should == []
224
+ o.x = 4
225
+ o.save_changes
226
+ MODEL_DB.sqls.should == ["UPDATE items SET x = 5 WHERE (id = 3)"]
227
+ MODEL_DB.reset
228
+ end
229
+ end
230
+
231
+ describe "Model#update_values" do
232
+ before(:each) do
233
+ MODEL_DB.reset
234
+
235
+ @c = Class.new(Sequel::Model(:items)) do
236
+ unrestrict_primary_key
237
+ columns :id, :x, :y
238
+ end
239
+ end
240
+
241
+ deprec_specify "should generate an update statement" do
242
+ o = @c.new(:id => 1)
243
+ o.update_values(:x => 1)
244
+ MODEL_DB.sqls.first.should == "UPDATE items SET x = 1 WHERE (id = 1)"
245
+ end
246
+
247
+ deprec_specify "should update attribute values" do
248
+ o = @c.new(:id => 1)
249
+ o.x.should be_nil
250
+ o.update_values(:x => 1)
251
+ o.x.should == 1
252
+ end
253
+
254
+ deprec_specify "should support string keys" do
255
+ o = @c.new(:id => 1)
256
+ o.x.should be_nil
257
+ o.update_values('x' => 1)
258
+ o.x.should == 1
259
+ MODEL_DB.sqls.first.should == "UPDATE items SET x = 1 WHERE (id = 1)"
260
+ end
261
+ end
262
+
263
+ describe "Model#set_values" do
264
+ before(:each) do
265
+ MODEL_DB.reset
266
+
267
+ @c = Class.new(Sequel::Model(:items)) do
268
+ unrestrict_primary_key
269
+ columns :id, :x, :y
270
+ end
271
+ end
272
+
273
+ deprec_specify "should not touch the database" do
274
+ o = @c.new(:id => 1)
275
+ o.set_values(:x => 1)
276
+ MODEL_DB.sqls.should == []
277
+ end
278
+
279
+ deprec_specify "should update attribute values" do
280
+ o = @c.new(:id => 1)
281
+ o.x.should be_nil
282
+ o.set_values(:x => 1)
283
+ o.x.should == 1
284
+ end
285
+
286
+ deprec_specify "should support string keys" do
287
+ o = @c.new(:id => 1)
288
+ o.x.should be_nil
289
+ o.set_values('x' => 1)
290
+ o.x.should == 1
291
+ end
292
+
293
+ deprec_specify "should raise an error if used with a non-String, non-Symbol key" do
294
+ proc{@c.new.set_values(1=>2)}.should raise_error(Sequel::Error)
295
+ end
296
+ end
297
+
298
+ describe "Model#new?" do
299
+
300
+ before(:each) do
301
+ MODEL_DB.reset
302
+
303
+ @c = Class.new(Sequel::Model(:items)) do
304
+ unrestrict_primary_key
305
+ columns :x
306
+ end
307
+ end
308
+
309
+ it "should be true for a new instance" do
310
+ n = @c.new(:x => 1)
311
+ n.should be_new
312
+ end
313
+
314
+ it "should be false after saving" do
315
+ n = @c.new(:x => 1)
316
+ n.save
317
+ n.should_not be_new
318
+ end
319
+ end
320
+
321
+ describe Sequel::Model, "w/ primary key" do
322
+
323
+ it "should default to ':id'" do
324
+ model_a = Class.new Sequel::Model
325
+ model_a.primary_key.should be_equal(:id)
326
+ end
327
+
328
+ it "should be changed through 'set_primary_key'" do
329
+ model_a = Class.new(Sequel::Model) { set_primary_key :a }
330
+ model_a.primary_key.should be_equal(:a)
331
+ end
332
+
333
+ it "should support multi argument composite keys" do
334
+ model_a = Class.new(Sequel::Model) { set_primary_key :a, :b }
335
+ model_a.primary_key.should be_eql([:a, :b])
336
+ end
337
+
338
+ it "should accept single argument composite keys" do
339
+ model_a = Class.new(Sequel::Model) { set_primary_key [:a, :b] }
340
+ model_a.primary_key.should be_eql([:a, :b])
341
+ end
342
+
343
+ end
344
+
345
+ describe Sequel::Model, "w/o primary key" do
346
+ it "should return nil for primary key" do
347
+ Class.new(Sequel::Model) { no_primary_key }.primary_key.should be_nil
348
+ end
349
+
350
+ it "should raise a Sequel::Error on 'this'" do
351
+ instance = Class.new(Sequel::Model) { no_primary_key }.new
352
+ proc { instance.this }.should raise_error(Sequel::Error)
353
+ end
354
+ end
355
+
356
+ describe Sequel::Model, "with this" do
357
+
358
+ before { @example = Class.new Sequel::Model(:examples); @example.columns :id, :a, :x, :y }
359
+
360
+ it "should return a dataset identifying the record" do
361
+ instance = @example.load :id => 3
362
+ instance.this.sql.should be_eql("SELECT * FROM examples WHERE (id = 3) LIMIT 1")
363
+ end
364
+
365
+ it "should support arbitary primary keys" do
366
+ @example.set_primary_key :a
367
+
368
+ instance = @example.load :a => 3
369
+ instance.this.sql.should be_eql("SELECT * FROM examples WHERE (a = 3) LIMIT 1")
370
+ end
371
+
372
+ it "should support composite primary keys" do
373
+ @example.set_primary_key :x, :y
374
+ instance = @example.load :x => 4, :y => 5
375
+
376
+ parts = [
377
+ 'SELECT * FROM examples WHERE %s LIMIT 1',
378
+ '((x = 4) AND (y = 5))',
379
+ '((y = 5) AND (x = 4))'
380
+ ].map { |expr| Regexp.escape expr }
381
+ regexp = Regexp.new parts.first % "(?:#{parts[1]}|#{parts[2]})"
382
+
383
+ instance.this.sql.should match(regexp)
384
+ end
385
+
386
+ end
387
+
388
+ describe "Model#pk" do
389
+ before(:each) do
390
+ @m = Class.new(Sequel::Model)
391
+ @m.columns :id, :x, :y
392
+ end
393
+
394
+ it "should be default return the value of the :id column" do
395
+ m = @m.load(:id => 111, :x => 2, :y => 3)
396
+ m.pk.should == 111
397
+ end
398
+
399
+ it "should be return the primary key value for custom primary key" do
400
+ @m.set_primary_key :x
401
+ m = @m.load(:id => 111, :x => 2, :y => 3)
402
+ m.pk.should == 2
403
+ end
404
+
405
+ it "should be return the primary key value for composite primary key" do
406
+ @m.set_primary_key [:y, :x]
407
+ m = @m.load(:id => 111, :x => 2, :y => 3)
408
+ m.pk.should == [3, 2]
409
+ end
410
+
411
+ it "should raise if no primary key" do
412
+ @m.set_primary_key nil
413
+ m = @m.new(:id => 111, :x => 2, :y => 3)
414
+ proc {m.pk}.should raise_error(Sequel::Error)
415
+
416
+ @m.no_primary_key
417
+ m = @m.new(:id => 111, :x => 2, :y => 3)
418
+ proc {m.pk}.should raise_error(Sequel::Error)
419
+ end
420
+ end
421
+
422
+ describe "Model#pk_hash" do
423
+ before(:each) do
424
+ @m = Class.new(Sequel::Model)
425
+ @m.columns :id, :x, :y
426
+ end
427
+
428
+ it "should be default return the value of the :id column" do
429
+ m = @m.load(:id => 111, :x => 2, :y => 3)
430
+ m.pk_hash.should == {:id => 111}
431
+ end
432
+
433
+ it "should be return the primary key value for custom primary key" do
434
+ @m.set_primary_key :x
435
+ m = @m.load(:id => 111, :x => 2, :y => 3)
436
+ m.pk_hash.should == {:x => 2}
437
+ end
438
+
439
+ it "should be return the primary key value for composite primary key" do
440
+ @m.set_primary_key [:y, :x]
441
+ m = @m.load(:id => 111, :x => 2, :y => 3)
442
+ m.pk_hash.should == {:y => 3, :x => 2}
443
+ end
444
+
445
+ it "should raise if no primary key" do
446
+ @m.set_primary_key nil
447
+ m = @m.new(:id => 111, :x => 2, :y => 3)
448
+ proc {m.pk_hash}.should raise_error(Sequel::Error)
449
+
450
+ @m.no_primary_key
451
+ m = @m.new(:id => 111, :x => 2, :y => 3)
452
+ proc {m.pk_hash}.should raise_error(Sequel::Error)
453
+ end
454
+ end
455
+
456
+ describe Sequel::Model, "#set" do
457
+ before do
458
+ MODEL_DB.reset
459
+
460
+ @c = Class.new(Sequel::Model(:items)) do
461
+ set_primary_key :id
462
+ columns :x, :y, :id
463
+ end
464
+ @c.strict_param_setting = false
465
+ @c.instance_variable_set(:@columns, true)
466
+ @o1 = @c.new
467
+ @o2 = @c.load(:id => 5)
468
+ end
469
+
470
+ it "should filter the given params using the model columns" do
471
+ @o1.set(:x => 1, :z => 2)
472
+ @o1.values.should == {:x => 1}
473
+ MODEL_DB.sqls.should == []
474
+
475
+ @o2.set(:y => 1, :abc => 2)
476
+ @o2.values.should == {:y => 1, :id=> 5}
477
+ MODEL_DB.sqls.should == []
478
+ end
479
+
480
+ it "should work with both strings and symbols" do
481
+ @o1.set('x'=> 1, 'z'=> 2)
482
+ @o1.values.should == {:x => 1}
483
+ MODEL_DB.sqls.should == []
484
+
485
+ @o2.set('y'=> 1, 'abc'=> 2)
486
+ @o2.values.should == {:y => 1, :id=> 5}
487
+ MODEL_DB.sqls.should == []
488
+ end
489
+
490
+ it "should support virtual attributes" do
491
+ @c.send(:define_method, :blah=){|v| self.x = v}
492
+ @o1.set(:blah => 333)
493
+ @o1.values.should == {:x => 333}
494
+ MODEL_DB.sqls.should == []
495
+ @o1.set('blah'=> 334)
496
+ @o1.values.should == {:x => 334}
497
+ MODEL_DB.sqls.should == []
498
+ end
499
+
500
+ it "should not modify the primary key" do
501
+ @o1.set(:x => 1, :id => 2)
502
+ @o1.values.should == {:x => 1}
503
+ MODEL_DB.sqls.should == []
504
+ @o2.set('y'=> 1, 'id'=> 2)
505
+ @o2.values.should == {:y => 1, :id=> 5}
506
+ MODEL_DB.sqls.should == []
507
+ end
508
+
509
+ deprec_specify "should be aliased as set_with_params" do
510
+ @o1.set_with_params(:x => 1, :z => 2)
511
+ @o1.values.should == {:x => 1}
512
+ MODEL_DB.sqls.should == []
513
+ end
514
+
515
+ it "should return self" do
516
+ returned_value = @o1.set(:x => 1, :z => 2)
517
+ returned_value.should == @o1
518
+ MODEL_DB.sqls.should == []
519
+ end
520
+
521
+ deprec_specify "should assume it is a column if no column information is present and the key is a symbol" do
522
+ @c.instance_variable_set(:@columns, nil)
523
+ o = @c.new.set(:x123=>1)
524
+ o[:x123].should == 1
525
+ end
526
+ end
527
+
528
+ describe Sequel::Model, "#update" do
529
+ before do
530
+ MODEL_DB.reset
531
+
532
+ @c = Class.new(Sequel::Model(:items)) do
533
+ set_primary_key :id
534
+ columns :x, :y, :id
535
+ end
536
+ @c.strict_param_setting = false
537
+ @c.instance_variable_set(:@columns, true)
538
+ @o1 = @c.new
539
+ @o2 = @c.load(:id => 5)
540
+ end
541
+
542
+ it "should filter the given params using the model columns" do
543
+ @o1.update(:x => 1, :z => 2)
544
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
545
+
546
+ MODEL_DB.reset
547
+ @o2.update(:y => 1, :abc => 2)
548
+ MODEL_DB.sqls.first.should == "UPDATE items SET y = 1 WHERE (id = 5)"
549
+ end
550
+
551
+ it "should support virtual attributes" do
552
+ @c.send(:define_method, :blah=){|v| self.x = v}
553
+ @o1.update(:blah => 333)
554
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (333)"
555
+ end
556
+
557
+ it "should not modify the primary key" do
558
+ @o1.update(:x => 1, :id => 2)
559
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
560
+ MODEL_DB.reset
561
+ @o2.update('y'=> 1, 'id'=> 2)
562
+ @o2.values.should == {:y => 1, :id=> 5}
563
+ MODEL_DB.sqls.first.should == "UPDATE items SET y = 1 WHERE (id = 5)"
564
+ end
565
+
566
+ deprec_specify "should be aliased as update_with_params" do
567
+ @o1.update_with_params(:x => 1, :z => 2)
568
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
569
+ end
570
+ end
571
+
572
+ describe Sequel::Model, "#(set|update)_(all|except|only)" do
573
+ before do
574
+ MODEL_DB.reset
575
+
576
+ @c = Class.new(Sequel::Model(:items)) do
577
+ set_primary_key :id
578
+ columns :x, :y, :z, :id
579
+ set_allowed_columns :x
580
+ set_restricted_columns :y
581
+ end
582
+ @c.strict_param_setting = false
583
+ @c.instance_variable_set(:@columns, true)
584
+ @o1 = @c.new
585
+ end
586
+
587
+ it "#set_all should set all attributes" do
588
+ @o1.set_all(:x => 1, :y => 2, :z=>3, :id=>4)
589
+ @o1.values.should == {:x => 1, :y => 2, :z=>3}
590
+ end
591
+
592
+ it "#set_only should only set given attributes" do
593
+ @o1.set_only({:x => 1, :y => 2, :z=>3, :id=>4}, [:x, :y])
594
+ @o1.values.should == {:x => 1, :y => 2}
595
+ @o1.set_only({:x => 4, :y => 5, :z=>6, :id=>7}, :x, :y)
596
+ @o1.values.should == {:x => 4, :y => 5}
597
+ end
598
+
599
+ it "#set_except should not set given attributes" do
600
+ @o1.set_except({:x => 1, :y => 2, :z=>3, :id=>4}, [:y, :z])
601
+ @o1.values.should == {:x => 1}
602
+ @o1.set_except({:x => 4, :y => 2, :z=>3, :id=>4}, :y, :z)
603
+ @o1.values.should == {:x => 4}
604
+ end
605
+
606
+ it "#update_all should update all attributes" do
607
+ @c.new.update_all(:x => 1, :id=>4)
608
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
609
+ MODEL_DB.reset
610
+ @c.new.update_all(:y => 1, :id=>4)
611
+ MODEL_DB.sqls.first.should == "INSERT INTO items (y) VALUES (1)"
612
+ MODEL_DB.reset
613
+ @c.new.update_all(:z => 1, :id=>4)
614
+ MODEL_DB.sqls.first.should == "INSERT INTO items (z) VALUES (1)"
615
+ end
616
+
617
+ it "#update_only should only update given attributes" do
618
+ @o1.update_only({:x => 1, :y => 2, :z=>3, :id=>4}, [:x])
619
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
620
+ MODEL_DB.reset
621
+ @c.new.update_only({:x => 1, :y => 2, :z=>3, :id=>4}, :x)
622
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
623
+ end
624
+
625
+ it "#update_except should not update given attributes" do
626
+ @o1.update_except({:x => 1, :y => 2, :z=>3, :id=>4}, [:y, :z])
627
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
628
+ MODEL_DB.reset
629
+ @c.new.update_except({:x => 1, :y => 2, :z=>3, :id=>4}, :y, :z)
630
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
631
+ end
632
+ end
633
+
634
+ describe Sequel::Model, "#destroy" do
635
+ before do
636
+ MODEL_DB.reset
637
+ @model = Class.new(Sequel::Model(:items))
638
+ @model.columns :id
639
+ @model.dataset.meta_def(:delete) {MODEL_DB.execute delete_sql}
640
+
641
+ @instance = @model.load(:id => 1234)
642
+ end
643
+
644
+ it "should return self" do
645
+ @model.send(:define_method, :after_destroy){3}
646
+ @instance.destroy.should == @instance
647
+ end
648
+
649
+ it "should run within a transaction if use_transactions is true" do
650
+ @instance.use_transactions = true
651
+ @model.db.should_receive(:transaction)
652
+ @instance.destroy
653
+ end
654
+
655
+ it "should not run within a transaction if use_transactions is false" do
656
+ @instance.use_transactions = false
657
+ @model.db.should_not_receive(:transaction)
658
+ @instance.destroy
659
+ end
660
+
661
+ it "should run before_destroy and after_destroy hooks" do
662
+ @model.send(:define_method, :before_destroy){MODEL_DB.execute('before blah')}
663
+ @model.send(:define_method, :after_destroy){MODEL_DB.execute('after blah')}
664
+ @instance.destroy
665
+
666
+ MODEL_DB.sqls.should == [
667
+ "before blah",
668
+ "DELETE FROM items WHERE (id = 1234)",
669
+ "after blah"
670
+ ]
671
+ end
672
+ end
673
+
674
+ describe Sequel::Model, "#exists?" do
675
+ before(:each) do
676
+ @model = Class.new(Sequel::Model(:items))
677
+ @m = @model.new
678
+ end
679
+
680
+ it "should returns true when #this.count > 0" do
681
+ @m.this.meta_def(:count) {1}
682
+ @m.exists?.should be_true
683
+ end
684
+
685
+ it "should return false when #this.count == 0" do
686
+ @m.this.meta_def(:count) {0}
687
+ @m.exists?.should be_false
688
+ end
689
+ end
690
+
691
+ describe Sequel::Model, "#each" do
692
+ setup do
693
+ @model = Class.new(Sequel::Model(:items))
694
+ @model.columns :a, :b, :id
695
+ @m = @model.load(:a => 1, :b => 2, :id => 4444)
696
+ end
697
+
698
+ specify "should iterate over the values" do
699
+ h = {}
700
+ @m.each {|k, v| h[k] = v}
701
+ h.should == {:a => 1, :b => 2, :id => 4444}
702
+ end
703
+ end
704
+
705
+ describe Sequel::Model, "#keys" do
706
+ setup do
707
+ @model = Class.new(Sequel::Model(:items))
708
+ @model.columns :a, :b, :id
709
+ @m = @model.load(:a => 1, :b => 2, :id => 4444)
710
+ end
711
+
712
+ specify "should return the value keys" do
713
+ @m.keys.size.should == 3
714
+ @m.keys.should include(:a, :b, :id)
715
+
716
+ @m = @model.new()
717
+ @m.keys.should == []
718
+ end
719
+ end
720
+
721
+ describe Sequel::Model, "#==" do
722
+ specify "should compare instances by values" do
723
+ z = Class.new(Sequel::Model)
724
+ z.columns :id, :x
725
+ a = z.load(:id => 1, :x => 3)
726
+ b = z.load(:id => 1, :x => 4)
727
+ c = z.load(:id => 1, :x => 3)
728
+
729
+ a.should_not == b
730
+ a.should == c
731
+ b.should_not == c
732
+ end
733
+
734
+ specify "should be aliased to #eql?" do
735
+ z = Class.new(Sequel::Model)
736
+ z.columns :id, :x
737
+ a = z.load(:id => 1, :x => 3)
738
+ b = z.load(:id => 1, :x => 4)
739
+ c = z.load(:id => 1, :x => 3)
740
+
741
+ a.eql?(b).should == false
742
+ a.eql?(c).should == true
743
+ b.eql?(c).should == false
744
+ end
745
+ end
746
+
747
+ describe Sequel::Model, "#===" do
748
+ specify "should compare instances by class and pk if pk is not nil" do
749
+ z = Class.new(Sequel::Model)
750
+ z.columns :id, :x
751
+ y = Class.new(Sequel::Model)
752
+ y.columns :id, :x
753
+ a = z.load(:id => 1, :x => 3)
754
+ b = z.load(:id => 1, :x => 4)
755
+ c = z.load(:id => 2, :x => 3)
756
+ d = y.load(:id => 1, :x => 3)
757
+
758
+ a.should === b
759
+ a.should_not === c
760
+ a.should_not === d
761
+ end
762
+
763
+ specify "should always be false if the primary key is nil" do
764
+ z = Class.new(Sequel::Model)
765
+ z.columns :id, :x
766
+ y = Class.new(Sequel::Model)
767
+ y.columns :id, :x
768
+ a = z.new(:x => 3)
769
+ b = z.new(:x => 4)
770
+ c = z.new(:x => 3)
771
+ d = y.new(:x => 3)
772
+
773
+ a.should_not === b
774
+ a.should_not === c
775
+ a.should_not === d
776
+ end
777
+ end
778
+
779
+ describe Sequel::Model, "#hash" do
780
+ specify "should be the same only for objects with the same class and pk if the pk is not nil" do
781
+ z = Class.new(Sequel::Model)
782
+ z.columns :id, :x
783
+ y = Class.new(Sequel::Model)
784
+ y.columns :id, :x
785
+ a = z.load(:id => 1, :x => 3)
786
+ b = z.load(:id => 1, :x => 4)
787
+ c = z.load(:id => 2, :x => 3)
788
+ d = y.load(:id => 1, :x => 3)
789
+
790
+ a.hash.should == b.hash
791
+ a.hash.should_not == c.hash
792
+ a.hash.should_not == d.hash
793
+ end
794
+
795
+ specify "should be the same only for objects with the same class and values if the pk is nil" do
796
+ z = Class.new(Sequel::Model)
797
+ z.columns :id, :x
798
+ y = Class.new(Sequel::Model)
799
+ y.columns :id, :x
800
+ a = z.new(:x => 3)
801
+ b = z.new(:x => 4)
802
+ c = z.new(:x => 3)
803
+ d = y.new(:x => 3)
804
+
805
+ a.hash.should_not == b.hash
806
+ a.hash.should == c.hash
807
+ a.hash.should_not == d.hash
808
+ end
809
+ end
810
+
811
+ describe Sequel::Model, "#initialize" do
812
+ setup do
813
+ @c = Class.new(Sequel::Model) do
814
+ columns :id, :x
815
+ end
816
+ @c.strict_param_setting = false
817
+ end
818
+
819
+ specify "should accept values" do
820
+ m = @c.new(:x => 2)
821
+ m.values.should == {:x => 2}
822
+ end
823
+
824
+ specify "should not modify the primary key" do
825
+ m = @c.new(:id => 1, :x => 2)
826
+ m.values.should == {:x => 2}
827
+ end
828
+
829
+ specify "should accept no values" do
830
+ m = @c.new
831
+ m.values.should == {}
832
+ end
833
+
834
+ specify "should accept a block to execute" do
835
+ m = @c.new {|o| o[:id] = 1234}
836
+ m.id.should == 1234
837
+ end
838
+
839
+ specify "should accept virtual attributes" do
840
+ @c.send(:define_method, :blah=){|x| @blah = x}
841
+ @c.send(:define_method, :blah){@blah}
842
+
843
+ m = @c.new(:x => 2, :blah => 3)
844
+ m.values.should == {:x => 2}
845
+ m.blah.should == 3
846
+ end
847
+
848
+ specify "should convert string keys into symbol keys" do
849
+ m = @c.new('x' => 2)
850
+ m.values.should == {:x => 2}
851
+ end
852
+ end
853
+
854
+ describe Sequel::Model, ".create" do
855
+
856
+ before(:each) do
857
+ MODEL_DB.reset
858
+ @c = Class.new(Sequel::Model(:items)) do
859
+ unrestrict_primary_key
860
+ columns :x
861
+ end
862
+ end
863
+
864
+ it "should be able to create rows in the associated table" do
865
+ o = @c.create(:x => 1)
866
+ o.class.should == @c
867
+ MODEL_DB.sqls.should == ['INSERT INTO items (x) VALUES (1)', "SELECT * FROM items WHERE (id IN ('INSERT INTO items (x) VALUES (1)')) LIMIT 1"]
868
+ end
869
+
870
+ it "should be able to create rows without any values specified" do
871
+ o = @c.create
872
+ o.class.should == @c
873
+ MODEL_DB.sqls.should == ["INSERT INTO items DEFAULT VALUES", "SELECT * FROM items WHERE (id IN ('INSERT INTO items DEFAULT VALUES')) LIMIT 1"]
874
+ end
875
+
876
+ it "should accept a block and run it" do
877
+ o1, o2, o3 = nil, nil, nil
878
+ o = @c.create {|o4| o1 = o4; o3 = o4; o2 = :blah; o3.x = 333}
879
+ o.class.should == @c
880
+ o1.should === o
881
+ o3.should === o
882
+ o2.should == :blah
883
+ MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (333)", "SELECT * FROM items WHERE (id IN ('INSERT INTO items (x) VALUES (333)')) LIMIT 1"]
884
+ end
885
+
886
+ it "should create a row for a model with custom primary key" do
887
+ @c.set_primary_key :x
888
+ o = @c.create(:x => 30)
889
+ o.class.should == @c
890
+ MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (30)", "SELECT * FROM items WHERE (x = 30) LIMIT 1"]
891
+ end
892
+ end
893
+
894
+ describe Sequel::Model, "#refresh" do
895
+ setup do
896
+ MODEL_DB.reset
897
+ @c = Class.new(Sequel::Model(:items)) do
898
+ unrestrict_primary_key
899
+ columns :id, :x
900
+ end
901
+ end
902
+
903
+ specify "should reload the instance values from the database" do
904
+ @m = @c.new(:id => 555)
905
+ @m[:x] = 'blah'
906
+ @m.this.should_receive(:first).and_return({:x => 'kaboom', :id => 555})
907
+ @m.refresh
908
+ @m[:x].should == 'kaboom'
909
+ end
910
+
911
+ specify "should raise if the instance is not found" do
912
+ @m = @c.new(:id => 555)
913
+ @m.this.should_receive(:first).and_return(nil)
914
+ proc {@m.refresh}.should raise_error(Sequel::Error)
915
+ end
916
+
917
+ specify "should be aliased by #reload" do
918
+ @m = @c.new(:id => 555)
919
+ @m.this.should_receive(:first).and_return({:x => 'kaboom', :id => 555})
920
+ @m.reload
921
+ @m[:x].should == 'kaboom'
922
+ end
923
+
924
+ specify "should remove cached associations" do
925
+ @c.many_to_one :node, :class=>@c
926
+ @m = @c.new(:id => 555)
927
+ @m.associations[:node] = 15
928
+ @m.reload
929
+ @m.associations.should == {}
930
+ end
931
+ end
932
+
933
+ describe Sequel::Model, "typecasting" do
934
+ setup do
935
+ MODEL_DB.reset
936
+ @c = Class.new(Sequel::Model(:items)) do
937
+ columns :x
938
+ end
939
+ end
940
+
941
+ teardown do
942
+ Sequel.datetime_class = Time
943
+ end
944
+
945
+ specify "should not convert if typecasting is turned off" do
946
+ @c.typecast_on_assignment = false
947
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer}})
948
+ m = @c.new
949
+ m.x = '1'
950
+ m.x.should == '1'
951
+ end
952
+
953
+ specify "should not convert if serializing the field" do
954
+ @c.serialize :x
955
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:string}})
956
+ m = @c.new
957
+ m.x =[1, 2]
958
+ m.x.should == [1, 2]
959
+ end
960
+
961
+ specify "should convert to integer for an integer field" do
962
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer}})
963
+ m = @c.new
964
+ m.x = '1'
965
+ m.x.should == 1
966
+ m.x = 1
967
+ m.x.should == 1
968
+ m.x = 1.3
969
+ m.x.should == 1
970
+ end
971
+
972
+ specify "should typecast '' to nil unless type is string or blob" do
973
+ [:integer, :float, :decimal, :boolean, :date, :time, :datetime].each do |x|
974
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>x}})
975
+ m = @c.new
976
+ m.x = ''
977
+ m.x.should == nil
978
+ end
979
+ [:string, :blob].each do |x|
980
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>x}})
981
+ m = @c.new
982
+ m.x = ''
983
+ m.x.should == ''
984
+ end
985
+ end
986
+
987
+ specify "should not typecast '' to nil if typecast_empty_string_to_nil is false" do
988
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer}})
989
+ m = @c.new
990
+ m.typecast_empty_string_to_nil = false
991
+ proc{m.x = ''}.should raise_error
992
+ @c.typecast_empty_string_to_nil = false
993
+ proc{@c.new.x = ''}.should raise_error
994
+ end
995
+
996
+ specify "should not typecast nil if NULLs are allowed" do
997
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer,:allow_null=>true}})
998
+ m = @c.new
999
+ m.x = nil
1000
+ m.x.should == nil
1001
+ end
1002
+
1003
+ specify "should raise an error if attempting to typecast nil and NULLs are not allowed" do
1004
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer,:allow_null=>false}})
1005
+ proc{@c.new.x = nil}.should raise_error(Sequel::Error)
1006
+ proc{@c.new.x = ''}.should raise_error(Sequel::Error)
1007
+ end
1008
+
1009
+ specify "should not raise an error if NULLs are not allowed and typecasting is turned off" do
1010
+ @c.typecast_on_assignment = false
1011
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer,:allow_null=>false}})
1012
+ m = @c.new
1013
+ m.x = nil
1014
+ m.x.should == nil
1015
+ end
1016
+
1017
+ specify "should not raise when typecasting nil to NOT NULL column but raise_on_typecast_failure is off" do
1018
+ @c.raise_on_typecast_failure = false
1019
+ @c.typecast_on_assignment = true
1020
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer,:allow_null=>false}})
1021
+ m = @c.new
1022
+ m.x = ''
1023
+ m.x.should == nil
1024
+ m.x = nil
1025
+ m.x.should == nil
1026
+ end
1027
+
1028
+ specify "should raise an error if invalid data is used in an integer field" do
1029
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer}})
1030
+ proc{@c.new.x = 'a'}.should raise_error(Sequel::Error::InvalidValue)
1031
+ end
1032
+
1033
+ specify "should assign value if raise_on_typecast_failure is off and assigning invalid integer" do
1034
+ @c.raise_on_typecast_failure = false
1035
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer}})
1036
+ model = @c.new
1037
+ model.x = '1d'
1038
+ model.x.should == '1d'
1039
+ end
1040
+
1041
+ specify "should convert to float for a float field" do
1042
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:float}})
1043
+ m = @c.new
1044
+ m.x = '1.3'
1045
+ m.x.should == 1.3
1046
+ m.x = 1
1047
+ m.x.should == 1.0
1048
+ m.x = 1.3
1049
+ m.x.should == 1.3
1050
+ end
1051
+
1052
+ specify "should raise an error if invalid data is used in an float field" do
1053
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:float}})
1054
+ proc{@c.new.x = 'a'}.should raise_error(Sequel::Error::InvalidValue)
1055
+ end
1056
+
1057
+ specify "should assign value if raise_on_typecast_failure is off and assigning invalid float" do
1058
+ @c.raise_on_typecast_failure = false
1059
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:float}})
1060
+ model = @c.new
1061
+ model.x = '1d'
1062
+ model.x.should == '1d'
1063
+ end
1064
+
1065
+ specify "should convert to BigDecimal for a decimal field" do
1066
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:decimal}})
1067
+ m = @c.new
1068
+ bd = '1.0'.to_d
1069
+ m.x = '1.0'
1070
+ m.x.should == bd
1071
+ m.x = 1.0
1072
+ m.x.should == bd
1073
+ m.x = 1
1074
+ m.x.should == bd
1075
+ m.x = bd
1076
+ m.x.should == bd
1077
+ end
1078
+
1079
+ specify "should raise an error if invalid data is used in an decimal field" do
1080
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:decimal}})
1081
+ proc{@c.new.x = Date.today}.should raise_error(Sequel::Error::InvalidValue)
1082
+ end
1083
+
1084
+ specify "should assign value if raise_on_typecast_failure is off and assigning invalid decimal" do
1085
+ @c.raise_on_typecast_failure = false
1086
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:decimal}})
1087
+ model = @c.new
1088
+ time = Time.now
1089
+ model.x = time
1090
+ model.x.should == time
1091
+ end
1092
+
1093
+ specify "should convert to string for a string field" do
1094
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:string}})
1095
+ m = @c.new
1096
+ m.x = '1.3'
1097
+ m.x.should == '1.3'
1098
+ m.x = 1
1099
+ m.x.should == '1'
1100
+ m.x = 1.3
1101
+ m.x.should == '1.3'
1102
+ end
1103
+
1104
+ specify "should convert to boolean for a boolean field" do
1105
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:boolean}})
1106
+ m = @c.new
1107
+ m.x = '1.3'
1108
+ m.x.should == true
1109
+ m.x = 1
1110
+ m.x.should == true
1111
+ m.x = 1.3
1112
+ m.x.should == true
1113
+ m.x = 't'
1114
+ m.x.should == true
1115
+ m.x = 'T'
1116
+ m.x.should == true
1117
+ m.x = true
1118
+ m.x.should == true
1119
+ m.x = nil
1120
+ m.x.should == nil
1121
+ m.x = ''
1122
+ m.x.should == nil
1123
+ m.x = []
1124
+ m.x.should == nil
1125
+ m.x = 'f'
1126
+ m.x.should == false
1127
+ m.x = 'F'
1128
+ m.x.should == false
1129
+ m.x = 'false'
1130
+ m.x.should == false
1131
+ m.x = 'FALSE'
1132
+ m.x.should == false
1133
+ m.x = '0'
1134
+ m.x.should == false
1135
+ m.x = 0
1136
+ m.x.should == false
1137
+ m.x = false
1138
+ m.x.should == false
1139
+ end
1140
+
1141
+ specify "should convert to date for a date field" do
1142
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:date}})
1143
+ m = @c.new
1144
+ y = Date.new(2007,10,21)
1145
+ m.x = '2007-10-21'
1146
+ m.x.should == y
1147
+ m.x = Date.parse('2007-10-21')
1148
+ m.x.should == y
1149
+ m.x = Time.parse('2007-10-21')
1150
+ m.x.should == y
1151
+ m.x = DateTime.parse('2007-10-21')
1152
+ m.x.should == y
1153
+ end
1154
+
1155
+ specify "should raise an error if invalid data is used in a date field" do
1156
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:date}})
1157
+ proc{@c.new.x = 'a'}.should raise_error(Sequel::Error::InvalidValue)
1158
+ proc{@c.new.x = 100}.should raise_error(Sequel::Error::InvalidValue)
1159
+ end
1160
+
1161
+ specify "should assign value if raise_on_typecast_failure is off and assigning invalid date" do
1162
+ @c.raise_on_typecast_failure = false
1163
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:date}})
1164
+ model = @c.new
1165
+ model.x = 4
1166
+ model.x.should == 4
1167
+ end
1168
+
1169
+ specify "should convert to time for a time field" do
1170
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:time}})
1171
+ m = @c.new
1172
+ x = '10:20:30'
1173
+ y = Time.parse(x)
1174
+ m.x = x
1175
+ m.x.should == y
1176
+ m.x = y
1177
+ m.x.should == y
1178
+ end
1179
+
1180
+ specify "should raise an error if invalid data is used in a time field" do
1181
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:time}})
1182
+ proc{@c.new.x = '0000'}.should raise_error
1183
+ proc{@c.new.x = 'a'}.should_not raise_error # Valid Time
1184
+ proc{@c.new.x = Date.parse('2008-10-21')}.should raise_error(Sequel::Error::InvalidValue)
1185
+ proc{@c.new.x = DateTime.parse('2008-10-21')}.should raise_error(Sequel::Error::InvalidValue)
1186
+ end
1187
+
1188
+ specify "should assign value if raise_on_typecast_failure is off and assigning invalid time" do
1189
+ @c.raise_on_typecast_failure = false
1190
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:time}})
1191
+ model = @c.new
1192
+ model.x = '0000'
1193
+ model.x.should == '0000'
1194
+ end
1195
+
1196
+ specify "should convert to the Sequel.datetime_class for a datetime field" do
1197
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:datetime}})
1198
+ m = @c.new
1199
+ x = '2007-10-21T10:20:30-07:00'
1200
+ y = Time.parse(x)
1201
+ m.x = x
1202
+ m.x.should == y
1203
+ m.x = DateTime.parse(x)
1204
+ m.x.should == y
1205
+ m.x = Time.parse(x)
1206
+ m.x.should == y
1207
+ m.x = Date.parse('2007-10-21')
1208
+ m.x.should == Time.parse('2007-10-21')
1209
+ Sequel.datetime_class = DateTime
1210
+ y = DateTime.parse(x)
1211
+ m.x = x
1212
+ m.x.should == y
1213
+ m.x = DateTime.parse(x)
1214
+ m.x.should == y
1215
+ m.x = Time.parse(x)
1216
+ m.x.should == y
1217
+ m.x = Date.parse('2007-10-21')
1218
+ m.x.should == DateTime.parse('2007-10-21')
1219
+ end
1220
+
1221
+ specify "should raise an error if invalid data is used in a datetime field" do
1222
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:datetime}})
1223
+ proc{@c.new.x = '0000'}.should raise_error(Sequel::Error::InvalidValue)
1224
+ proc{@c.new.x = 'a'}.should_not raise_error # Valid Time
1225
+ Sequel.datetime_class = DateTime
1226
+ proc{@c.new.x = '0000'}.should raise_error(Sequel::Error::InvalidValue)
1227
+ proc{@c.new.x = 'a'}.should raise_error(Sequel::Error::InvalidValue)
1228
+ end
1229
+
1230
+ specify "should assign value if raise_on_typecast_failure is off and assigning invalid datetime" do
1231
+ @c.raise_on_typecast_failure = false
1232
+ @c.instance_variable_set(:@db_schema, {:x=>{:type=>:datetime}})
1233
+ model = @c.new
1234
+ model.x = '0000'
1235
+ model.x.should == '0000'
1236
+ Sequel.datetime_class = DateTime
1237
+ model = @c.new
1238
+ model.x = '0000'
1239
+ model.x.should == '0000'
1240
+ model.x = 'a'
1241
+ model.x.should == 'a'
1242
+ end
1243
+ end