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