epugh-sequel 0.0.0

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