sequel 3.21.0 → 3.29.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 (200) hide show
  1. data/CHANGELOG +413 -3
  2. data/README.rdoc +20 -6
  3. data/Rakefile +23 -16
  4. data/bin/sequel +1 -5
  5. data/doc/association_basics.rdoc +210 -43
  6. data/doc/dataset_basics.rdoc +4 -4
  7. data/doc/mass_assignment.rdoc +54 -0
  8. data/doc/migration.rdoc +15 -538
  9. data/doc/model_hooks.rdoc +72 -27
  10. data/doc/opening_databases.rdoc +86 -50
  11. data/doc/prepared_statements.rdoc +40 -13
  12. data/doc/reflection.rdoc +8 -2
  13. data/doc/release_notes/3.22.0.txt +39 -0
  14. data/doc/release_notes/3.23.0.txt +172 -0
  15. data/doc/release_notes/3.24.0.txt +420 -0
  16. data/doc/release_notes/3.25.0.txt +88 -0
  17. data/doc/release_notes/3.26.0.txt +88 -0
  18. data/doc/release_notes/3.27.0.txt +82 -0
  19. data/doc/release_notes/3.28.0.txt +304 -0
  20. data/doc/release_notes/3.29.0.txt +459 -0
  21. data/doc/schema_modification.rdoc +547 -0
  22. data/doc/sharding.rdoc +7 -1
  23. data/doc/testing.rdoc +115 -0
  24. data/doc/transactions.rdoc +137 -0
  25. data/doc/virtual_rows.rdoc +2 -2
  26. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  27. data/lib/sequel/adapters/ado.rb +40 -18
  28. data/lib/sequel/adapters/amalgalite.rb +15 -7
  29. data/lib/sequel/adapters/db2.rb +175 -86
  30. data/lib/sequel/adapters/dbi.rb +15 -15
  31. data/lib/sequel/adapters/do/mysql.rb +0 -5
  32. data/lib/sequel/adapters/do/postgres.rb +0 -5
  33. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  34. data/lib/sequel/adapters/do.rb +17 -36
  35. data/lib/sequel/adapters/firebird.rb +27 -208
  36. data/lib/sequel/adapters/ibmdb.rb +448 -0
  37. data/lib/sequel/adapters/informix.rb +6 -23
  38. data/lib/sequel/adapters/jdbc/as400.rb +5 -31
  39. data/lib/sequel/adapters/jdbc/db2.rb +44 -0
  40. data/lib/sequel/adapters/jdbc/derby.rb +217 -0
  41. data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
  42. data/lib/sequel/adapters/jdbc/h2.rb +26 -17
  43. data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
  44. data/lib/sequel/adapters/jdbc/informix.rb +26 -0
  45. data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
  46. data/lib/sequel/adapters/jdbc/mssql.rb +0 -32
  47. data/lib/sequel/adapters/jdbc/mysql.rb +9 -10
  48. data/lib/sequel/adapters/jdbc/oracle.rb +67 -25
  49. data/lib/sequel/adapters/jdbc/postgresql.rb +6 -11
  50. data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
  51. data/lib/sequel/adapters/jdbc/sqlserver.rb +41 -0
  52. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  53. data/lib/sequel/adapters/jdbc.rb +107 -38
  54. data/lib/sequel/adapters/mock.rb +315 -0
  55. data/lib/sequel/adapters/mysql.rb +78 -182
  56. data/lib/sequel/adapters/mysql2.rb +24 -23
  57. data/lib/sequel/adapters/odbc/db2.rb +17 -0
  58. data/lib/sequel/adapters/odbc/mssql.rb +0 -5
  59. data/lib/sequel/adapters/odbc.rb +28 -9
  60. data/lib/sequel/adapters/openbase.rb +2 -4
  61. data/lib/sequel/adapters/oracle.rb +349 -51
  62. data/lib/sequel/adapters/postgres.rb +169 -21
  63. data/lib/sequel/adapters/shared/access.rb +21 -6
  64. data/lib/sequel/adapters/shared/db2.rb +288 -0
  65. data/lib/sequel/adapters/shared/firebird.rb +214 -0
  66. data/lib/sequel/adapters/shared/informix.rb +45 -0
  67. data/lib/sequel/adapters/shared/mssql.rb +108 -65
  68. data/lib/sequel/adapters/shared/mysql.rb +56 -13
  69. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
  70. data/lib/sequel/adapters/shared/oracle.rb +185 -34
  71. data/lib/sequel/adapters/shared/postgres.rb +107 -58
  72. data/lib/sequel/adapters/shared/progress.rb +0 -6
  73. data/lib/sequel/adapters/shared/sqlite.rb +168 -41
  74. data/lib/sequel/adapters/sqlite.rb +27 -18
  75. data/lib/sequel/adapters/swift/mysql.rb +9 -5
  76. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  77. data/lib/sequel/adapters/swift/sqlite.rb +6 -4
  78. data/lib/sequel/adapters/swift.rb +5 -5
  79. data/lib/sequel/adapters/tinytds.rb +152 -17
  80. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +63 -0
  81. data/lib/sequel/ast_transformer.rb +190 -0
  82. data/lib/sequel/connection_pool/threaded.rb +3 -2
  83. data/lib/sequel/connection_pool.rb +1 -1
  84. data/lib/sequel/core.rb +46 -5
  85. data/lib/sequel/database/connecting.rb +5 -6
  86. data/lib/sequel/database/dataset.rb +4 -4
  87. data/lib/sequel/database/dataset_defaults.rb +59 -1
  88. data/lib/sequel/database/logging.rb +1 -1
  89. data/lib/sequel/database/misc.rb +100 -19
  90. data/lib/sequel/database/query.rb +153 -58
  91. data/lib/sequel/database/schema_generator.rb +8 -5
  92. data/lib/sequel/database/schema_methods.rb +59 -29
  93. data/lib/sequel/dataset/actions.rb +194 -57
  94. data/lib/sequel/dataset/features.rb +81 -8
  95. data/lib/sequel/dataset/graph.rb +8 -7
  96. data/lib/sequel/dataset/misc.rb +50 -23
  97. data/lib/sequel/dataset/mutation.rb +5 -6
  98. data/lib/sequel/dataset/prepared_statements.rb +32 -15
  99. data/lib/sequel/dataset/query.rb +223 -42
  100. data/lib/sequel/dataset/sql.rb +58 -61
  101. data/lib/sequel/dataset.rb +8 -0
  102. data/lib/sequel/exceptions.rb +4 -0
  103. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  104. data/lib/sequel/extensions/migration.rb +6 -4
  105. data/lib/sequel/extensions/named_timezones.rb +5 -0
  106. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  107. data/lib/sequel/extensions/to_dot.rb +95 -83
  108. data/lib/sequel/model/associations.rb +997 -331
  109. data/lib/sequel/model/base.rb +386 -129
  110. data/lib/sequel/model/errors.rb +1 -1
  111. data/lib/sequel/model/exceptions.rb +5 -1
  112. data/lib/sequel/model.rb +15 -8
  113. data/lib/sequel/plugins/association_pks.rb +22 -4
  114. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  115. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  116. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  117. data/lib/sequel/plugins/force_encoding.rb +6 -6
  118. data/lib/sequel/plugins/identity_map.rb +114 -7
  119. data/lib/sequel/plugins/many_through_many.rb +65 -7
  120. data/lib/sequel/plugins/prepared_statements.rb +151 -0
  121. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  122. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  123. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  124. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  125. data/lib/sequel/plugins/serialization.rb +6 -1
  126. data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
  127. data/lib/sequel/plugins/sharding.rb +12 -25
  128. data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
  129. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  130. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  131. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  132. data/lib/sequel/sql.rb +107 -51
  133. data/lib/sequel/timezones.rb +44 -35
  134. data/lib/sequel/version.rb +1 -1
  135. data/spec/adapters/db2_spec.rb +146 -0
  136. data/spec/adapters/mssql_spec.rb +65 -29
  137. data/spec/adapters/mysql_spec.rb +122 -123
  138. data/spec/adapters/oracle_spec.rb +48 -76
  139. data/spec/adapters/postgres_spec.rb +213 -61
  140. data/spec/adapters/spec_helper.rb +6 -5
  141. data/spec/adapters/sqlite_spec.rb +35 -21
  142. data/spec/core/connection_pool_spec.rb +71 -92
  143. data/spec/core/core_sql_spec.rb +20 -31
  144. data/spec/core/database_spec.rb +729 -508
  145. data/spec/core/dataset_spec.rb +980 -1044
  146. data/spec/core/expression_filters_spec.rb +159 -42
  147. data/spec/core/mock_adapter_spec.rb +378 -0
  148. data/spec/core/object_graph_spec.rb +48 -114
  149. data/spec/core/schema_generator_spec.rb +3 -3
  150. data/spec/core/schema_spec.rb +298 -38
  151. data/spec/core/spec_helper.rb +6 -48
  152. data/spec/extensions/association_pks_spec.rb +38 -0
  153. data/spec/extensions/class_table_inheritance_spec.rb +1 -1
  154. data/spec/extensions/columns_introspection_spec.rb +91 -0
  155. data/spec/extensions/dataset_associations_spec.rb +199 -0
  156. data/spec/extensions/defaults_setter_spec.rb +64 -0
  157. data/spec/extensions/identity_map_spec.rb +162 -0
  158. data/spec/extensions/instance_hooks_spec.rb +71 -0
  159. data/spec/extensions/many_through_many_spec.rb +195 -20
  160. data/spec/extensions/migration_spec.rb +17 -17
  161. data/spec/extensions/named_timezones_spec.rb +22 -2
  162. data/spec/extensions/nested_attributes_spec.rb +4 -0
  163. data/spec/extensions/prepared_statements_associations_spec.rb +126 -0
  164. data/spec/extensions/prepared_statements_safe_spec.rb +79 -0
  165. data/spec/extensions/prepared_statements_spec.rb +72 -0
  166. data/spec/extensions/prepared_statements_with_pk_spec.rb +38 -0
  167. data/spec/extensions/schema_dumper_spec.rb +2 -2
  168. data/spec/extensions/schema_spec.rb +13 -21
  169. data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
  170. data/spec/extensions/serialization_spec.rb +5 -8
  171. data/spec/extensions/single_table_inheritance_spec.rb +11 -0
  172. data/spec/extensions/spec_helper.rb +7 -1
  173. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  174. data/spec/extensions/to_dot_spec.rb +3 -5
  175. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  176. data/spec/extensions/xml_serializer_spec.rb +16 -4
  177. data/spec/integration/associations_test.rb +522 -21
  178. data/spec/integration/database_test.rb +4 -2
  179. data/spec/integration/dataset_test.rb +375 -62
  180. data/spec/integration/eager_loader_test.rb +19 -21
  181. data/spec/integration/model_test.rb +80 -1
  182. data/spec/integration/plugin_test.rb +304 -116
  183. data/spec/integration/prepared_statement_test.rb +200 -120
  184. data/spec/integration/schema_test.rb +161 -30
  185. data/spec/integration/spec_helper.rb +39 -30
  186. data/spec/integration/timezone_test.rb +38 -12
  187. data/spec/integration/transaction_test.rb +172 -5
  188. data/spec/integration/type_test.rb +17 -3
  189. data/spec/model/association_reflection_spec.rb +174 -7
  190. data/spec/model/associations_spec.rb +849 -661
  191. data/spec/model/base_spec.rb +255 -95
  192. data/spec/model/dataset_methods_spec.rb +7 -27
  193. data/spec/model/eager_loading_spec.rb +640 -676
  194. data/spec/model/hooks_spec.rb +309 -67
  195. data/spec/model/model_spec.rb +207 -167
  196. data/spec/model/plugins_spec.rb +24 -13
  197. data/spec/model/record_spec.rb +321 -218
  198. data/spec/model/spec_helper.rb +13 -71
  199. data/spec/model/validations_spec.rb +11 -0
  200. metadata +95 -38
@@ -1,14 +1,12 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe "Model attribute setters" do
4
-
5
- before(:each) do
6
- MODEL_DB.reset
7
-
4
+ before do
8
5
  @c = Class.new(Sequel::Model(:items)) do
9
6
  columns :id, :x, :y, :"x y"
10
7
  end
11
8
  @o = @c.new
9
+ MODEL_DB.reset
12
10
  end
13
11
 
14
12
  it "should mark the column value as changed" do
@@ -41,18 +39,13 @@ describe Sequel::Model, "dataset" do
41
39
  before do
42
40
  @a = Class.new(Sequel::Model(:items))
43
41
  @b = Class.new(Sequel::Model)
44
-
45
- class Elephant < Sequel::Model(:ele1)
46
- end
47
-
48
- class Maggot < Sequel::Model
49
- end
50
-
51
- class ShoeSize < Sequel::Model
52
- end
53
-
54
- class BootSize < ShoeSize
55
- end
42
+ class ::Elephant < Sequel::Model(:ele1); end
43
+ class ::Maggot < Sequel::Model; end
44
+ class ::ShoeSize < Sequel::Model; end
45
+ class ::BootSize < ShoeSize; end
46
+ end
47
+ after do
48
+ [:Elephant, :Maggot, :ShoeSize, :BootSize].each{|x| Object.send(:remove_const, x)}
56
49
  end
57
50
 
58
51
  specify "should default to the plural of the class name" do
@@ -74,33 +67,59 @@ describe Sequel::Model, "dataset" do
74
67
  end
75
68
 
76
69
  specify "should disregard namespaces for the table name" do
77
- module BlahBlah
78
- class MwaHaHa < Sequel::Model
70
+ begin
71
+ module ::BlahBlah
72
+ class MwaHaHa < Sequel::Model
73
+ end
79
74
  end
80
- end
81
75
 
82
- BlahBlah::MwaHaHa.dataset.sql.should == 'SELECT * FROM mwa_ha_has'
76
+ BlahBlah::MwaHaHa.dataset.sql.should == 'SELECT * FROM mwa_ha_has'
77
+ ensure
78
+ Object.send(:remove_const, :BlahBlah)
79
+ end
83
80
  end
84
81
  end
85
82
 
86
83
  describe Sequel::Model, ".def_dataset_method" do
87
84
  before do
88
- @c = Class.new(Sequel::Model(:items)) do
89
- end
85
+ @c = Class.new(Sequel::Model(:items))
90
86
  end
91
87
 
92
88
  it "should add a method to the dataset and model if called with a block argument" do
93
- @c.instance_eval do
94
- def_dataset_method(:return_3){3}
95
- end
89
+ @c.def_dataset_method(:return_3){3}
96
90
  @c.return_3.should == 3
97
91
  @c.dataset.return_3.should == 3
98
92
  end
99
93
 
100
- it "should add all passed methods to the model if called without a block argument" do
94
+ it "should handle weird method names" do
95
+ @c.def_dataset_method(:"return 3"){3}
96
+ @c.send(:"return 3").should == 3
97
+ @c.dataset.send(:"return 3").should == 3
98
+ end
99
+
100
+ it "should not add a model method if the model already responds to the method" do
101
101
  @c.instance_eval do
102
- def_dataset_method(:return_3, :return_4)
102
+ def foo
103
+ 1
104
+ end
105
+
106
+ private
107
+
108
+ def bar
109
+ 2
110
+ end
111
+
112
+ def_dataset_method(:foo){3}
113
+ def_dataset_method(:bar){4}
103
114
  end
115
+ @c.foo.should == 1
116
+ @c.dataset.foo.should == 3
117
+ @c.send(:bar).should == 2
118
+ @c.dataset.bar.should == 4
119
+ end
120
+
121
+ it "should add all passed methods to the model if called without a block argument" do
122
+ @c.def_dataset_method(:return_3, :return_4)
104
123
  proc{@c.return_3}.should raise_error(NoMethodError)
105
124
  proc{@c.return_4}.should raise_error(NoMethodError)
106
125
  @c.dataset.instance_eval do
@@ -112,30 +131,113 @@ describe Sequel::Model, ".def_dataset_method" do
112
131
  end
113
132
 
114
133
  it "should cache calls and readd methods if set_dataset is used" do
115
- @c.instance_eval do
116
- def_dataset_method(:return_3){3}
117
- end
134
+ @c.def_dataset_method(:return_3){3}
118
135
  @c.set_dataset :items
119
136
  @c.return_3.should == 3
120
137
  @c.dataset.return_3.should == 3
121
138
  end
122
139
 
123
140
  it "should readd methods to subclasses, if set_dataset is used in a subclass" do
124
- @c.instance_eval do
125
- def_dataset_method(:return_3){3}
126
- end
141
+ @c.def_dataset_method(:return_3){3}
142
+ c = Class.new(@c)
143
+ c.set_dataset :items
144
+ c.return_3.should == 3
145
+ c.dataset.return_3.should == 3
146
+ end
147
+ end
148
+
149
+ describe Sequel::Model, ".dataset_module" do
150
+ before do
151
+ @c = Class.new(Sequel::Model(:items))
152
+ end
153
+
154
+ it "should extend the dataset with the module if the model has a dataset" do
155
+ @c.dataset_module{def return_3() 3 end}
156
+ @c.dataset.return_3.should == 3
157
+ end
158
+
159
+ it "should add methods defined in the module to the class" do
160
+ @c.dataset_module{def return_3() 3 end}
161
+ @c.return_3.should == 3
162
+ end
163
+
164
+ it "should cache calls and readd methods if set_dataset is used" do
165
+ @c.dataset_module{def return_3() 3 end}
166
+ @c.set_dataset :items
167
+ @c.return_3.should == 3
168
+ @c.dataset.return_3.should == 3
169
+ end
170
+
171
+ it "should readd methods to subclasses, if set_dataset is used in a subclass" do
172
+ @c.dataset_module{def return_3() 3 end}
127
173
  c = Class.new(@c)
128
174
  c.set_dataset :items
129
175
  c.return_3.should == 3
130
176
  c.dataset.return_3.should == 3
131
177
  end
178
+
179
+ it "should only have a single dataset_module per class" do
180
+ @c.dataset_module{def return_3() 3 end}
181
+ @c.dataset_module{def return_3() 3 + (begin; super; rescue NoMethodError; 1; end) end}
182
+ @c.return_3.should == 4
183
+ end
184
+
185
+ it "should not have subclasses share the dataset_module" do
186
+ @c.dataset_module{def return_3() 3 end}
187
+ c = Class.new(@c)
188
+ c.dataset_module{def return_3() 3 + (begin; super; rescue NoMethodError; 1; end) end}
189
+ c.return_3.should == 6
190
+ end
191
+
192
+ it "should accept a module object and extend the dataset with it" do
193
+ @c.dataset_module Module.new{def return_3() 3 end}
194
+ @c.dataset.return_3.should == 3
195
+ end
196
+
197
+ it "should be able to call dataset_module with a module multiple times" do
198
+ @c.dataset_module Module.new{def return_3() 3 end}
199
+ @c.dataset_module Module.new{def return_4() 4 end}
200
+ @c.dataset.return_3.should == 3
201
+ @c.dataset.return_4.should == 4
202
+ end
203
+
204
+ it "should be able mix dataset_module calls with and without arguments" do
205
+ @c.dataset_module{def return_3() 3 end}
206
+ @c.dataset_module Module.new{def return_4() 4 end}
207
+ @c.dataset.return_3.should == 3
208
+ @c.dataset.return_4.should == 4
209
+ end
210
+
211
+ it "should have modules provided to dataset_module extend subclass datasets" do
212
+ @c.dataset_module{def return_3() 3 end}
213
+ @c.dataset_module Module.new{def return_4() 4 end}
214
+ c = Class.new(@c)
215
+ c.set_dataset :a
216
+ c.dataset.return_3.should == 3
217
+ c.dataset.return_4.should == 4
218
+ end
219
+
220
+ it "should return the dataset module if given a block" do
221
+ Object.new.extend(@c.dataset_module{def return_3() 3 end}).return_3.should == 3
222
+ end
223
+
224
+ it "should return the argument if given one" do
225
+ Object.new.extend(@c.dataset_module Module.new{def return_3() 3 end}).return_3.should == 3
226
+ end
227
+
228
+ it "should raise error if called with both an argument and ablock" do
229
+ proc{@c.dataset_module(Module.new{def return_3() 3 end}){}}.should raise_error(Sequel::Error)
230
+ end
132
231
  end
133
232
 
134
233
  describe "A model class with implicit table name" do
135
234
  before do
136
- class Donkey < Sequel::Model
235
+ class ::Donkey < Sequel::Model
137
236
  end
138
237
  end
238
+ after do
239
+ Object.send(:remove_const, :Donkey)
240
+ end
139
241
 
140
242
  specify "should have a dataset associated with the model class" do
141
243
  Donkey.dataset.model.should == Donkey
@@ -144,11 +246,12 @@ end
144
246
 
145
247
  describe "A model inheriting from a model" do
146
248
  before do
147
- class Feline < Sequel::Model
148
- end
149
-
150
- class Leopard < Feline
151
- end
249
+ class ::Feline < Sequel::Model; end
250
+ class ::Leopard < Feline; end
251
+ end
252
+ after do
253
+ Object.send(:remove_const, :Leopard)
254
+ Object.send(:remove_const, :Feline)
152
255
  end
153
256
 
154
257
  specify "should have a dataset associated with itself" do
@@ -228,29 +331,27 @@ end
228
331
 
229
332
  describe "Model.db=" do
230
333
  before do
231
- $db1 = MockDatabase.new
232
- $db2 = MockDatabase.new
334
+ @db1 = Sequel.mock
335
+ @db2 = Sequel.mock
233
336
 
234
- class BlueBlue < Sequel::Model(:items)
235
- set_dataset $db1[:blue].filter(:x=>1)
236
- end
337
+ @m = Class.new(Sequel::Model(@db1[:blue].filter(:x=>1)))
237
338
  end
238
339
 
239
340
  specify "should affect the underlying dataset" do
240
- BlueBlue.db = $db2
341
+ @m.db = @db2
241
342
 
242
- BlueBlue.dataset.db.should === $db2
243
- BlueBlue.dataset.db.should_not === $db1
343
+ @m.dataset.db.should === @db2
344
+ @m.dataset.db.should_not === @db1
244
345
  end
245
346
 
246
347
  specify "should keep the same dataset options" do
247
- BlueBlue.db = $db2
248
- BlueBlue.dataset.sql.should == 'SELECT * FROM blue WHERE (x = 1)'
348
+ @m.db = @db2
349
+ @m.dataset.sql.should == 'SELECT * FROM blue WHERE (x = 1)'
249
350
  end
250
351
 
251
352
  specify "should use the database for subclasses" do
252
- BlueBlue.db = $db2
253
- Class.new(BlueBlue).db.should === $db2
353
+ @m.db = @db2
354
+ Class.new(@m).db.should === @db2
254
355
  end
255
356
  end
256
357
 
@@ -258,9 +359,6 @@ describe Sequel::Model, ".(allowed|restricted)_columns " do
258
359
  before do
259
360
  @c = Class.new(Sequel::Model(:blahblah)) do
260
361
  columns :x, :y, :z
261
- def _refresh(ds)
262
- self
263
- end
264
362
  end
265
363
  @c.strict_param_setting = false
266
364
  @c.instance_variable_set(:@columns, [:x, :y, :z])
@@ -288,9 +386,12 @@ describe Sequel::Model, ".(allowed|restricted)_columns " do
288
386
  i.values.should == {:x => 1, :y => 2}
289
387
  i.set(:x => 4, :y => 5, :z => 6)
290
388
  i.values.should == {:x => 4, :y => 5}
291
- i.update(:x => 7, :y => 8, :z => 9)
292
- i.values.delete(:id) # stupid specs
293
- i.values.should == {:x => 7, :y => 8}
389
+
390
+ @c.dataset._fetch = {:x => 7}
391
+ i = @c.new
392
+ i.update(:x => 7, :z => 9)
393
+ i.values.should == {:x => 7}
394
+ MODEL_DB.sqls.should == ["INSERT INTO blahblah (x) VALUES (7)", "SELECT * FROM blahblah WHERE (id = 10) LIMIT 1"]
294
395
  end
295
396
 
296
397
  it "should not set restricted columns by default" do
@@ -299,9 +400,12 @@ describe Sequel::Model, ".(allowed|restricted)_columns " do
299
400
  i.values.should == {:x => 1, :y => 2}
300
401
  i.set(:x => 4, :y => 5, :z => 6)
301
402
  i.values.should == {:x => 4, :y => 5}
302
- i.update(:x => 7, :y => 8, :z => 9)
303
- i.values.delete(:id) # stupid specs
304
- i.values.should == {:x => 7, :y => 8}
403
+
404
+ @c.dataset._fetch = {:x => 7}
405
+ i = @c.new
406
+ i.update(:x => 7, :z => 9)
407
+ i.values.should == {:x => 7}
408
+ MODEL_DB.sqls.should == ["INSERT INTO blahblah (x) VALUES (7)", "SELECT * FROM blahblah WHERE (id = 10) LIMIT 1"]
305
409
  end
306
410
 
307
411
  it "should have allowed take precedence over restricted" do
@@ -311,9 +415,12 @@ describe Sequel::Model, ".(allowed|restricted)_columns " do
311
415
  i.values.should == {:x => 1, :y => 2}
312
416
  i.set(:x => 4, :y => 5, :z => 6)
313
417
  i.values.should == {:x => 4, :y => 5}
314
- i.update(:x => 7, :y => 8, :z => 9)
315
- i.values.delete(:id) # stupid specs
316
- i.values.should == {:x => 7, :y => 8}
418
+
419
+ @c.dataset._fetch = {:y => 7}
420
+ i = @c.new
421
+ i.update(:y => 7, :z => 9)
422
+ i.values.should == {:y => 7}
423
+ MODEL_DB.sqls.should == ["INSERT INTO blahblah (y) VALUES (7)", "SELECT * FROM blahblah WHERE (id = 10) LIMIT 1"]
317
424
  end
318
425
  end
319
426
 
@@ -322,12 +429,8 @@ describe Sequel::Model, ".(un)?restrict_primary_key\\??" do
322
429
  @c = Class.new(Sequel::Model(:blahblah)) do
323
430
  set_primary_key :id
324
431
  columns :x, :y, :z, :id
325
- def refresh
326
- self
327
- end
328
432
  end
329
433
  @c.strict_param_setting = false
330
- @c.instance_variable_set(:@columns, [:x, :y, :z])
331
434
  end
332
435
 
333
436
  it "should restrict updates to primary key by default" do
@@ -364,11 +467,7 @@ describe Sequel::Model, ".strict_param_setting" do
364
467
  @c = Class.new(Sequel::Model(:blahblah)) do
365
468
  columns :x, :y, :z, :id
366
469
  set_restricted_columns :z
367
- def refresh
368
- self
369
- end
370
470
  end
371
- @c.instance_variable_set(:@columns, [:x, :y, :z])
372
471
  end
373
472
 
374
473
  it "should be enabled by default" do
@@ -425,20 +524,18 @@ end
425
524
 
426
525
  describe Sequel::Model, ".[] optimization" do
427
526
  before do
428
- @c = Class.new(Sequel::Model(:a))
429
- @c.instance_eval do
430
- def simple_table
431
- @simple_table
432
- end
433
- end
527
+ @db = MODEL_DB.clone
528
+ @db.quote_identifiers = true
529
+ @c = Class.new(Sequel::Model(@db))
434
530
  end
435
531
 
436
532
  it "should set simple_pk to the literalized primary key column name if a single primary key" do
437
- @c.simple_pk.should == 'id'
533
+ @c.set_primary_key :id
534
+ @c.simple_pk.should == '"id"'
438
535
  @c.set_primary_key :b
439
- @c.simple_pk.should == 'b'
536
+ @c.simple_pk.should == '"b"'
440
537
  @c.set_primary_key :b__a.identifier
441
- @c.simple_pk.should == 'b__a'
538
+ @c.simple_pk.should == '"b__a"'
442
539
  end
443
540
 
444
541
  it "should have simple_pk be blank if compound or no primary key" do
@@ -452,36 +549,99 @@ describe Sequel::Model, ".[] optimization" do
452
549
 
453
550
  it "should have simple table set if passed a Symbol to set_dataset" do
454
551
  @c.set_dataset :a
455
- @c.simple_table.should == 'a'
552
+ @c.simple_table.should == '"a"'
456
553
  @c.set_dataset :b
457
- @c.simple_table.should == 'b'
554
+ @c.simple_table.should == '"b"'
458
555
  @c.set_dataset :b__a
459
- @c.simple_table.should == 'b.a'
556
+ @c.simple_table.should == '"b"."a"'
557
+ end
558
+
559
+ it "should have simple_table set if passed a simple select all dataset to set_dataset" do
560
+ @c.set_dataset @db[:a]
561
+ @c.simple_table.should == '"a"'
562
+ @c.set_dataset @db[:b]
563
+ @c.simple_table.should == '"b"'
564
+ @c.set_dataset @db[:b__a]
565
+ @c.simple_table.should == '"b"."a"'
566
+ end
567
+
568
+ it "should simple_pk and simple_table respect dataset's identifier input methods" do
569
+ ds = @db[:ab]
570
+ ds.identifier_input_method = :reverse
571
+ @c.set_dataset ds
572
+ @c.simple_table.should == '"ba"'
573
+ @c.set_primary_key :cd
574
+ @c.simple_pk.should == '"dc"'
575
+
576
+ @c.set_dataset ds.from(:ef__gh)
577
+ @c.simple_table.should == '"fe"."hg"'
460
578
  end
461
579
 
462
- it "should have simple_table = nil if passed a dataset to set_dataset" do
463
- @c.set_dataset @c.db[:a]
580
+ it "should have simple_table = nil if passed a non-simple select all dataset to set_dataset" do
581
+ @c.set_dataset @c.db[:a].filter(:active)
464
582
  @c.simple_table.should == nil
465
583
  end
466
584
 
467
585
  it "should have simple_table superclasses setting if inheriting" do
468
- @c.set_dataset :a
469
- Class.new(@c).simple_table.should == 'a'
470
- @c.instance_variable_set(:@simple_table, nil)
471
586
  Class.new(@c).simple_table.should == nil
472
- @c.instance_variable_set(:@simple_table, "'b'")
473
- Class.new(@c).simple_table.should == "'b'"
587
+ @c.set_dataset :a
588
+ Class.new(@c).simple_table.should == '"a"'
474
589
  end
475
590
 
476
591
  it "should use Dataset#with_sql if simple_table and simple_pk are true" do
477
592
  @c.set_dataset :a
478
- @c.dataset.should_receive(:with_sql).and_return(@c.dataset)
479
- @c[1]
593
+ @c.dataset._fetch = {:id => 1}
594
+ @c[1].should == @c.load(:id=>1)
595
+ @db.sqls.should == ['SELECT * FROM "a" WHERE "id" = 1']
480
596
  end
481
597
 
482
598
  it "should not use Dataset#with_sql if either simple_table or simple_pk is nil" do
483
- @c.set_dataset @c.dataset
484
- @c.dataset.should_not_receive(:with_sql)
485
- @c[1]
599
+ @c.set_dataset @db[:a].filter(:active)
600
+ @c.dataset._fetch = {:id => 1}
601
+ @c[1].should == @c.load(:id=>1)
602
+ @db.sqls.should == ['SELECT * FROM "a" WHERE ("active" AND ("id" = 1)) LIMIT 1']
603
+ end
604
+ end
605
+
606
+ describe "Model datasets #with_pk" do
607
+ before do
608
+ @c = Class.new(Sequel::Model(:a))
609
+ @ds = @c.dataset
610
+ @ds._fetch = {:id=>1}
611
+ MODEL_DB.reset
612
+ end
613
+
614
+ it "should return the first record where the primary key matches" do
615
+ @ds.with_pk(1).should == @c.load(:id=>1)
616
+ MODEL_DB.sqls.should == ["SELECT * FROM a WHERE (a.id = 1) LIMIT 1"]
617
+ end
618
+
619
+ it "should handle existing filters" do
620
+ @ds.filter(:a=>2).with_pk(1)
621
+ MODEL_DB.sqls.should == ["SELECT * FROM a WHERE ((a = 2) AND (a.id = 1)) LIMIT 1"]
622
+ end
623
+
624
+ it "should work with string values" do
625
+ @ds.with_pk("foo")
626
+ MODEL_DB.sqls.should == ["SELECT * FROM a WHERE (a.id = 'foo') LIMIT 1"]
627
+ end
628
+
629
+ it "should handle an array for composite primary keys" do
630
+ @c.set_primary_key :id1, :id2
631
+ @ds.with_pk([1, 2])
632
+ sqls = MODEL_DB.sqls
633
+ ["SELECT * FROM a WHERE ((a.id1 = 1) AND (a.id2 = 2)) LIMIT 1",
634
+ "SELECT * FROM a WHERE ((a.id2 = 2) AND (a.id1 = 1)) LIMIT 1"].should include(sqls.pop)
635
+ sqls.should == []
636
+ end
637
+
638
+ it "should have #[] consider an integer as a primary key lookup" do
639
+ @ds[1].should == @c.load(:id=>1)
640
+ MODEL_DB.sqls.should == ["SELECT * FROM a WHERE (a.id = 1) LIMIT 1"]
641
+ end
642
+
643
+ it "should not have #[] consider a string as a primary key lookup" do
644
+ @ds['foo'].should == @c.load(:id=>1)
645
+ MODEL_DB.sqls.should == ["SELECT * FROM a WHERE (foo) LIMIT 1"]
486
646
  end
487
647
  end
@@ -3,39 +3,25 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
3
3
  describe Sequel::Model::DatasetMethods, "#destroy" do
4
4
  before do
5
5
  @c = Class.new(Sequel::Model(:items)) do
6
- class_variable_set(:@@destroyed, [])
6
+ self::Destroyed = []
7
7
  def destroy
8
- self.class.send(:class_variable_get, :@@destroyed) << self
9
- end
10
- def self.destroyed
11
- class_variable_get(:@@destroyed)
8
+ model::Destroyed << self
12
9
  end
13
10
  end
14
11
  @d = @c.dataset
12
+ @d._fetch = [{:id=>1}, {:id=>2}]
15
13
  MODEL_DB.reset
16
14
  end
17
15
 
18
16
  it "should instantiate objects in the dataset and call destroy on each" do
19
- def @d.fetch_rows(sql)
20
- yield({:id=>1})
21
- yield({:id=>2})
22
- end
23
17
  @d.destroy
24
- @c.destroyed.collect{|x| x.values}.should == [{:id=>1}, {:id=>2}]
18
+ @c::Destroyed.collect{|x| x.values}.should == [{:id=>1}, {:id=>2}]
25
19
  end
26
20
 
27
21
  it "should return the number of records destroyed" do
28
- def @d.fetch_rows(sql)
29
- yield({:id=>1})
30
- yield({:id=>2})
31
- end
32
22
  @d.destroy.should == 2
33
- def @d.fetch_rows(sql)
34
- yield({:id=>1})
35
- end
23
+ @d._fetch = [[{:i=>1}], []]
36
24
  @d.destroy.should == 1
37
- def @d.fetch_rows(sql)
38
- end
39
25
  @d.destroy.should == 0
40
26
  end
41
27
 
@@ -61,10 +47,7 @@ describe Sequel::Model::DatasetMethods, "#to_hash" do
61
47
  end
62
48
 
63
49
  it "should result in a hash with primary key value keys and model object values" do
64
- def @d.fetch_rows(sql)
65
- yield({:name=>1})
66
- yield({:name=>2})
67
- end
50
+ @d._fetch = [{:name=>1}, {:name=>2}]
68
51
  h = @d.to_hash
69
52
  h.should be_a_kind_of(Hash)
70
53
  a = h.to_a
@@ -73,10 +56,7 @@ describe Sequel::Model::DatasetMethods, "#to_hash" do
73
56
  end
74
57
 
75
58
  it "should result in a hash with given value keys and model object values" do
76
- def @d.fetch_rows(sql)
77
- yield({:name=>1, :number=>3})
78
- yield({:name=>2, :number=>4})
79
- end
59
+ @d._fetch = [{:name=>1, :number=>3}, {:name=>2, :number=>4}]
80
60
  h = @d.to_hash(:number)
81
61
  h.should be_a_kind_of(Hash)
82
62
  a = h.to_a