sequel 3.21.0 → 3.31.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 (225) hide show
  1. data/CHANGELOG +485 -3
  2. data/README.rdoc +20 -6
  3. data/Rakefile +37 -19
  4. data/bin/sequel +1 -5
  5. data/doc/association_basics.rdoc +249 -43
  6. data/doc/dataset_basics.rdoc +4 -4
  7. data/doc/dataset_filtering.rdoc +8 -0
  8. data/doc/mass_assignment.rdoc +54 -0
  9. data/doc/migration.rdoc +15 -538
  10. data/doc/model_hooks.rdoc +72 -27
  11. data/doc/opening_databases.rdoc +89 -50
  12. data/doc/prepared_statements.rdoc +40 -13
  13. data/doc/reflection.rdoc +8 -2
  14. data/doc/release_notes/3.22.0.txt +39 -0
  15. data/doc/release_notes/3.23.0.txt +172 -0
  16. data/doc/release_notes/3.24.0.txt +420 -0
  17. data/doc/release_notes/3.25.0.txt +88 -0
  18. data/doc/release_notes/3.26.0.txt +88 -0
  19. data/doc/release_notes/3.27.0.txt +82 -0
  20. data/doc/release_notes/3.28.0.txt +304 -0
  21. data/doc/release_notes/3.29.0.txt +459 -0
  22. data/doc/release_notes/3.30.0.txt +135 -0
  23. data/doc/release_notes/3.31.0.txt +146 -0
  24. data/doc/schema_modification.rdoc +547 -0
  25. data/doc/sharding.rdoc +7 -1
  26. data/doc/testing.rdoc +129 -0
  27. data/doc/transactions.rdoc +137 -0
  28. data/doc/virtual_rows.rdoc +2 -2
  29. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  30. data/lib/sequel/adapters/ado.rb +40 -18
  31. data/lib/sequel/adapters/amalgalite.rb +17 -9
  32. data/lib/sequel/adapters/db2.rb +175 -86
  33. data/lib/sequel/adapters/dbi.rb +15 -15
  34. data/lib/sequel/adapters/do/mysql.rb +5 -7
  35. data/lib/sequel/adapters/do/postgres.rb +0 -5
  36. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  37. data/lib/sequel/adapters/do.rb +17 -36
  38. data/lib/sequel/adapters/firebird.rb +27 -208
  39. data/lib/sequel/adapters/ibmdb.rb +448 -0
  40. data/lib/sequel/adapters/informix.rb +6 -23
  41. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  42. data/lib/sequel/adapters/jdbc/db2.rb +45 -0
  43. data/lib/sequel/adapters/jdbc/derby.rb +247 -0
  44. data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
  45. data/lib/sequel/adapters/jdbc/h2.rb +56 -29
  46. data/lib/sequel/adapters/jdbc/hsqldb.rb +170 -0
  47. data/lib/sequel/adapters/jdbc/informix.rb +26 -0
  48. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  49. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  50. data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
  51. data/lib/sequel/adapters/jdbc/oracle.rb +81 -25
  52. data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
  53. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
  54. data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
  55. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  56. data/lib/sequel/adapters/jdbc.rb +231 -78
  57. data/lib/sequel/adapters/mock.rb +335 -0
  58. data/lib/sequel/adapters/mysql.rb +82 -184
  59. data/lib/sequel/adapters/mysql2.rb +26 -25
  60. data/lib/sequel/adapters/odbc/db2.rb +17 -0
  61. data/lib/sequel/adapters/odbc/mssql.rb +1 -6
  62. data/lib/sequel/adapters/odbc.rb +28 -9
  63. data/lib/sequel/adapters/openbase.rb +3 -5
  64. data/lib/sequel/adapters/oracle.rb +351 -53
  65. data/lib/sequel/adapters/postgres.rb +194 -33
  66. data/lib/sequel/adapters/shared/access.rb +32 -9
  67. data/lib/sequel/adapters/shared/db2.rb +321 -0
  68. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  69. data/lib/sequel/adapters/shared/informix.rb +53 -0
  70. data/lib/sequel/adapters/shared/mssql.rb +231 -106
  71. data/lib/sequel/adapters/shared/mysql.rb +181 -63
  72. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
  73. data/lib/sequel/adapters/shared/oracle.rb +231 -41
  74. data/lib/sequel/adapters/shared/postgres.rb +214 -82
  75. data/lib/sequel/adapters/shared/progress.rb +4 -7
  76. data/lib/sequel/adapters/shared/sqlite.rb +201 -57
  77. data/lib/sequel/adapters/sqlite.rb +29 -21
  78. data/lib/sequel/adapters/swift/mysql.rb +12 -7
  79. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  80. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  81. data/lib/sequel/adapters/swift.rb +5 -5
  82. data/lib/sequel/adapters/tinytds.rb +160 -19
  83. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  84. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  85. data/lib/sequel/ast_transformer.rb +190 -0
  86. data/lib/sequel/connection_pool/threaded.rb +3 -2
  87. data/lib/sequel/connection_pool.rb +1 -1
  88. data/lib/sequel/core.rb +46 -5
  89. data/lib/sequel/database/connecting.rb +5 -6
  90. data/lib/sequel/database/dataset.rb +4 -4
  91. data/lib/sequel/database/dataset_defaults.rb +59 -1
  92. data/lib/sequel/database/logging.rb +1 -1
  93. data/lib/sequel/database/misc.rb +104 -19
  94. data/lib/sequel/database/query.rb +153 -58
  95. data/lib/sequel/database/schema_generator.rb +17 -7
  96. data/lib/sequel/database/schema_methods.rb +59 -29
  97. data/lib/sequel/dataset/actions.rb +231 -76
  98. data/lib/sequel/dataset/features.rb +91 -8
  99. data/lib/sequel/dataset/graph.rb +38 -11
  100. data/lib/sequel/dataset/misc.rb +50 -23
  101. data/lib/sequel/dataset/mutation.rb +5 -6
  102. data/lib/sequel/dataset/prepared_statements.rb +48 -27
  103. data/lib/sequel/dataset/query.rb +236 -43
  104. data/lib/sequel/dataset/sql.rb +665 -253
  105. data/lib/sequel/dataset.rb +8 -0
  106. data/lib/sequel/exceptions.rb +4 -0
  107. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  108. data/lib/sequel/extensions/migration.rb +6 -4
  109. data/lib/sequel/extensions/named_timezones.rb +5 -0
  110. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  111. data/lib/sequel/extensions/to_dot.rb +95 -83
  112. data/lib/sequel/model/associations.rb +1020 -337
  113. data/lib/sequel/model/base.rb +414 -132
  114. data/lib/sequel/model/errors.rb +1 -1
  115. data/lib/sequel/model/exceptions.rb +5 -1
  116. data/lib/sequel/model.rb +15 -8
  117. data/lib/sequel/plugins/association_pks.rb +22 -4
  118. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  119. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  120. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  121. data/lib/sequel/plugins/force_encoding.rb +6 -6
  122. data/lib/sequel/plugins/identity_map.rb +114 -7
  123. data/lib/sequel/plugins/many_through_many.rb +65 -7
  124. data/lib/sequel/plugins/prepared_statements.rb +151 -0
  125. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  126. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  127. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  128. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  129. data/lib/sequel/plugins/serialization.rb +88 -44
  130. data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
  131. data/lib/sequel/plugins/sharding.rb +21 -54
  132. data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
  133. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  134. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  135. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  136. data/lib/sequel/sql.rb +109 -52
  137. data/lib/sequel/timezones.rb +57 -38
  138. data/lib/sequel/version.rb +1 -1
  139. data/spec/adapters/db2_spec.rb +146 -0
  140. data/spec/adapters/mssql_spec.rb +111 -29
  141. data/spec/adapters/mysql_spec.rb +135 -123
  142. data/spec/adapters/oracle_spec.rb +49 -77
  143. data/spec/adapters/postgres_spec.rb +267 -78
  144. data/spec/adapters/spec_helper.rb +6 -5
  145. data/spec/adapters/sqlite_spec.rb +35 -21
  146. data/spec/core/connection_pool_spec.rb +71 -92
  147. data/spec/core/core_sql_spec.rb +21 -30
  148. data/spec/core/database_spec.rb +788 -512
  149. data/spec/core/dataset_spec.rb +1073 -1053
  150. data/spec/core/expression_filters_spec.rb +159 -42
  151. data/spec/core/mock_adapter_spec.rb +419 -0
  152. data/spec/core/object_graph_spec.rb +86 -114
  153. data/spec/core/schema_generator_spec.rb +3 -3
  154. data/spec/core/schema_spec.rb +298 -38
  155. data/spec/core/spec_helper.rb +6 -48
  156. data/spec/extensions/association_autoreloading_spec.rb +1 -10
  157. data/spec/extensions/association_dependencies_spec.rb +2 -12
  158. data/spec/extensions/association_pks_spec.rb +66 -32
  159. data/spec/extensions/caching_spec.rb +23 -50
  160. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  161. data/spec/extensions/columns_introspection_spec.rb +91 -0
  162. data/spec/extensions/composition_spec.rb +18 -13
  163. data/spec/extensions/dataset_associations_spec.rb +199 -0
  164. data/spec/extensions/defaults_setter_spec.rb +64 -0
  165. data/spec/extensions/hook_class_methods_spec.rb +65 -91
  166. data/spec/extensions/identity_map_spec.rb +114 -22
  167. data/spec/extensions/instance_filters_spec.rb +11 -21
  168. data/spec/extensions/instance_hooks_spec.rb +53 -0
  169. data/spec/extensions/json_serializer_spec.rb +4 -5
  170. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  171. data/spec/extensions/list_spec.rb +17 -39
  172. data/spec/extensions/many_through_many_spec.rb +283 -250
  173. data/spec/extensions/migration_spec.rb +35 -32
  174. data/spec/extensions/named_timezones_spec.rb +23 -3
  175. data/spec/extensions/nested_attributes_spec.rb +97 -88
  176. data/spec/extensions/optimistic_locking_spec.rb +9 -20
  177. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  178. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  179. data/spec/extensions/prepared_statements_spec.rb +53 -0
  180. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  181. data/spec/extensions/pretty_table_spec.rb +1 -6
  182. data/spec/extensions/rcte_tree_spec.rb +41 -43
  183. data/spec/extensions/schema_dumper_spec.rb +5 -8
  184. data/spec/extensions/schema_spec.rb +13 -21
  185. data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
  186. data/spec/extensions/serialization_spec.rb +72 -43
  187. data/spec/extensions/sharding_spec.rb +66 -140
  188. data/spec/extensions/single_table_inheritance_spec.rb +18 -29
  189. data/spec/extensions/spec_helper.rb +13 -61
  190. data/spec/extensions/sql_expr_spec.rb +20 -60
  191. data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
  192. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  193. data/spec/extensions/timestamps_spec.rb +6 -6
  194. data/spec/extensions/to_dot_spec.rb +4 -7
  195. data/spec/extensions/touch_spec.rb +13 -14
  196. data/spec/extensions/tree_spec.rb +11 -26
  197. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  198. data/spec/extensions/update_primary_key_spec.rb +30 -24
  199. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  200. data/spec/extensions/validation_helpers_spec.rb +16 -35
  201. data/spec/extensions/xml_serializer_spec.rb +16 -4
  202. data/spec/integration/associations_test.rb +537 -21
  203. data/spec/integration/database_test.rb +4 -2
  204. data/spec/integration/dataset_test.rb +461 -65
  205. data/spec/integration/eager_loader_test.rb +19 -21
  206. data/spec/integration/model_test.rb +80 -1
  207. data/spec/integration/plugin_test.rb +304 -116
  208. data/spec/integration/prepared_statement_test.rb +212 -122
  209. data/spec/integration/schema_test.rb +161 -30
  210. data/spec/integration/spec_helper.rb +39 -30
  211. data/spec/integration/timezone_test.rb +38 -12
  212. data/spec/integration/transaction_test.rb +172 -5
  213. data/spec/integration/type_test.rb +17 -3
  214. data/spec/model/association_reflection_spec.rb +201 -7
  215. data/spec/model/associations_spec.rb +865 -662
  216. data/spec/model/base_spec.rb +275 -95
  217. data/spec/model/dataset_methods_spec.rb +7 -27
  218. data/spec/model/eager_loading_spec.rb +677 -676
  219. data/spec/model/hooks_spec.rb +309 -67
  220. data/spec/model/model_spec.rb +222 -168
  221. data/spec/model/plugins_spec.rb +24 -13
  222. data/spec/model/record_spec.rb +381 -218
  223. data/spec/model/spec_helper.rb +13 -71
  224. data/spec/model/validations_spec.rb +11 -0
  225. metadata +115 -73
@@ -1,36 +1,23 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe "Model#save server use" do
4
-
5
- before(:each) do
6
- @c = Class.new(Sequel::Model(:items)) do
7
- columns :id, :x, :y
8
- end
9
- @c.db = MockDatabase.new
10
- db2 = @db2 = MockDatabase.new
11
- @c.class_eval do
12
- define_method(:after_save) do
13
- model.db = db2
14
- ds = model.dataset
15
- def ds.fetch_rows(sql)
16
- yield @db.execute(sql, @opts[:server])
17
- end
18
- @this = nil
19
- end
20
- end
4
+ before do
5
+ @db = Sequel.mock(:autoid=>proc{|sql| 10}, :fetch=>{:x=>1, :id=>10}, :servers=>{:blah=>{}, :read_only=>{}})
6
+ @c = Class.new(Sequel::Model(@db[:items]))
7
+ @c.columns :id, :x, :y
8
+ @c.dataset.columns(:id, :x, :y)
9
+ @db.sqls
21
10
  end
22
11
 
23
12
  it "should use the :default server if the model doesn't have one already specified" do
24
- @c.db.should_receive(:execute).with("INSERT INTO items (x) VALUES (1)").and_return(10)
25
- @db2.should_receive(:execute).with('SELECT * FROM items WHERE (id = 10) LIMIT 1', :default).and_return(:x=>1, :id=>10)
26
- @c.new(:x=>1).save
13
+ @c.new(:x=>1).save.should == @c.load(:x=>1, :id=>10)
14
+ @db.sqls.should == ["INSERT INTO items (x) VALUES (1)", 'SELECT * FROM items WHERE (id = 10) LIMIT 1']
27
15
  end
28
16
 
29
17
  it "should use the model's server if the model has one already specified" do
30
18
  @c.dataset = @c.dataset.server(:blah)
31
- @c.db.should_receive(:execute).with("INSERT INTO items (x) VALUES (1)").and_return(10)
32
- @db2.should_receive(:execute).with('SELECT * FROM items WHERE (id = 10) LIMIT 1', :blah).and_return(:x=>1, :id=>10)
33
- @c.new(:x=>1).save
19
+ @c.new(:x=>1).save.should == @c.load(:x=>1, :id=>10)
20
+ @db.sqls.should == ["INSERT INTO items (x) VALUES (1) -- blah", 'SELECT * FROM items WHERE (id = 10) LIMIT 1 -- blah']
34
21
  end
35
22
  end
36
23
 
@@ -39,32 +26,37 @@ describe "Model#save" do
39
26
  @c = Class.new(Sequel::Model(:items)) do
40
27
  columns :id, :x, :y
41
28
  end
42
- @c.dataset.meta_def(:insert){|h| super(h); 1}
29
+ @c.dataset.autoid = 13
43
30
  MODEL_DB.reset
44
31
  end
45
32
 
46
33
  it "should insert a record for a new model instance" do
47
34
  o = @c.new(:x => 1)
48
35
  o.save
49
- MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (1)",
50
- "SELECT * FROM items WHERE (id = 1) LIMIT 1"]
36
+ MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (1)", "SELECT * FROM items WHERE (id = 13) LIMIT 1"]
51
37
  end
52
38
 
53
39
  it "should use dataset's insert_select method if present" do
54
40
  ds = @c.dataset = @c.dataset.clone
41
+ ds._fetch = {:y=>2}
42
+ def ds.supports_insert_select?() true end
55
43
  def ds.insert_select(hash)
56
- execute("INSERT INTO items (y) VALUES (2)")
57
- {:y=>2}
44
+ execute("INSERT INTO items (y) VALUES (2) RETURNING *"){|r| return r}
58
45
  end
59
46
  o = @c.new(:x => 1)
60
47
  o.save
61
48
 
62
49
  o.values.should == {:y=>2}
63
- MODEL_DB.sqls.should == ["INSERT INTO items (y) VALUES (2)"]
50
+ MODEL_DB.sqls.should == ["INSERT INTO items (y) VALUES (2) RETURNING *"]
51
+ end
52
+
53
+ it "should not use dataset's insert_select method if specific columns are selected" do
54
+ ds = @c.dataset = @c.dataset.select(:y)
55
+ ds.should_not_receive(:insert_select)
56
+ @c.new(:x => 1).save
64
57
  end
65
58
 
66
59
  it "should use value returned by insert as the primary key and refresh the object" do
67
- @c.dataset.meta_def(:insert){|h| super(h); 13}
68
60
  o = @c.new(:x => 11)
69
61
  o.save
70
62
  MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (11)",
@@ -72,14 +64,12 @@ describe "Model#save" do
72
64
  end
73
65
 
74
66
  it "should allow you to skip refreshing by overridding _save_refresh" do
75
- @c.dataset.meta_def(:insert){|h| super(h); 13}
76
67
  @c.send(:define_method, :_save_refresh){}
77
68
  @c.create(:x => 11)
78
69
  MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (11)"]
79
70
  end
80
71
 
81
72
  it "should work correctly for inserting a record without a primary key" do
82
- @c.dataset.meta_def(:insert){|h| super(h); 13}
83
73
  @c.no_primary_key
84
74
  o = @c.new(:x => 11)
85
75
  o.save
@@ -87,15 +77,15 @@ describe "Model#save" do
87
77
  end
88
78
 
89
79
  it "should set the autoincrementing_primary_key value to the value returned by insert" do
90
- @c.dataset.meta_def(:insert){|h| super(h); 13}
91
80
  @c.unrestrict_primary_key
92
81
  @c.set_primary_key [:x, :y]
93
82
  o = @c.new(:x => 11)
94
83
  o.meta_def(:autoincrementing_primary_key){:y}
95
84
  o.save
96
- MODEL_DB.sqls.length.should == 2
97
- MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (11)"
98
- MODEL_DB.sqls.last.should =~ %r{SELECT \* FROM items WHERE \(\([xy] = 1[13]\) AND \([xy] = 1[13]\)\) LIMIT 1}
85
+ sqls = MODEL_DB.sqls
86
+ sqls.length.should == 2
87
+ sqls.first.should == "INSERT INTO items (x) VALUES (11)"
88
+ sqls.last.should =~ %r{SELECT \* FROM items WHERE \(\([xy] = 1[13]\) AND \([xy] = 1[13]\)\) LIMIT 1}
99
89
  end
100
90
 
101
91
  it "should update a record for an existing model instance" do
@@ -106,17 +96,18 @@ describe "Model#save" do
106
96
 
107
97
  it "should raise a NoExistingObject exception if the dataset update call doesn't return 1, unless require_modification is false" do
108
98
  o = @c.load(:id => 3, :x => 1)
109
- o.this.meta_def(:update){|*a| 0}
99
+ t = o.this
100
+ t.numrows = 0
110
101
  proc{o.save}.should raise_error(Sequel::NoExistingObject)
111
- o.this.meta_def(:update){|*a| 2}
102
+ t.numrows = 2
112
103
  proc{o.save}.should raise_error(Sequel::NoExistingObject)
113
- o.this.meta_def(:update){|*a| 1}
104
+ t.numrows = 1
114
105
  proc{o.save}.should_not raise_error
115
106
 
116
107
  o.require_modification = false
117
- o.this.meta_def(:update){|*a| 0}
108
+ t.numrows = 0
118
109
  proc{o.save}.should_not raise_error
119
- o.this.meta_def(:update){|*a| 2}
110
+ t.numrows = 2
120
111
  proc{o.save}.should_not raise_error
121
112
  end
122
113
 
@@ -185,22 +176,18 @@ describe "Model#save" do
185
176
  @c.use_transactions = true
186
177
  @c.load(:id => 3, :x => 1, :y => nil).save(:y)
187
178
  MODEL_DB.sqls.should == ["BEGIN", "UPDATE items SET y = NULL WHERE (id = 3)", "COMMIT"]
188
- MODEL_DB.reset
189
179
  @c.use_transactions = false
190
180
  @c.load(:id => 3, :x => 1, :y => nil).save(:y)
191
181
  MODEL_DB.sqls.should == ["UPDATE items SET y = NULL WHERE (id = 3)"]
192
- MODEL_DB.reset
193
182
  end
194
183
 
195
184
  it "should inherit Model's use_transactions setting" do
196
185
  @c.use_transactions = true
197
186
  Class.new(@c).load(:id => 3, :x => 1, :y => nil).save(:y)
198
187
  MODEL_DB.sqls.should == ["BEGIN", "UPDATE items SET y = NULL WHERE (id = 3)", "COMMIT"]
199
- MODEL_DB.reset
200
188
  @c.use_transactions = false
201
189
  Class.new(@c).load(:id => 3, :x => 1, :y => nil).save(:y)
202
190
  MODEL_DB.sqls.should == ["UPDATE items SET y = NULL WHERE (id = 3)"]
203
- MODEL_DB.reset
204
191
  end
205
192
 
206
193
  it "should use object's use_transactions setting" do
@@ -209,13 +196,11 @@ describe "Model#save" do
209
196
  @c.use_transactions = true
210
197
  o.save(:y)
211
198
  MODEL_DB.sqls.should == ["UPDATE items SET y = NULL WHERE (id = 3)"]
212
- MODEL_DB.reset
213
199
  o = @c.load(:id => 3, :x => 1, :y => nil)
214
200
  o.use_transactions = true
215
201
  @c.use_transactions = false
216
202
  o.save(:y)
217
203
  MODEL_DB.sqls.should == ["BEGIN", "UPDATE items SET y = NULL WHERE (id = 3)", "COMMIT"]
218
- MODEL_DB.reset
219
204
  end
220
205
 
221
206
  it "should use :transaction option if given" do
@@ -223,12 +208,10 @@ describe "Model#save" do
223
208
  o.use_transactions = true
224
209
  o.save(:y, :transaction=>false)
225
210
  MODEL_DB.sqls.should == ["UPDATE items SET y = NULL WHERE (id = 3)"]
226
- MODEL_DB.reset
227
211
  o = @c.load(:id => 3, :x => 1, :y => nil)
228
212
  o.use_transactions = false
229
213
  o.save(:y, :transaction=>true)
230
214
  MODEL_DB.sqls.should == ["BEGIN", "UPDATE items SET y = NULL WHERE (id = 3)", "COMMIT"]
231
- MODEL_DB.reset
232
215
  end
233
216
 
234
217
  it "should rollback if before_save returns false and raise_on_save_failure = true" do
@@ -240,7 +223,6 @@ describe "Model#save" do
240
223
  end
241
224
  proc { o.save(:y) }.should raise_error(Sequel::BeforeHookFailed)
242
225
  MODEL_DB.sqls.should == ["BEGIN", "ROLLBACK"]
243
- MODEL_DB.reset
244
226
  end
245
227
 
246
228
  it "should rollback if before_save returns false and :raise_on_failure option is true" do
@@ -252,7 +234,6 @@ describe "Model#save" do
252
234
  end
253
235
  proc { o.save(:y, :raise_on_failure => true) }.should raise_error(Sequel::BeforeHookFailed)
254
236
  MODEL_DB.sqls.should == ["BEGIN", "ROLLBACK"]
255
- MODEL_DB.reset
256
237
  end
257
238
 
258
239
  it "should not rollback outer transactions if before_save returns false and raise_on_save_failure = false" do
@@ -267,7 +248,6 @@ describe "Model#save" do
267
248
  MODEL_DB.run "BLAH"
268
249
  end
269
250
  MODEL_DB.sqls.should == ["BEGIN", "BLAH", "COMMIT"]
270
- MODEL_DB.reset
271
251
  end
272
252
 
273
253
  it "should rollback if before_save returns false and raise_on_save_failure = false" do
@@ -279,7 +259,6 @@ describe "Model#save" do
279
259
  end
280
260
  o.save(:y).should == nil
281
261
  MODEL_DB.sqls.should == ["BEGIN", "ROLLBACK"]
282
- MODEL_DB.reset
283
262
  end
284
263
 
285
264
  it "should not rollback if before_save throws Rollback and use_transactions = false" do
@@ -290,7 +269,66 @@ describe "Model#save" do
290
269
  end
291
270
  proc { o.save(:y) }.should raise_error(Sequel::Rollback)
292
271
  MODEL_DB.sqls.should == []
293
- MODEL_DB.reset
272
+ end
273
+
274
+ it "should support a :server option to set the server/shard to use" do
275
+ db = Sequel.mock(:fetch=>{:id=>13, :x=>1}, :autoid=>proc{13}, :numrows=>1, :servers=>{:s1=>{}})
276
+ c = Class.new(Sequel::Model(db[:items]))
277
+ c.columns :id, :x
278
+ db.sqls
279
+ o = c.new(:x => 1)
280
+ o.save(:server=>:s1)
281
+ db.sqls.should == ["INSERT INTO items (x) VALUES (1) -- s1", "SELECT * FROM items WHERE (id = 13) LIMIT 1 -- s1"]
282
+ o.save(:server=>:s1, :transaction=>true)
283
+ db.sqls.should == ["BEGIN -- s1", "UPDATE items SET x = 1 WHERE (id = 13) -- s1", 'COMMIT -- s1']
284
+ end
285
+ end
286
+
287
+ describe "Model#set_server" do
288
+ before do
289
+ @db = Sequel.mock(:fetch=>{:id=>13, :x=>1}, :autoid=>proc{13}, :numrows=>1, :servers=>{:s1=>{}})
290
+ @c = Class.new(Sequel::Model(@db[:items])) do
291
+ columns :id, :x
292
+ end
293
+ @db.sqls
294
+ end
295
+
296
+ it "should set the server to use when inserting" do
297
+ @c.new(:x => 1).set_server(:s1).save
298
+ @db.sqls.should == ["INSERT INTO items (x) VALUES (1) -- s1", "SELECT * FROM items WHERE (id = 13) LIMIT 1 -- s1"]
299
+ end
300
+
301
+ it "should set the server to use when updating" do
302
+ @c.load(:id=>13, :x => 1).set_server(:s1).save
303
+ @db.sqls.should == ["UPDATE items SET x = 1 WHERE (id = 13) -- s1"]
304
+ end
305
+
306
+ it "should set the server to use for transactions when saving" do
307
+ @c.load(:id=>13, :x => 1).set_server(:s1).save(:transaction=>true)
308
+ @db.sqls.should == ["BEGIN -- s1", "UPDATE items SET x = 1 WHERE (id = 13) -- s1", 'COMMIT -- s1']
309
+ end
310
+
311
+ it "should set the server to use when deleting" do
312
+ @c.load(:id=>13).set_server(:s1).delete
313
+ @db.sqls.should == ["DELETE FROM items WHERE (id = 13) -- s1"]
314
+ end
315
+
316
+ it "should set the server to use for transactions when destroying" do
317
+ o = @c.load(:id=>13).set_server(:s1)
318
+ o.use_transactions = true
319
+ o.destroy
320
+ @db.sqls.should == ["BEGIN -- s1", "DELETE FROM items WHERE (id = 13) -- s1", 'COMMIT -- s1']
321
+ end
322
+
323
+ it "should set the server on this if this is already loaded" do
324
+ o = @c.load(:id=>13, :x => 1)
325
+ o.this
326
+ o.set_server(:s1)
327
+ o.this.opts[:server].should == :s1
328
+ end
329
+
330
+ it "should set the server on this if this is not already loaded" do
331
+ @c.load(:id=>13, :x => 1).set_server(:s1).this.opts[:server].should == :s1
294
332
  end
295
333
  end
296
334
 
@@ -299,7 +337,6 @@ describe "Model#marshallable" do
299
337
  class ::Album < Sequel::Model
300
338
  columns :id, :x
301
339
  end
302
- Album.dataset.meta_def(:insert){|h| super(h); 1}
303
340
  end
304
341
  after do
305
342
  Object.send(:remove_const, :Album)
@@ -381,7 +418,6 @@ describe "Model#modified[!?]" do
381
418
  end
382
419
 
383
420
  describe "Model#save_changes" do
384
-
385
421
  before do
386
422
  @c = Class.new(Sequel::Model(:items)) do
387
423
  unrestrict_primary_key
@@ -426,15 +462,14 @@ describe "Model#save_changes" do
426
462
  MODEL_DB.sqls.should == ["UPDATE items SET x = 2 WHERE (id = 3)"]
427
463
  o.save_changes
428
464
  o.save_changes
429
- MODEL_DB.sqls.should == ["UPDATE items SET x = 2 WHERE (id = 3)"]
430
- MODEL_DB.reset
465
+ MODEL_DB.sqls.should == []
431
466
 
432
467
  o.y = 4
433
468
  o.save_changes
434
469
  MODEL_DB.sqls.should == ["UPDATE items SET y = 4 WHERE (id = 3)"]
435
470
  o.save_changes
436
471
  o.save_changes
437
- MODEL_DB.sqls.should == ["UPDATE items SET y = 4 WHERE (id = 3)"]
472
+ MODEL_DB.sqls.should == []
438
473
  end
439
474
 
440
475
  it "should not consider columns changed if the values did not change" do
@@ -446,7 +481,6 @@ describe "Model#save_changes" do
446
481
  o.x = 3
447
482
  o.save_changes
448
483
  MODEL_DB.sqls.should == ["UPDATE items SET x = 3 WHERE (id = 3)"]
449
- MODEL_DB.reset
450
484
 
451
485
  o[:y] = nil
452
486
  o.save_changes
@@ -472,13 +506,11 @@ describe "Model#save_changes" do
472
506
  o.x = 2
473
507
  o.save_changes
474
508
  MODEL_DB.sqls.should == ["UPDATE items SET x = 3 WHERE (id = 3)"]
475
- MODEL_DB.reset
476
509
  o.save_changes
477
510
  MODEL_DB.sqls.should == []
478
511
  o.x = 4
479
512
  o.save_changes
480
513
  MODEL_DB.sqls.should == ["UPDATE items SET x = 5 WHERE (id = 3)"]
481
- MODEL_DB.reset
482
514
  end
483
515
 
484
516
  it "should update columns changed in a before_save hook" do
@@ -489,25 +521,21 @@ describe "Model#save_changes" do
489
521
  o.x = 2
490
522
  o.save_changes
491
523
  MODEL_DB.sqls.should == ["UPDATE items SET x = 3 WHERE (id = 3)"]
492
- MODEL_DB.reset
493
524
  o.save_changes
494
525
  MODEL_DB.sqls.should == []
495
526
  o.x = 4
496
527
  o.save_changes
497
528
  MODEL_DB.sqls.should == ["UPDATE items SET x = 5 WHERE (id = 3)"]
498
- MODEL_DB.reset
499
529
  end
500
530
  end
501
531
 
502
532
  describe "Model#new?" do
503
-
504
- before(:each) do
505
- MODEL_DB.reset
506
-
533
+ before do
507
534
  @c = Class.new(Sequel::Model(:items)) do
508
535
  unrestrict_primary_key
509
536
  columns :x
510
537
  end
538
+ MODEL_DB.reset
511
539
  end
512
540
 
513
541
  it "should be true for a new instance" do
@@ -523,74 +551,65 @@ describe "Model#new?" do
523
551
  end
524
552
 
525
553
  describe Sequel::Model, "w/ primary key" do
526
-
527
554
  it "should default to ':id'" do
528
555
  model_a = Class.new Sequel::Model
529
- model_a.primary_key.should be_equal(:id)
556
+ model_a.primary_key.should == :id
530
557
  end
531
558
 
532
559
  it "should be changed through 'set_primary_key'" do
533
- model_a = Class.new(Sequel::Model) { set_primary_key :a }
534
- model_a.primary_key.should be_equal(:a)
560
+ model_a = Class.new(Sequel::Model){ set_primary_key :a }
561
+ model_a.primary_key.should == :a
535
562
  end
536
563
 
537
564
  it "should support multi argument composite keys" do
538
- model_a = Class.new(Sequel::Model) { set_primary_key :a, :b }
539
- model_a.primary_key.should be_eql([:a, :b])
565
+ model_a = Class.new(Sequel::Model){ set_primary_key :a, :b }
566
+ model_a.primary_key.should == [:a, :b]
540
567
  end
541
568
 
542
569
  it "should accept single argument composite keys" do
543
- model_a = Class.new(Sequel::Model) { set_primary_key [:a, :b] }
544
- model_a.primary_key.should be_eql([:a, :b])
570
+ model_a = Class.new(Sequel::Model){ set_primary_key [:a, :b] }
571
+ model_a.primary_key.should == [:a, :b]
545
572
  end
546
-
547
573
  end
548
574
 
549
575
  describe Sequel::Model, "w/o primary key" do
550
576
  it "should return nil for primary key" do
551
- Class.new(Sequel::Model) { no_primary_key }.primary_key.should be_nil
577
+ Class.new(Sequel::Model){no_primary_key}.primary_key.should be_nil
552
578
  end
553
579
 
554
580
  it "should raise a Sequel::Error on 'this'" do
555
- instance = Class.new(Sequel::Model) { no_primary_key }.new
556
- proc { instance.this }.should raise_error(Sequel::Error)
581
+ instance = Class.new(Sequel::Model){no_primary_key}.new
582
+ proc{instance.this}.should raise_error(Sequel::Error)
557
583
  end
558
584
  end
559
585
 
560
586
  describe Sequel::Model, "with this" do
561
-
562
- before { @example = Class.new Sequel::Model(:examples); @example.columns :id, :a, :x, :y }
587
+ before do
588
+ @example = Class.new(Sequel::Model(:examples))
589
+ @example.columns :id, :a, :x, :y
590
+ end
563
591
 
564
592
  it "should return a dataset identifying the record" do
565
- instance = @example.load :id => 3
566
- instance.this.sql.should be_eql("SELECT * FROM examples WHERE (id = 3) LIMIT 1")
593
+ instance = @example.load(:id => 3)
594
+ instance.this.sql.should == "SELECT * FROM examples WHERE (id = 3) LIMIT 1"
567
595
  end
568
596
 
569
597
  it "should support arbitary primary keys" do
570
598
  @example.set_primary_key :a
571
599
 
572
- instance = @example.load :a => 3
573
- instance.this.sql.should be_eql("SELECT * FROM examples WHERE (a = 3) LIMIT 1")
600
+ instance = @example.load(:a => 3)
601
+ instance.this.sql.should == "SELECT * FROM examples WHERE (a = 3) LIMIT 1"
574
602
  end
575
603
 
576
604
  it "should support composite primary keys" do
577
605
  @example.set_primary_key :x, :y
578
- instance = @example.load :x => 4, :y => 5
579
-
580
- parts = [
581
- 'SELECT * FROM examples WHERE %s LIMIT 1',
582
- '((x = 4) AND (y = 5))',
583
- '((y = 5) AND (x = 4))'
584
- ].map { |expr| Regexp.escape expr }
585
- regexp = Regexp.new parts.first % "(?:#{parts[1]}|#{parts[2]})"
586
-
587
- instance.this.sql.should match(regexp)
606
+ instance = @example.load(:x => 4, :y => 5)
607
+ instance.this.sql.should =~ /SELECT \* FROM examples WHERE \(\([xy] = [45]\) AND \([xy] = [45]\)\) LIMIT 1/
588
608
  end
589
-
590
609
  end
591
610
 
592
611
  describe "Model#pk" do
593
- before(:each) do
612
+ before do
594
613
  @m = Class.new(Sequel::Model)
595
614
  @m.columns :id, :x, :y
596
615
  end
@@ -623,8 +642,42 @@ describe "Model#pk" do
623
642
  end
624
643
  end
625
644
 
645
+ describe "Model#pk_or_nil" do
646
+ before do
647
+ @m = Class.new(Sequel::Model)
648
+ @m.columns :id, :x, :y
649
+ end
650
+
651
+ it "should be default return the value of the :id column" do
652
+ m = @m.load(:id => 111, :x => 2, :y => 3)
653
+ m.pk_or_nil.should == 111
654
+ end
655
+
656
+ it "should be return the primary key value for custom primary key" do
657
+ @m.set_primary_key :x
658
+ m = @m.load(:id => 111, :x => 2, :y => 3)
659
+ m.pk_or_nil.should == 2
660
+ end
661
+
662
+ it "should be return the primary key value for composite primary key" do
663
+ @m.set_primary_key [:y, :x]
664
+ m = @m.load(:id => 111, :x => 2, :y => 3)
665
+ m.pk_or_nil.should == [3, 2]
666
+ end
667
+
668
+ it "should raise if no primary key" do
669
+ @m.set_primary_key nil
670
+ m = @m.new(:id => 111, :x => 2, :y => 3)
671
+ m.pk_or_nil.should be_nil
672
+
673
+ @m.no_primary_key
674
+ m = @m.new(:id => 111, :x => 2, :y => 3)
675
+ m.pk_or_nil.should be_nil
676
+ end
677
+ end
678
+
626
679
  describe "Model#pk_hash" do
627
- before(:each) do
680
+ before do
628
681
  @m = Class.new(Sequel::Model)
629
682
  @m.columns :id, :x, :y
630
683
  end
@@ -659,16 +712,14 @@ end
659
712
 
660
713
  describe Sequel::Model, "#set" do
661
714
  before do
662
- MODEL_DB.reset
663
-
664
715
  @c = Class.new(Sequel::Model(:items)) do
665
716
  set_primary_key :id
666
717
  columns :x, :y, :id
667
718
  end
668
719
  @c.strict_param_setting = false
669
- @c.instance_variable_set(:@columns, true)
670
720
  @o1 = @c.new
671
721
  @o2 = @c.load(:id => 5)
722
+ MODEL_DB.reset
672
723
  end
673
724
 
674
725
  it "should filter the given params using the model columns" do
@@ -716,6 +767,29 @@ describe Sequel::Model, "#set" do
716
767
  MODEL_DB.sqls.should == []
717
768
  end
718
769
 
770
+ it "should raise error if strict_param_setting is true and method does not exist" do
771
+ @o1.strict_param_setting = true
772
+ proc{@o1.set('foo' => 1)}.should raise_error(Sequel::Error)
773
+ end
774
+
775
+ it "should raise error if strict_param_setting is true and column is a primary key" do
776
+ @o1.strict_param_setting = true
777
+ proc{@o1.set('id' => 1)}.should raise_error(Sequel::Error)
778
+ end
779
+
780
+ it "should raise error if strict_param_setting is true and column is restricted" do
781
+ @o1.strict_param_setting = true
782
+ @c.set_restricted_columns :x
783
+ proc{@o1.set('x' => 1)}.should raise_error(Sequel::Error)
784
+ end
785
+
786
+ it "should not create a symbol if strict_param_setting is true and string is given" do
787
+ @o1.strict_param_setting = true
788
+ l = Symbol.all_symbols.length
789
+ proc{@o1.set('sadojafdso' => 1)}.should raise_error(Sequel::Error)
790
+ Symbol.all_symbols.length.should == l
791
+ end
792
+
719
793
  it "#set should correctly handle cases where an instance method is added to the class" do
720
794
  @o1.set(:x => 1)
721
795
  @o1.values.should == {:x => 1}
@@ -739,51 +813,74 @@ describe Sequel::Model, "#set" do
739
813
  @o1.set(:x => 2, :z => 3)
740
814
  @o1.values.should == {:x => 2, :z=>3}
741
815
  end
816
+
817
+ it "#set should correctly handle cases where a module with a setter method is included in the class" do
818
+ @o1.set(:x => 1)
819
+ @o1.values.should == {:x => 1}
820
+
821
+ @c.send(:include, Module.new do
822
+ def z=(v)
823
+ self[:z] = v
824
+ end
825
+ end)
826
+ @o1.set(:x => 2, :z => 3)
827
+ @o1.values.should == {:x => 2, :z=>3}
828
+ end
829
+
830
+ it "#set should correctly handle cases where the object extends a module with a setter method " do
831
+ @o1.set(:x => 1)
832
+ @o1.values.should == {:x => 1}
833
+
834
+ @o1.extend(Module.new do
835
+ def z=(v)
836
+ self[:z] = v
837
+ end
838
+ end)
839
+ @o1.set(:x => 2, :z => 3)
840
+ @o1.values.should == {:x => 2, :z=>3}
841
+ end
742
842
  end
743
843
 
744
844
  describe Sequel::Model, "#update" do
745
845
  before do
746
- MODEL_DB.reset
747
-
748
846
  @c = Class.new(Sequel::Model(:items)) do
749
847
  set_primary_key :id
750
848
  columns :x, :y, :id
751
849
  end
752
850
  @c.strict_param_setting = false
753
- @c.instance_variable_set(:@columns, true)
754
851
  @o1 = @c.new
755
852
  @o2 = @c.load(:id => 5)
853
+ MODEL_DB.reset
756
854
  end
757
855
 
758
856
  it "should filter the given params using the model columns" do
759
857
  @o1.update(:x => 1, :z => 2)
760
- MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
858
+ MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (1)", "SELECT * FROM items WHERE (id = 10) LIMIT 1"]
761
859
 
762
860
  MODEL_DB.reset
763
861
  @o2.update(:y => 1, :abc => 2)
764
- MODEL_DB.sqls.first.should == "UPDATE items SET y = 1 WHERE (id = 5)"
862
+ MODEL_DB.sqls.should == ["UPDATE items SET y = 1 WHERE (id = 5)"]
765
863
  end
766
864
 
767
865
  it "should support virtual attributes" do
768
866
  @c.send(:define_method, :blah=){|v| self.x = v}
769
867
  @o1.update(:blah => 333)
770
- MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (333)"
868
+ MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (333)", "SELECT * FROM items WHERE (id = 10) LIMIT 1"]
771
869
  end
772
870
 
773
871
  it "should not modify the primary key" do
774
872
  @o1.update(:x => 1, :id => 2)
775
- MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
873
+ MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (1)", "SELECT * FROM items WHERE (id = 10) LIMIT 1"]
776
874
  MODEL_DB.reset
777
875
  @o2.update('y'=> 1, 'id'=> 2)
778
876
  @o2.values.should == {:y => 1, :id=> 5}
779
- MODEL_DB.sqls.first.should == "UPDATE items SET y = 1 WHERE (id = 5)"
877
+ MODEL_DB.sqls.should == ["UPDATE items SET y = 1 WHERE (id = 5)"]
780
878
  end
781
879
  end
782
880
 
783
881
  describe Sequel::Model, "#set_fields" do
784
882
  before do
785
- @c = Class.new(Sequel::Model(:items))
786
- @c.class_eval do
883
+ @c = Class.new(Sequel::Model(:items)) do
787
884
  set_primary_key :id
788
885
  columns :x, :y, :z, :id
789
886
  end
@@ -803,11 +900,9 @@ end
803
900
 
804
901
  describe Sequel::Model, "#update_fields" do
805
902
  before do
806
- @c = Class.new(Sequel::Model(:items))
807
- @c.class_eval do
903
+ @c = Class.new(Sequel::Model(:items)) do
808
904
  set_primary_key :id
809
905
  columns :x, :y, :z, :id
810
- def _refresh(ds); end
811
906
  end
812
907
  @c.strict_param_setting = true
813
908
  @o1 = @c.load(:id=>1)
@@ -817,21 +912,18 @@ describe Sequel::Model, "#update_fields" do
817
912
  it "should set only the given fields, and then save the changes to the record" do
818
913
  @o1.update_fields({:x => 1, :y => 2, :z=>3, :id=>4}, [:x, :y])
819
914
  @o1.values.should == {:x => 1, :y => 2, :id=>1}
820
- MODEL_DB.sqls.first.should =~ /UPDATE items SET [xy] = [12], [xy] = [12] WHERE \(id = 1\)/
821
- MODEL_DB.sqls.length.should == 1
822
- MODEL_DB.reset
915
+ sqls = MODEL_DB.sqls
916
+ sqls.pop.should =~ /UPDATE items SET [xy] = [12], [xy] = [12] WHERE \(id = 1\)/
917
+ sqls.should == []
823
918
 
824
919
  @o1.update_fields({:x => 1, :y => 5, :z=>6, :id=>7}, [:x, :y])
825
920
  @o1.values.should == {:x => 1, :y => 5, :id=>1}
826
921
  MODEL_DB.sqls.should == ["UPDATE items SET y = 5 WHERE (id = 1)"]
827
- MODEL_DB.reset
828
922
  end
829
923
  end
830
924
 
831
925
  describe Sequel::Model, "#(set|update)_(all|except|only)" do
832
926
  before do
833
- MODEL_DB.reset
834
-
835
927
  @c = Class.new(Sequel::Model(:items)) do
836
928
  set_primary_key :id
837
929
  columns :x, :y, :z, :id
@@ -839,8 +931,8 @@ describe Sequel::Model, "#(set|update)_(all|except|only)" do
839
931
  set_restricted_columns :y
840
932
  end
841
933
  @c.strict_param_setting = false
842
- @c.instance_variable_set(:@columns, true)
843
934
  @o1 = @c.new
935
+ MODEL_DB.reset
844
936
  end
845
937
 
846
938
  it "should raise errors if not all hash fields can be set and strict_param_setting is true" do
@@ -884,40 +976,34 @@ describe Sequel::Model, "#(set|update)_(all|except|only)" do
884
976
 
885
977
  it "#update_all should update all attributes" do
886
978
  @c.new.update_all(:x => 1, :id=>4)
887
- MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
888
- MODEL_DB.reset
979
+ MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (1)", "SELECT * FROM items WHERE (id = 10) LIMIT 1"]
889
980
  @c.new.update_all(:y => 1, :id=>4)
890
- MODEL_DB.sqls.first.should == "INSERT INTO items (y) VALUES (1)"
891
- MODEL_DB.reset
981
+ MODEL_DB.sqls.should == ["INSERT INTO items (y) VALUES (1)", "SELECT * FROM items WHERE (id = 10) LIMIT 1"]
892
982
  @c.new.update_all(:z => 1, :id=>4)
893
- MODEL_DB.sqls.first.should == "INSERT INTO items (z) VALUES (1)"
983
+ MODEL_DB.sqls.should == ["INSERT INTO items (z) VALUES (1)", "SELECT * FROM items WHERE (id = 10) LIMIT 1"]
894
984
  end
895
985
 
896
986
  it "#update_only should only update given attributes" do
897
987
  @o1.update_only({:x => 1, :y => 2, :z=>3, :id=>4}, [:x])
898
- MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
899
- MODEL_DB.reset
988
+ MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (1)", "SELECT * FROM items WHERE (id = 10) LIMIT 1"]
900
989
  @c.new.update_only({:x => 1, :y => 2, :z=>3, :id=>4}, :x)
901
- MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
990
+ MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (1)", "SELECT * FROM items WHERE (id = 10) LIMIT 1"]
902
991
  end
903
992
 
904
993
  it "#update_except should not update given attributes" do
905
994
  @o1.update_except({:x => 1, :y => 2, :z=>3, :id=>4}, [:y, :z])
906
- MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
907
- MODEL_DB.reset
995
+ MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (1)", "SELECT * FROM items WHERE (id = 10) LIMIT 1"]
908
996
  @c.new.update_except({:x => 1, :y => 2, :z=>3, :id=>4}, :y, :z)
909
- MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
997
+ MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (1)", "SELECT * FROM items WHERE (id = 10) LIMIT 1"]
910
998
  end
911
999
  end
912
1000
 
913
1001
  describe Sequel::Model, "#destroy" do
914
1002
  before do
915
- MODEL_DB.reset
916
1003
  @model = Class.new(Sequel::Model(:items))
917
1004
  @model.columns :id
918
- @model.dataset.meta_def(:delete){MODEL_DB.execute delete_sql;1}
919
-
920
1005
  @instance = @model.load(:id => 1234)
1006
+ MODEL_DB.reset
921
1007
  end
922
1008
 
923
1009
  it "should return self" do
@@ -942,49 +1028,40 @@ describe Sequel::Model, "#destroy" do
942
1028
 
943
1029
  it "should run within a transaction if use_transactions is true" do
944
1030
  @instance.use_transactions = true
945
- @model.db.should_receive(:transaction)
946
1031
  @instance.destroy
1032
+ MODEL_DB.sqls.should == ["BEGIN", "DELETE FROM items WHERE (id = 1234)", "COMMIT"]
947
1033
  end
948
1034
 
949
1035
  it "should not run within a transaction if use_transactions is false" do
950
1036
  @instance.use_transactions = false
951
- @model.db.should_not_receive(:transaction)
952
1037
  @instance.destroy
1038
+ MODEL_DB.sqls.should == ["DELETE FROM items WHERE (id = 1234)"]
953
1039
  end
954
1040
 
955
1041
  it "should run within a transaction if :transaction option is true" do
956
1042
  @instance.use_transactions = false
957
- @model.db.should_receive(:transaction)
958
1043
  @instance.destroy(:transaction => true)
1044
+ MODEL_DB.sqls.should == ["BEGIN", "DELETE FROM items WHERE (id = 1234)", "COMMIT"]
959
1045
  end
960
1046
 
961
1047
  it "should not run within a transaction if :transaction option is false" do
962
1048
  @instance.use_transactions = true
963
- @model.db.should_not_receive(:transaction)
964
1049
  @instance.destroy(:transaction => false)
1050
+ MODEL_DB.sqls.should == ["DELETE FROM items WHERE (id = 1234)"]
965
1051
  end
966
1052
 
967
1053
  it "should run before_destroy and after_destroy hooks" do
968
1054
  @model.send(:define_method, :before_destroy){MODEL_DB.execute('before blah')}
969
1055
  @model.send(:define_method, :after_destroy){MODEL_DB.execute('after blah')}
970
1056
  @instance.destroy
971
-
972
- MODEL_DB.sqls.should == [
973
- "before blah",
974
- "DELETE FROM items WHERE (id = 1234)",
975
- "after blah"
976
- ]
1057
+ MODEL_DB.sqls.should == ["before blah", "DELETE FROM items WHERE (id = 1234)", "after blah"]
977
1058
  end
978
1059
  end
979
1060
 
980
1061
  describe Sequel::Model, "#exists?" do
981
- before(:each) do
1062
+ before do
982
1063
  @model = Class.new(Sequel::Model(:items))
983
- @ds = @model.dataset
984
- def @ds.fetch_rows(sql)
985
- db.execute(sql)
986
- yield(:x=>1) if sql =~ /id = 1/
987
- end
1064
+ @model.dataset._fetch = proc{|sql| {:x=>1} if sql =~ /id = 1/}
988
1065
  MODEL_DB.reset
989
1066
  end
990
1067
 
@@ -997,6 +1074,11 @@ describe Sequel::Model, "#exists?" do
997
1074
  @model.load(:id=>2).exists?.should be_false
998
1075
  MODEL_DB.sqls.should == ['SELECT 1 FROM items WHERE (id = 2) LIMIT 1']
999
1076
  end
1077
+
1078
+ it "should return false without issuing a query if the model object is new" do
1079
+ @model.new.exists?.should be_false
1080
+ MODEL_DB.sqls.should == []
1081
+ end
1000
1082
  end
1001
1083
 
1002
1084
  describe Sequel::Model, "#each" do
@@ -1008,7 +1090,7 @@ describe Sequel::Model, "#each" do
1008
1090
 
1009
1091
  specify "should iterate over the values" do
1010
1092
  h = {}
1011
- @m.each {|k, v| h[k] = v}
1093
+ @m.each{|k, v| h[k] = v}
1012
1094
  h.should == {:a => 1, :b => 2, :id => 4444}
1013
1095
  end
1014
1096
  end
@@ -1021,11 +1103,8 @@ describe Sequel::Model, "#keys" do
1021
1103
  end
1022
1104
 
1023
1105
  specify "should return the value keys" do
1024
- @m.keys.size.should == 3
1025
- @m.keys.should include(:a, :b, :id)
1026
-
1027
- @m = @model.new()
1028
- @m.keys.should == []
1106
+ @m.keys.sort_by{|k| k.to_s}.should == [:a, :b, :id]
1107
+ @model.new.keys.should == []
1029
1108
  end
1030
1109
  end
1031
1110
 
@@ -1094,13 +1173,10 @@ describe Sequel::Model, "#hash" do
1094
1173
  y = Class.new(Sequel::Model)
1095
1174
  y.columns :id, :x
1096
1175
  a = z.load(:id => 1, :x => 3)
1097
- b = z.load(:id => 1, :x => 4)
1098
- c = z.load(:id => 2, :x => 3)
1099
- d = y.load(:id => 1, :x => 3)
1100
1176
 
1101
- a.hash.should == b.hash
1102
- a.hash.should_not == c.hash
1103
- a.hash.should_not == d.hash
1177
+ a.hash.should == z.load(:id => 1, :x => 4).hash
1178
+ a.hash.should_not == z.load(:id => 2, :x => 3).hash
1179
+ a.hash.should_not == y.load(:id => 1, :x => 3).hash
1104
1180
  end
1105
1181
 
1106
1182
  specify "should be the same only for objects with the same class and values if the pk is nil" do
@@ -1109,14 +1185,71 @@ describe Sequel::Model, "#hash" do
1109
1185
  y = Class.new(Sequel::Model)
1110
1186
  y.columns :id, :x
1111
1187
  a = z.new(:x => 3)
1112
- b = z.new(:x => 4)
1113
- c = z.new(:x => 3)
1114
- d = y.new(:x => 3)
1115
1188
 
1116
- a.hash.should_not == b.hash
1117
- a.hash.should == c.hash
1118
- a.hash.should_not == d.hash
1189
+ a.hash.should_not == z.new(:x => 4).hash
1190
+ a.hash.should == z.new(:x => 3).hash
1191
+ a.hash.should_not == y.new(:x => 3).hash
1192
+ end
1193
+
1194
+ specify "should be the same only for objects with the same class and pk if pk is composite and all values are non-NULL" do
1195
+ z = Class.new(Sequel::Model)
1196
+ z.columns :id, :id2, :x
1197
+ z.set_primary_key(:id, :id2)
1198
+ y = Class.new(Sequel::Model)
1199
+ y.columns :id, :id2, :x
1200
+ y.set_primary_key(:id, :id2)
1201
+ a = z.load(:id => 1, :id2=>2, :x => 3)
1202
+
1203
+ a.hash.should == z.load(:id => 1, :id2=>2, :x => 4).hash
1204
+ a.hash.should_not == z.load(:id => 2, :id2=>1, :x => 3).hash
1205
+ a.hash.should_not == y.load(:id => 1, :id2=>1, :x => 3).hash
1206
+ end
1207
+
1208
+ specify "should be the same only for objects with the same class and value if pk is composite and one values is NULL" do
1209
+ z = Class.new(Sequel::Model)
1210
+ z.columns :id, :id2, :x
1211
+ z.set_primary_key(:id, :id2)
1212
+ y = Class.new(Sequel::Model)
1213
+ y.columns :id, :id2, :x
1214
+ y.set_primary_key(:id, :id2)
1215
+
1216
+ a = z.load(:id => 1, :id2 => nil, :x => 3)
1217
+ a.hash.should == z.load(:id => 1, :id2=>nil, :x => 3).hash
1218
+ a.hash.should_not == z.load(:id => 1, :id2=>nil, :x => 4).hash
1219
+ a.hash.should_not == y.load(:id => 1, :id2=>nil, :x => 3).hash
1220
+
1221
+ a = z.load(:id =>nil, :id2 => nil, :x => 3)
1222
+ a.hash.should == z.load(:id => nil, :id2=>nil, :x => 3).hash
1223
+ a.hash.should_not == z.load(:id => nil, :id2=>nil, :x => 4).hash
1224
+ a.hash.should_not == y.load(:id => nil, :id2=>nil, :x => 3).hash
1225
+
1226
+ a = z.load(:id => 1, :x => 3)
1227
+ a.hash.should == z.load(:id => 1, :x => 3).hash
1228
+ a.hash.should_not == z.load(:id => 1, :id2=>nil, :x => 3).hash
1229
+ a.hash.should_not == z.load(:id => 1, :x => 4).hash
1230
+ a.hash.should_not == y.load(:id => 1, :x => 3).hash
1231
+
1232
+ a = z.load(:x => 3)
1233
+ a.hash.should == z.load(:x => 3).hash
1234
+ a.hash.should_not == z.load(:id => nil, :id2=>nil, :x => 3).hash
1235
+ a.hash.should_not == z.load(:x => 4).hash
1236
+ a.hash.should_not == y.load(:x => 3).hash
1237
+ end
1238
+
1239
+ specify "should be the same only for objects with the same class and values if the no primary key" do
1240
+ z = Class.new(Sequel::Model)
1241
+ z.columns :id, :x
1242
+ z.no_primary_key
1243
+ y = Class.new(Sequel::Model)
1244
+ y.columns :id, :x
1245
+ y.no_primary_key
1246
+ a = z.new(:x => 3)
1247
+
1248
+ a.hash.should_not == z.new(:x => 4).hash
1249
+ a.hash.should == z.new(:x => 3).hash
1250
+ a.hash.should_not == y.new(:x => 3).hash
1119
1251
  end
1252
+
1120
1253
  end
1121
1254
 
1122
1255
  describe Sequel::Model, "#initialize" do
@@ -1161,10 +1294,32 @@ describe Sequel::Model, "#initialize" do
1161
1294
  m.values.should == {:x => 2}
1162
1295
  end
1163
1296
  end
1297
+
1298
+ describe Sequel::Model, "#initialize_set" do
1299
+ before do
1300
+ @c = Class.new(Sequel::Model){columns :id, :x, :y}
1301
+ end
1164
1302
 
1165
- describe Sequel::Model, ".create" do
1303
+ specify "should be called by initialize to set the column values" do
1304
+ @c.send(:define_method, :initialize_set){|h| set(:y => 3)}
1305
+ @c.new(:x => 2).values.should == {:y => 3}
1306
+ end
1307
+
1308
+ specify "should be called with the hash given to initialize " do
1309
+ x = nil
1310
+ @c.send(:define_method, :initialize_set){|y| x = y}
1311
+ @c.new(:x => 2)
1312
+ x.should == {:x => 2}
1313
+ end
1166
1314
 
1167
- before(:each) do
1315
+ specify "should not cause columns modified by the method to be considered as changed" do
1316
+ @c.send(:define_method, :initialize_set){|h| set(:y => 3)}
1317
+ @c.new(:x => 2).changed_columns.should == []
1318
+ end
1319
+ end
1320
+
1321
+ describe Sequel::Model, ".create" do
1322
+ before do
1168
1323
  MODEL_DB.reset
1169
1324
  @c = Class.new(Sequel::Model(:items)) do
1170
1325
  unrestrict_primary_key
@@ -1175,13 +1330,13 @@ describe Sequel::Model, ".create" do
1175
1330
  it "should be able to create rows in the associated table" do
1176
1331
  o = @c.create(:x => 1)
1177
1332
  o.class.should == @c
1178
- MODEL_DB.sqls.should == ['INSERT INTO items (x) VALUES (1)', "SELECT * FROM items WHERE (id IN ('INSERT INTO items (x) VALUES (1)')) LIMIT 1"]
1333
+ MODEL_DB.sqls.should == ['INSERT INTO items (x) VALUES (1)', "SELECT * FROM items WHERE (id = 10) LIMIT 1"]
1179
1334
  end
1180
1335
 
1181
1336
  it "should be able to create rows without any values specified" do
1182
1337
  o = @c.create
1183
1338
  o.class.should == @c
1184
- MODEL_DB.sqls.should == ["INSERT INTO items DEFAULT VALUES", "SELECT * FROM items WHERE (id IN ('INSERT INTO items DEFAULT VALUES')) LIMIT 1"]
1339
+ MODEL_DB.sqls.should == ["INSERT INTO items DEFAULT VALUES", "SELECT * FROM items WHERE (id = 10) LIMIT 1"]
1185
1340
  end
1186
1341
 
1187
1342
  it "should accept a block and run it" do
@@ -1191,7 +1346,7 @@ describe Sequel::Model, ".create" do
1191
1346
  o1.should === o
1192
1347
  o3.should === o
1193
1348
  o2.should == :blah
1194
- MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (333)", "SELECT * FROM items WHERE (id IN ('INSERT INTO items (x) VALUES (333)')) LIMIT 1"]
1349
+ MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (333)", "SELECT * FROM items WHERE (id = 10) LIMIT 1"]
1195
1350
  end
1196
1351
 
1197
1352
  it "should create a row for a model with custom primary key" do
@@ -1204,32 +1359,35 @@ end
1204
1359
 
1205
1360
  describe Sequel::Model, "#refresh" do
1206
1361
  before do
1207
- MODEL_DB.reset
1208
1362
  @c = Class.new(Sequel::Model(:items)) do
1209
1363
  unrestrict_primary_key
1210
1364
  columns :id, :x
1211
1365
  end
1366
+ MODEL_DB.reset
1212
1367
  end
1213
1368
 
1214
1369
  specify "should reload the instance values from the database" do
1215
1370
  @m = @c.new(:id => 555)
1216
1371
  @m[:x] = 'blah'
1217
- @m.this.should_receive(:first).and_return({:x => 'kaboom', :id => 555})
1372
+ @c.dataset._fetch = {:x => 'kaboom', :id => 555}
1218
1373
  @m.refresh
1219
1374
  @m[:x].should == 'kaboom'
1375
+ MODEL_DB.sqls.should == ["SELECT * FROM items WHERE (id = 555) LIMIT 1"]
1220
1376
  end
1221
1377
 
1222
1378
  specify "should raise if the instance is not found" do
1223
1379
  @m = @c.new(:id => 555)
1224
- @m.this.should_receive(:first).and_return(nil)
1380
+ @c.dataset._fetch = []
1225
1381
  proc {@m.refresh}.should raise_error(Sequel::Error)
1382
+ MODEL_DB.sqls.should == ["SELECT * FROM items WHERE (id = 555) LIMIT 1"]
1226
1383
  end
1227
1384
 
1228
1385
  specify "should be aliased by #reload" do
1229
1386
  @m = @c.new(:id => 555)
1230
- @m.this.should_receive(:first).and_return({:x => 'kaboom', :id => 555})
1387
+ @c.dataset._fetch = {:x => 'kaboom', :id => 555}
1231
1388
  @m.reload
1232
1389
  @m[:x].should == 'kaboom'
1390
+ MODEL_DB.sqls.should == ["SELECT * FROM items WHERE (id = 555) LIMIT 1"]
1233
1391
  end
1234
1392
 
1235
1393
  specify "should remove cached associations" do
@@ -1243,10 +1401,11 @@ end
1243
1401
 
1244
1402
  describe Sequel::Model, "typecasting" do
1245
1403
  before do
1246
- MODEL_DB.reset
1247
1404
  @c = Class.new(Sequel::Model(:items)) do
1248
1405
  columns :x
1249
1406
  end
1407
+ @c.db_schema = {:x=>{:type=>:integer}}
1408
+ MODEL_DB.reset
1250
1409
  end
1251
1410
 
1252
1411
  after do
@@ -1255,14 +1414,13 @@ describe Sequel::Model, "typecasting" do
1255
1414
 
1256
1415
  specify "should not convert if typecasting is turned off" do
1257
1416
  @c.typecast_on_assignment = false
1258
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer}})
1259
1417
  m = @c.new
1260
1418
  m.x = '1'
1261
1419
  m.x.should == '1'
1262
1420
  end
1263
1421
 
1264
1422
  specify "should convert to integer for an integer field" do
1265
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer}})
1423
+ @c.db_schema = {:x=>{:type=>:integer}}
1266
1424
  m = @c.new
1267
1425
  m.x = '1'
1268
1426
  m.x.should == 1
@@ -1274,13 +1432,13 @@ describe Sequel::Model, "typecasting" do
1274
1432
 
1275
1433
  specify "should typecast '' to nil unless type is string or blob" do
1276
1434
  [:integer, :float, :decimal, :boolean, :date, :time, :datetime].each do |x|
1277
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>x}})
1435
+ @c.db_schema = {:x=>{:type=>x}}
1278
1436
  m = @c.new
1279
1437
  m.x = ''
1280
1438
  m.x.should == nil
1281
1439
  end
1282
1440
  [:string, :blob].each do |x|
1283
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>x}})
1441
+ @c.db_schema = {:x=>{:type=>x}}
1284
1442
  m = @c.new
1285
1443
  m.x = ''
1286
1444
  m.x.should == ''
@@ -1288,7 +1446,6 @@ describe Sequel::Model, "typecasting" do
1288
1446
  end
1289
1447
 
1290
1448
  specify "should not typecast '' to nil if typecast_empty_string_to_nil is false" do
1291
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer}})
1292
1449
  m = @c.new
1293
1450
  m.typecast_empty_string_to_nil = false
1294
1451
  proc{m.x = ''}.should raise_error
@@ -1297,21 +1454,21 @@ describe Sequel::Model, "typecasting" do
1297
1454
  end
1298
1455
 
1299
1456
  specify "should not typecast nil if NULLs are allowed" do
1300
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer,:allow_null=>true}})
1457
+ @c.db_schema[:x][:allow_null] = true
1301
1458
  m = @c.new
1302
1459
  m.x = nil
1303
1460
  m.x.should == nil
1304
1461
  end
1305
1462
 
1306
1463
  specify "should raise an error if attempting to typecast nil and NULLs are not allowed" do
1307
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer,:allow_null=>false}})
1464
+ @c.db_schema[:x][:allow_null] = false
1308
1465
  proc{@c.new.x = nil}.should raise_error(Sequel::Error)
1309
1466
  proc{@c.new.x = ''}.should raise_error(Sequel::Error)
1310
1467
  end
1311
1468
 
1312
1469
  specify "should not raise an error if NULLs are not allowed and typecasting is turned off" do
1313
1470
  @c.typecast_on_assignment = false
1314
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer,:allow_null=>false}})
1471
+ @c.db_schema[:x][:allow_null] = false
1315
1472
  m = @c.new
1316
1473
  m.x = nil
1317
1474
  m.x.should == nil
@@ -1320,7 +1477,6 @@ describe Sequel::Model, "typecasting" do
1320
1477
  specify "should not raise when typecasting nil to NOT NULL column but raise_on_typecast_failure is off" do
1321
1478
  @c.raise_on_typecast_failure = false
1322
1479
  @c.typecast_on_assignment = true
1323
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer,:allow_null=>false}})
1324
1480
  m = @c.new
1325
1481
  m.x = ''
1326
1482
  m.x.should == nil
@@ -1329,20 +1485,18 @@ describe Sequel::Model, "typecasting" do
1329
1485
  end
1330
1486
 
1331
1487
  specify "should raise an error if invalid data is used in an integer field" do
1332
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer}})
1333
1488
  proc{@c.new.x = 'a'}.should raise_error(Sequel::InvalidValue)
1334
1489
  end
1335
1490
 
1336
1491
  specify "should assign value if raise_on_typecast_failure is off and assigning invalid integer" do
1337
1492
  @c.raise_on_typecast_failure = false
1338
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer}})
1339
1493
  model = @c.new
1340
1494
  model.x = '1d'
1341
1495
  model.x.should == '1d'
1342
1496
  end
1343
1497
 
1344
1498
  specify "should convert to float for a float field" do
1345
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:float}})
1499
+ @c.db_schema = {:x=>{:type=>:float}}
1346
1500
  m = @c.new
1347
1501
  m.x = '1.3'
1348
1502
  m.x.should == 1.3
@@ -1353,20 +1507,20 @@ describe Sequel::Model, "typecasting" do
1353
1507
  end
1354
1508
 
1355
1509
  specify "should raise an error if invalid data is used in an float field" do
1356
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:float}})
1510
+ @c.db_schema = {:x=>{:type=>:float}}
1357
1511
  proc{@c.new.x = 'a'}.should raise_error(Sequel::InvalidValue)
1358
1512
  end
1359
1513
 
1360
1514
  specify "should assign value if raise_on_typecast_failure is off and assigning invalid float" do
1361
1515
  @c.raise_on_typecast_failure = false
1362
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:float}})
1516
+ @c.db_schema = {:x=>{:type=>:float}}
1363
1517
  model = @c.new
1364
1518
  model.x = '1d'
1365
1519
  model.x.should == '1d'
1366
1520
  end
1367
1521
 
1368
1522
  specify "should convert to BigDecimal for a decimal field" do
1369
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:decimal}})
1523
+ @c.db_schema = {:x=>{:type=>:decimal}}
1370
1524
  m = @c.new
1371
1525
  bd = BigDecimal.new('1.0')
1372
1526
  m.x = '1.0'
@@ -1380,13 +1534,13 @@ describe Sequel::Model, "typecasting" do
1380
1534
  end
1381
1535
 
1382
1536
  specify "should raise an error if invalid data is used in an decimal field" do
1383
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:decimal}})
1537
+ @c.db_schema = {:x=>{:type=>:decimal}}
1384
1538
  proc{@c.new.x = Date.today}.should raise_error(Sequel::InvalidValue)
1385
1539
  end
1386
1540
 
1387
1541
  specify "should assign value if raise_on_typecast_failure is off and assigning invalid decimal" do
1388
1542
  @c.raise_on_typecast_failure = false
1389
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:decimal}})
1543
+ @c.db_schema = {:x=>{:type=>:decimal}}
1390
1544
  model = @c.new
1391
1545
  time = Time.now
1392
1546
  model.x = time
@@ -1394,7 +1548,7 @@ describe Sequel::Model, "typecasting" do
1394
1548
  end
1395
1549
 
1396
1550
  specify "should convert to string for a string field" do
1397
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:string}})
1551
+ @c.db_schema = {:x=>{:type=>:string}}
1398
1552
  m = @c.new
1399
1553
  m.x = '1.3'
1400
1554
  m.x.should == '1.3'
@@ -1405,7 +1559,7 @@ describe Sequel::Model, "typecasting" do
1405
1559
  end
1406
1560
 
1407
1561
  specify "should convert to boolean for a boolean field" do
1408
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:boolean}})
1562
+ @c.db_schema = {:x=>{:type=>:boolean}}
1409
1563
  m = @c.new
1410
1564
  m.x = '1.3'
1411
1565
  m.x.should == true
@@ -1417,6 +1571,10 @@ describe Sequel::Model, "typecasting" do
1417
1571
  m.x.should == true
1418
1572
  m.x = 'T'
1419
1573
  m.x.should == true
1574
+ m.x = 'y'
1575
+ m.x.should == true
1576
+ m.x = 'Y'
1577
+ m.x.should == true
1420
1578
  m.x = true
1421
1579
  m.x.should == true
1422
1580
  m.x = nil
@@ -1433,6 +1591,14 @@ describe Sequel::Model, "typecasting" do
1433
1591
  m.x.should == false
1434
1592
  m.x = 'FALSE'
1435
1593
  m.x.should == false
1594
+ m.x = 'n'
1595
+ m.x.should == false
1596
+ m.x = 'N'
1597
+ m.x.should == false
1598
+ m.x = 'no'
1599
+ m.x.should == false
1600
+ m.x = 'NO'
1601
+ m.x.should == false
1436
1602
  m.x = '0'
1437
1603
  m.x.should == false
1438
1604
  m.x = 0
@@ -1442,7 +1608,7 @@ describe Sequel::Model, "typecasting" do
1442
1608
  end
1443
1609
 
1444
1610
  specify "should convert to date for a date field" do
1445
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:date}})
1611
+ @c.db_schema = {:x=>{:type=>:date}}
1446
1612
  m = @c.new
1447
1613
  y = Date.new(2007,10,21)
1448
1614
  m.x = '2007-10-21'
@@ -1456,7 +1622,7 @@ describe Sequel::Model, "typecasting" do
1456
1622
  end
1457
1623
 
1458
1624
  specify "should accept a hash with symbol or string keys for a date field" do
1459
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:date}})
1625
+ @c.db_schema = {:x=>{:type=>:date}}
1460
1626
  m = @c.new
1461
1627
  y = Date.new(2007,10,21)
1462
1628
  m.x = {:year=>2007, :month=>10, :day=>21}
@@ -1466,32 +1632,33 @@ describe Sequel::Model, "typecasting" do
1466
1632
  end
1467
1633
 
1468
1634
  specify "should raise an error if invalid data is used in a date field" do
1469
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:date}})
1635
+ @c.db_schema = {:x=>{:type=>:date}}
1470
1636
  proc{@c.new.x = 'a'}.should raise_error(Sequel::InvalidValue)
1471
1637
  proc{@c.new.x = 100}.should raise_error(Sequel::InvalidValue)
1472
1638
  end
1473
1639
 
1474
1640
  specify "should assign value if raise_on_typecast_failure is off and assigning invalid date" do
1475
1641
  @c.raise_on_typecast_failure = false
1476
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:date}})
1642
+ @c.db_schema = {:x=>{:type=>:date}}
1477
1643
  model = @c.new
1478
1644
  model.x = 4
1479
1645
  model.x.should == 4
1480
1646
  end
1481
1647
 
1482
- specify "should convert to time for a time field" do
1483
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:time}})
1648
+ specify "should convert to Sequel::SQLTime for a time field" do
1649
+ @c.db_schema = {:x=>{:type=>:time}}
1484
1650
  m = @c.new
1485
1651
  x = '10:20:30'
1486
- y = Time.parse(x)
1652
+ y = Sequel::SQLTime.parse(x)
1487
1653
  m.x = x
1488
1654
  m.x.should == y
1489
1655
  m.x = y
1490
1656
  m.x.should == y
1657
+ m.x.should be_a_kind_of(Sequel::SQLTime)
1491
1658
  end
1492
1659
 
1493
1660
  specify "should accept a hash with symbol or string keys for a time field" do
1494
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:time}})
1661
+ @c.db_schema = {:x=>{:type=>:time}}
1495
1662
  m = @c.new
1496
1663
  y = Time.parse('10:20:30')
1497
1664
  m.x = {:hour=>10, :minute=>20, :second=>30}
@@ -1501,7 +1668,7 @@ describe Sequel::Model, "typecasting" do
1501
1668
  end
1502
1669
 
1503
1670
  specify "should raise an error if invalid data is used in a time field" do
1504
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:time}})
1671
+ @c.db_schema = {:x=>{:type=>:time}}
1505
1672
  proc{@c.new.x = '0000'}.should raise_error
1506
1673
  proc{@c.new.x = Date.parse('2008-10-21')}.should raise_error(Sequel::InvalidValue)
1507
1674
  proc{@c.new.x = DateTime.parse('2008-10-21')}.should raise_error(Sequel::InvalidValue)
@@ -1509,14 +1676,14 @@ describe Sequel::Model, "typecasting" do
1509
1676
 
1510
1677
  specify "should assign value if raise_on_typecast_failure is off and assigning invalid time" do
1511
1678
  @c.raise_on_typecast_failure = false
1512
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:time}})
1679
+ @c.db_schema = {:x=>{:type=>:time}}
1513
1680
  model = @c.new
1514
1681
  model.x = '0000'
1515
1682
  model.x.should == '0000'
1516
1683
  end
1517
1684
 
1518
1685
  specify "should convert to the Sequel.datetime_class for a datetime field" do
1519
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:datetime}})
1686
+ @c.db_schema = {:x=>{:type=>:datetime}}
1520
1687
  m = @c.new
1521
1688
  x = '2007-10-21T10:20:30-07:00'
1522
1689
  y = Time.parse(x)
@@ -1541,7 +1708,7 @@ describe Sequel::Model, "typecasting" do
1541
1708
  end
1542
1709
 
1543
1710
  specify "should accept a hash with symbol or string keys for a datetime field" do
1544
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:datetime}})
1711
+ @c.db_schema = {:x=>{:type=>:datetime}}
1545
1712
  m = @c.new
1546
1713
  y = Time.parse('2007-10-21 10:20:30')
1547
1714
  m.x = {:year=>2007, :month=>10, :day=>21, :hour=>10, :minute=>20, :second=>30}
@@ -1557,7 +1724,7 @@ describe Sequel::Model, "typecasting" do
1557
1724
  end
1558
1725
 
1559
1726
  specify "should raise an error if invalid data is used in a datetime field" do
1560
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:datetime}})
1727
+ @c.db_schema = {:x=>{:type=>:datetime}}
1561
1728
  proc{@c.new.x = '0000'}.should raise_error(Sequel::InvalidValue)
1562
1729
  Sequel.datetime_class = DateTime
1563
1730
  proc{@c.new.x = '0000'}.should raise_error(Sequel::InvalidValue)
@@ -1566,7 +1733,7 @@ describe Sequel::Model, "typecasting" do
1566
1733
 
1567
1734
  specify "should assign value if raise_on_typecast_failure is off and assigning invalid datetime" do
1568
1735
  @c.raise_on_typecast_failure = false
1569
- @c.instance_variable_set(:@db_schema, {:x=>{:type=>:datetime}})
1736
+ @c.db_schema = {:x=>{:type=>:datetime}}
1570
1737
  model = @c.new
1571
1738
  model.x = '0000'
1572
1739
  model.x.should == '0000'
@@ -1584,11 +1751,7 @@ describe "Model#lock!" do
1584
1751
  @c = Class.new(Sequel::Model(:items)) do
1585
1752
  columns :id
1586
1753
  end
1587
- ds = @c.dataset
1588
- def ds.fetch_rows(sql)
1589
- db.execute(sql)
1590
- yield({:id=>1})
1591
- end
1754
+ @c.dataset._fetch = {:id=>1}
1592
1755
  MODEL_DB.reset
1593
1756
  end
1594
1757