sequel 3.28.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 (148) hide show
  1. data/CHANGELOG +119 -3
  2. data/Rakefile +5 -3
  3. data/bin/sequel +1 -5
  4. data/doc/model_hooks.rdoc +9 -1
  5. data/doc/opening_databases.rdoc +49 -40
  6. data/doc/prepared_statements.rdoc +27 -6
  7. data/doc/release_notes/3.28.0.txt +2 -2
  8. data/doc/release_notes/3.29.0.txt +459 -0
  9. data/doc/sharding.rdoc +7 -1
  10. data/doc/testing.rdoc +18 -9
  11. data/doc/transactions.rdoc +41 -1
  12. data/lib/sequel/adapters/ado.rb +28 -17
  13. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  14. data/lib/sequel/adapters/amalgalite.rb +11 -7
  15. data/lib/sequel/adapters/db2.rb +122 -70
  16. data/lib/sequel/adapters/dbi.rb +15 -15
  17. data/lib/sequel/adapters/do.rb +5 -36
  18. data/lib/sequel/adapters/do/mysql.rb +0 -5
  19. data/lib/sequel/adapters/do/postgres.rb +0 -5
  20. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  21. data/lib/sequel/adapters/firebird.rb +3 -6
  22. data/lib/sequel/adapters/ibmdb.rb +24 -16
  23. data/lib/sequel/adapters/informix.rb +2 -4
  24. data/lib/sequel/adapters/jdbc.rb +47 -11
  25. data/lib/sequel/adapters/jdbc/as400.rb +5 -24
  26. data/lib/sequel/adapters/jdbc/db2.rb +0 -5
  27. data/lib/sequel/adapters/jdbc/derby.rb +217 -0
  28. data/lib/sequel/adapters/jdbc/firebird.rb +0 -5
  29. data/lib/sequel/adapters/jdbc/h2.rb +10 -12
  30. data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
  31. data/lib/sequel/adapters/jdbc/informix.rb +0 -5
  32. data/lib/sequel/adapters/jdbc/jtds.rb +0 -5
  33. data/lib/sequel/adapters/jdbc/mysql.rb +0 -10
  34. data/lib/sequel/adapters/jdbc/oracle.rb +70 -3
  35. data/lib/sequel/adapters/jdbc/postgresql.rb +0 -11
  36. data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
  37. data/lib/sequel/adapters/jdbc/sqlserver.rb +0 -5
  38. data/lib/sequel/adapters/jdbc/transactions.rb +56 -7
  39. data/lib/sequel/adapters/mock.rb +315 -0
  40. data/lib/sequel/adapters/mysql.rb +64 -51
  41. data/lib/sequel/adapters/mysql2.rb +15 -9
  42. data/lib/sequel/adapters/odbc.rb +13 -6
  43. data/lib/sequel/adapters/odbc/db2.rb +0 -4
  44. data/lib/sequel/adapters/odbc/mssql.rb +0 -5
  45. data/lib/sequel/adapters/openbase.rb +2 -4
  46. data/lib/sequel/adapters/oracle.rb +333 -51
  47. data/lib/sequel/adapters/postgres.rb +80 -27
  48. data/lib/sequel/adapters/shared/access.rb +0 -6
  49. data/lib/sequel/adapters/shared/db2.rb +13 -15
  50. data/lib/sequel/adapters/shared/firebird.rb +6 -6
  51. data/lib/sequel/adapters/shared/mssql.rb +23 -18
  52. data/lib/sequel/adapters/shared/mysql.rb +6 -6
  53. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
  54. data/lib/sequel/adapters/shared/oracle.rb +185 -30
  55. data/lib/sequel/adapters/shared/postgres.rb +35 -18
  56. data/lib/sequel/adapters/shared/progress.rb +0 -6
  57. data/lib/sequel/adapters/shared/sqlite.rb +116 -37
  58. data/lib/sequel/adapters/sqlite.rb +16 -8
  59. data/lib/sequel/adapters/swift.rb +5 -5
  60. data/lib/sequel/adapters/swift/mysql.rb +0 -5
  61. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  62. data/lib/sequel/adapters/swift/sqlite.rb +6 -4
  63. data/lib/sequel/adapters/tinytds.rb +13 -10
  64. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -0
  65. data/lib/sequel/core.rb +40 -0
  66. data/lib/sequel/database/connecting.rb +1 -2
  67. data/lib/sequel/database/dataset.rb +3 -3
  68. data/lib/sequel/database/dataset_defaults.rb +58 -0
  69. data/lib/sequel/database/misc.rb +62 -2
  70. data/lib/sequel/database/query.rb +113 -49
  71. data/lib/sequel/database/schema_methods.rb +7 -2
  72. data/lib/sequel/dataset/actions.rb +37 -19
  73. data/lib/sequel/dataset/features.rb +24 -0
  74. data/lib/sequel/dataset/graph.rb +7 -6
  75. data/lib/sequel/dataset/misc.rb +11 -3
  76. data/lib/sequel/dataset/mutation.rb +2 -3
  77. data/lib/sequel/dataset/prepared_statements.rb +6 -4
  78. data/lib/sequel/dataset/query.rb +46 -15
  79. data/lib/sequel/dataset/sql.rb +28 -4
  80. data/lib/sequel/extensions/named_timezones.rb +5 -0
  81. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  82. data/lib/sequel/model.rb +2 -1
  83. data/lib/sequel/model/associations.rb +115 -33
  84. data/lib/sequel/model/base.rb +91 -31
  85. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  86. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  87. data/lib/sequel/plugins/force_encoding.rb +6 -6
  88. data/lib/sequel/plugins/identity_map.rb +1 -1
  89. data/lib/sequel/plugins/many_through_many.rb +6 -10
  90. data/lib/sequel/plugins/prepared_statements.rb +12 -1
  91. data/lib/sequel/plugins/prepared_statements_associations.rb +1 -1
  92. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  93. data/lib/sequel/plugins/serialization.rb +6 -1
  94. data/lib/sequel/plugins/sharding.rb +0 -5
  95. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  96. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  97. data/lib/sequel/plugins/update_primary_key.rb +1 -1
  98. data/lib/sequel/timezones.rb +42 -42
  99. data/lib/sequel/version.rb +1 -1
  100. data/spec/adapters/mssql_spec.rb +29 -29
  101. data/spec/adapters/mysql_spec.rb +86 -104
  102. data/spec/adapters/oracle_spec.rb +48 -76
  103. data/spec/adapters/postgres_spec.rb +98 -33
  104. data/spec/adapters/spec_helper.rb +0 -5
  105. data/spec/adapters/sqlite_spec.rb +24 -21
  106. data/spec/core/connection_pool_spec.rb +9 -15
  107. data/spec/core/core_sql_spec.rb +20 -31
  108. data/spec/core/database_spec.rb +491 -227
  109. data/spec/core/dataset_spec.rb +638 -1051
  110. data/spec/core/expression_filters_spec.rb +0 -1
  111. data/spec/core/mock_adapter_spec.rb +378 -0
  112. data/spec/core/object_graph_spec.rb +48 -114
  113. data/spec/core/schema_generator_spec.rb +3 -3
  114. data/spec/core/schema_spec.rb +51 -114
  115. data/spec/core/spec_helper.rb +3 -90
  116. data/spec/extensions/class_table_inheritance_spec.rb +1 -1
  117. data/spec/extensions/dataset_associations_spec.rb +199 -0
  118. data/spec/extensions/instance_hooks_spec.rb +71 -0
  119. data/spec/extensions/named_timezones_spec.rb +22 -2
  120. data/spec/extensions/nested_attributes_spec.rb +3 -0
  121. data/spec/extensions/schema_spec.rb +1 -1
  122. data/spec/extensions/serialization_modification_detection_spec.rb +1 -0
  123. data/spec/extensions/serialization_spec.rb +5 -8
  124. data/spec/extensions/spec_helper.rb +4 -0
  125. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  126. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  127. data/spec/integration/associations_test.rb +123 -12
  128. data/spec/integration/dataset_test.rb +140 -47
  129. data/spec/integration/eager_loader_test.rb +19 -21
  130. data/spec/integration/model_test.rb +80 -1
  131. data/spec/integration/plugin_test.rb +179 -128
  132. data/spec/integration/prepared_statement_test.rb +92 -91
  133. data/spec/integration/schema_test.rb +42 -23
  134. data/spec/integration/spec_helper.rb +25 -31
  135. data/spec/integration/timezone_test.rb +38 -12
  136. data/spec/integration/transaction_test.rb +161 -34
  137. data/spec/integration/type_test.rb +3 -3
  138. data/spec/model/association_reflection_spec.rb +83 -7
  139. data/spec/model/associations_spec.rb +393 -676
  140. data/spec/model/base_spec.rb +186 -116
  141. data/spec/model/dataset_methods_spec.rb +7 -27
  142. data/spec/model/eager_loading_spec.rb +343 -867
  143. data/spec/model/hooks_spec.rb +160 -79
  144. data/spec/model/model_spec.rb +118 -165
  145. data/spec/model/plugins_spec.rb +7 -13
  146. data/spec/model/record_spec.rb +138 -207
  147. data/spec/model/spec_helper.rb +10 -73
  148. metadata +14 -8
@@ -6,7 +6,6 @@ String.send(:include, Sequel::SQL::StringMethods)
6
6
  describe "Blockless Ruby Filters" do
7
7
  before do
8
8
  db = Sequel::Database.new
9
- db.quote_identifiers = false
10
9
  @d = db[:items]
11
10
  def @d.l(*args, &block)
12
11
  literal(filter_expr(*args, &block))
@@ -0,0 +1,378 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "Sequel Mock Adapter" do
4
+ specify "should have an adapter method" do
5
+ db = Sequel.mock
6
+ db.should be_a_kind_of(Sequel::Mock::Database)
7
+ db.adapter_scheme.should == :mock
8
+ end
9
+
10
+ specify "should each not return any rows by default" do
11
+ called = false
12
+ Sequel.mock[:t].each{|r| called = true}
13
+ called.should be_false
14
+ end
15
+
16
+ specify "should return 0 for update and delete by default" do
17
+ Sequel.mock[:t].update(:a=>1).should == 0
18
+ Sequel.mock[:t].delete.should == 0
19
+ end
20
+
21
+ specify "should return nil for insert by default" do
22
+ Sequel.mock[:t].insert(:a=>1).should be_nil
23
+ end
24
+
25
+ specify "should be able to set the rows returned by each using :fetch option with a single hash" do
26
+ rs = []
27
+ db = Sequel.mock(:fetch=>{:a=>1})
28
+ db[:t].each{|r| rs << r}
29
+ rs.should == [{:a=>1}]
30
+ db[:t].each{|r| rs << r}
31
+ rs.should == [{:a=>1}, {:a=>1}]
32
+ db[:t].each{|r| r[:a] = 2; rs << r}
33
+ rs.should == [{:a=>1}, {:a=>1}, {:a=>2}]
34
+ db[:t].each{|r| rs << r}
35
+ rs.should == [{:a=>1}, {:a=>1}, {:a=>2}, {:a=>1}]
36
+ end
37
+
38
+ specify "should be able to set the rows returned by each using :fetch option with an array of hashes" do
39
+ rs = []
40
+ db = Sequel.mock(:fetch=>[{:a=>1}, {:a=>2}])
41
+ db[:t].each{|r| rs << r}
42
+ rs.should == [{:a=>1}, {:a=>2}]
43
+ db[:t].each{|r| rs << r}
44
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>1}, {:a=>2}]
45
+ db[:t].each{|r| r[:a] += 2; rs << r}
46
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>1}, {:a=>2}, {:a=>3}, {:a=>4}]
47
+ db[:t].each{|r| rs << r}
48
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>1}, {:a=>2}, {:a=>3}, {:a=>4}, {:a=>1}, {:a=>2}]
49
+ end
50
+
51
+ specify "should be able to set the rows returned by each using :fetch option with an array or arrays of hashes" do
52
+ rs = []
53
+ db = Sequel.mock(:fetch=>[[{:a=>1}, {:a=>2}], [{:a=>3}, {:a=>4}]])
54
+ db[:t].each{|r| rs << r}
55
+ rs.should == [{:a=>1}, {:a=>2}]
56
+ db[:t].each{|r| rs << r}
57
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>3}, {:a=>4}]
58
+ db[:t].each{|r| rs << r}
59
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>3}, {:a=>4}]
60
+ end
61
+
62
+ specify "should be able to set the rows returned by each using :fetch option with a proc that takes sql" do
63
+ rs = []
64
+ db = Sequel.mock(:fetch=>proc{|sql| sql =~ /FROM t/ ? {:b=>1} : [{:a=>1}, {:a=>2}]})
65
+ db[:t].each{|r| rs << r}
66
+ rs.should == [{:b=>1}]
67
+ db[:b].each{|r| rs << r}
68
+ rs.should == [{:b=>1}, {:a=>1}, {:a=>2}]
69
+ db[:t].each{|r| r[:b] += 1; rs << r}
70
+ db[:b].each{|r| r[:a] += 2; rs << r}
71
+ rs.should == [{:b=>1}, {:a=>1}, {:a=>2}, {:b=>2}, {:a=>3}, {:a=>4}]
72
+ db[:t].each{|r| rs << r}
73
+ db[:b].each{|r| rs << r}
74
+ rs.should == [{:b=>1}, {:a=>1}, {:a=>2}, {:b=>2}, {:a=>3}, {:a=>4}, {:b=>1}, {:a=>1}, {:a=>2}]
75
+ end
76
+
77
+ specify "should have a fetch= method for setting rows returned by each after the fact" do
78
+ rs = []
79
+ db = Sequel.mock
80
+ db.fetch = {:a=>1}
81
+ db[:t].each{|r| rs << r}
82
+ rs.should == [{:a=>1}]
83
+ db[:t].each{|r| rs << r}
84
+ rs.should == [{:a=>1}] * 2
85
+ end
86
+
87
+ specify "should be able to set an exception to raise by setting the :fetch option to an exception class " do
88
+ db = Sequel.mock(:fetch=>ArgumentError)
89
+ proc{db[:t].all}.should raise_error(Sequel::DatabaseError)
90
+ begin
91
+ db[:t].all
92
+ rescue => e
93
+ end
94
+ e.should be_a_kind_of(Sequel::DatabaseError)
95
+ e.wrapped_exception.should be_a_kind_of(ArgumentError)
96
+ end
97
+
98
+ specify "should be able to set separate kinds of results for fetch using an array" do
99
+ rs = []
100
+ db = Sequel.mock(:fetch=>[{:a=>1}, [{:a=>2}, {:a=>3}], proc{|s| {:a=>4}}, proc{|s| }, nil, ArgumentError])
101
+ db[:t].each{|r| rs << r}
102
+ rs.should == [{:a=>1}]
103
+ db[:t].each{|r| rs << r}
104
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>3}]
105
+ db[:t].each{|r| rs << r}
106
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>3}, {:a=>4}]
107
+ db[:t].each{|r| rs << r}
108
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>3}, {:a=>4}]
109
+ db[:t].each{|r| rs << r}
110
+ rs.should == [{:a=>1}, {:a=>2}, {:a=>3}, {:a=>4}]
111
+ proc{db[:t].all}.should raise_error(Sequel::DatabaseError)
112
+ end
113
+
114
+ specify "should be able to set the rows returned by each on a per dataset basis using _fetch" do
115
+ rs = []
116
+ db = Sequel.mock(:fetch=>{:a=>1})
117
+ ds = db[:t]
118
+ ds.each{|r| rs << r}
119
+ rs.should == [{:a=>1}]
120
+ ds._fetch = {:b=>2}
121
+ ds.each{|r| rs << r}
122
+ rs.should == [{:a=>1}, {:b=>2}]
123
+ end
124
+
125
+ specify "should be able to set the number of rows modified by update and delete using :numrows option as an integer" do
126
+ db = Sequel.mock(:numrows=>2)
127
+ db[:t].update(:a=>1).should == 2
128
+ db[:t].delete.should == 2
129
+ db[:t].update(:a=>1).should == 2
130
+ db[:t].delete.should == 2
131
+ end
132
+
133
+ specify "should be able to set the number of rows modified by update and delete using :numrows option as an array of integers" do
134
+ db = Sequel.mock(:numrows=>[2, 1])
135
+ db[:t].update(:a=>1).should == 2
136
+ db[:t].delete.should == 1
137
+ db[:t].update(:a=>1).should == 0
138
+ db[:t].delete.should == 0
139
+ end
140
+
141
+ specify "should be able to set the number of rows modified by update and delete using :numrows option as a proc" do
142
+ db = Sequel.mock(:numrows=>proc{|sql| sql =~ / t/ ? 2 : 1})
143
+ db[:t].update(:a=>1).should == 2
144
+ db[:t].delete.should == 2
145
+ db[:b].update(:a=>1).should == 1
146
+ db[:b].delete.should == 1
147
+ end
148
+
149
+ specify "should be able to set an exception to raise by setting the :numrows option to an exception class " do
150
+ db = Sequel.mock(:numrows=>ArgumentError)
151
+ proc{db[:t].update(:a=>1)}.should raise_error(Sequel::DatabaseError)
152
+ begin
153
+ db[:t].delete
154
+ rescue => e
155
+ end
156
+ e.should be_a_kind_of(Sequel::DatabaseError)
157
+ e.wrapped_exception.should be_a_kind_of(ArgumentError)
158
+ end
159
+
160
+ specify "should be able to set separate kinds of results for numrows using an array" do
161
+ db = Sequel.mock(:numrows=>[1, proc{|s| 2}, nil, ArgumentError])
162
+ db[:t].delete.should == 1
163
+ db[:t].update(:a=>1).should == 2
164
+ db[:t].delete.should == 0
165
+ proc{db[:t].delete}.should raise_error(Sequel::DatabaseError)
166
+ end
167
+
168
+ specify "should have a numrows= method to set the number of rows modified by update and delete after the fact" do
169
+ db = Sequel.mock
170
+ db.numrows = 2
171
+ db[:t].update(:a=>1).should == 2
172
+ db[:t].delete.should == 2
173
+ db[:t].update(:a=>1).should == 2
174
+ db[:t].delete.should == 2
175
+ end
176
+
177
+ specify "should be able to set the number of rows modified by update and delete on a per dataset basis" do
178
+ db = Sequel.mock(:numrows=>2)
179
+ ds = db[:t]
180
+ ds.update(:a=>1).should == 2
181
+ ds.delete.should == 2
182
+ ds.numrows = 3
183
+ ds.update(:a=>1).should == 3
184
+ ds.delete.should == 3
185
+ end
186
+
187
+ specify "should be able to set the autogenerated primary key returned by insert using :autoid option as an integer" do
188
+ db = Sequel.mock(:autoid=>1)
189
+ db[:t].insert(:a=>1).should == 1
190
+ db[:t].insert(:a=>1).should == 2
191
+ db[:t].insert(:a=>1).should == 3
192
+ end
193
+
194
+ specify "should be able to set the autogenerated primary key returned by insert using :autoid option as an array of integers" do
195
+ db = Sequel.mock(:autoid=>[1, 3, 5])
196
+ db[:t].insert(:a=>1).should == 1
197
+ db[:t].insert(:a=>1).should == 3
198
+ db[:t].insert(:a=>1).should == 5
199
+ db[:t].insert(:a=>1).should be_nil
200
+ end
201
+
202
+ specify "should be able to set the autogenerated primary key returned by insert using :autoid option as a proc" do
203
+ db = Sequel.mock(:autoid=>proc{|sql| sql =~ /INTO t / ? 2 : 1})
204
+ db[:t].insert(:a=>1).should == 2
205
+ db[:t].insert(:a=>1).should == 2
206
+ db[:b].insert(:a=>1).should == 1
207
+ db[:b].insert(:a=>1).should == 1
208
+ end
209
+
210
+ specify "should be able to set an exception to raise by setting the :autoid option to an exception class " do
211
+ db = Sequel.mock(:autoid=>ArgumentError)
212
+ proc{db[:t].insert(:a=>1)}.should raise_error(Sequel::DatabaseError)
213
+ begin
214
+ db[:t].insert
215
+ rescue => e
216
+ end
217
+ e.should be_a_kind_of(Sequel::DatabaseError)
218
+ e.wrapped_exception.should be_a_kind_of(ArgumentError)
219
+ end
220
+
221
+ specify "should be able to set separate kinds of results for autoid using an array" do
222
+ db = Sequel.mock(:autoid=>[1, proc{|s| 2}, nil, ArgumentError])
223
+ db[:t].insert.should == 1
224
+ db[:t].insert.should == 2
225
+ db[:t].insert.should == nil
226
+ proc{db[:t].insert}.should raise_error(Sequel::DatabaseError)
227
+ end
228
+
229
+ specify "should have an autoid= method to set the autogenerated primary key returned by insert after the fact" do
230
+ db = Sequel.mock
231
+ db.autoid = 1
232
+ db[:t].insert(:a=>1).should == 1
233
+ db[:t].insert(:a=>1).should == 2
234
+ db[:t].insert(:a=>1).should == 3
235
+ end
236
+
237
+ specify "should be able to set the autogenerated primary key returned by insert on a per dataset basis" do
238
+ db = Sequel.mock(:autoid=>1)
239
+ ds = db[:t]
240
+ ds.insert(:a=>1).should == 1
241
+ ds.autoid = 5
242
+ ds.insert(:a=>1).should == 5
243
+ ds.insert(:a=>1).should == 6
244
+ db[:t].insert(:a=>1).should == 2
245
+ end
246
+
247
+ specify "should be able to set the columns to set in the dataset as an array of symbols" do
248
+ db = Sequel.mock(:columns=>[:a, :b])
249
+ db[:t].columns.should == [:a, :b]
250
+ db.sqls.should == ["SELECT * FROM t LIMIT 1"]
251
+ ds = db[:t]
252
+ ds.all
253
+ db.sqls.should == ["SELECT * FROM t"]
254
+ ds.columns.should == [:a, :b]
255
+ db.sqls.should == []
256
+ db[:t].columns.should == [:a, :b]
257
+ end
258
+
259
+ specify "should be able to set the columns to set in the dataset as an array of arrays of symbols" do
260
+ db = Sequel.mock(:columns=>[[:a, :b], [:c, :d]])
261
+ db[:t].columns.should == [:a, :b]
262
+ db[:t].columns.should == [:c, :d]
263
+ end
264
+
265
+ specify "should be able to set the columns to set in the dataset as a proc" do
266
+ db = Sequel.mock(:columns=>proc{|sql| (sql =~ / t/) ? [:a, :b] : [:c, :d]})
267
+ db[:b].columns.should == [:c, :d]
268
+ db[:t].columns.should == [:a, :b]
269
+ end
270
+
271
+ specify "should have a columns= method to set the columns to set after the fact" do
272
+ db = Sequel.mock
273
+ db.columns = [[:a, :b], [:c, :d]]
274
+ db[:t].columns.should == [:a, :b]
275
+ db[:t].columns.should == [:c, :d]
276
+ end
277
+
278
+ specify "should keep a record of all executed SQL in #sqls" do
279
+ db = Sequel.mock
280
+ db[:t].all
281
+ db[:b].delete
282
+ db[:c].insert(:a=>1)
283
+ db[:d].update(:a=>1)
284
+ db.sqls.should == ['SELECT * FROM t', 'DELETE FROM b', 'INSERT INTO c (a) VALUES (1)', 'UPDATE d SET a = 1']
285
+ end
286
+
287
+ specify "should clear sqls on retrieval" do
288
+ db = Sequel.mock
289
+ db[:t].all
290
+ db.sqls.should == ['SELECT * FROM t']
291
+ db.sqls.should == []
292
+ end
293
+
294
+ specify "should also log SQL executed to the given loggers" do
295
+ a = []
296
+ def a.method_missing(m, *x) push(*x) end
297
+ db = Sequel.mock(:loggers=>[a])
298
+ db[:t].all
299
+ db[:b].delete
300
+ db[:c].insert(:a=>1)
301
+ db[:d].update(:a=>1)
302
+ a.should == ['SELECT * FROM t', 'DELETE FROM b', 'INSERT INTO c (a) VALUES (1)', 'UPDATE d SET a = 1']
303
+ end
304
+
305
+ specify "should correctly handle transactions" do
306
+ db = Sequel.mock
307
+ db.transaction{db[:a].all}
308
+ db.sqls.should == ['BEGIN', 'SELECT * FROM a', 'COMMIT']
309
+ db.transaction{db[:a].all; raise Sequel::Rollback}
310
+ db.sqls.should == ['BEGIN', 'SELECT * FROM a', 'ROLLBACK']
311
+ proc{db.transaction{db[:a].all; raise ArgumentError}}.should raise_error(ArgumentError)
312
+ db.sqls.should == ['BEGIN', 'SELECT * FROM a', 'ROLLBACK']
313
+ proc{db.transaction(:rollback=>:reraise){db[:a].all; raise Sequel::Rollback}}.should raise_error(Sequel::Rollback)
314
+ db.sqls.should == ['BEGIN', 'SELECT * FROM a', 'ROLLBACK']
315
+ db.transaction(:rollback=>:always){db[:a].all}
316
+ db.sqls.should == ['BEGIN', 'SELECT * FROM a', 'ROLLBACK']
317
+ db.transaction{db.transaction{db[:a].all; raise Sequel::Rollback}}
318
+ db.sqls.should == ['BEGIN', 'SELECT * FROM a', 'ROLLBACK']
319
+ db.transaction{db.transaction(:savepoint=>true){db[:a].all; raise Sequel::Rollback}}
320
+ db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'SELECT * FROM a', 'ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT']
321
+ db.transaction{db.transaction(:savepoint=>true){db[:a].all}; raise Sequel::Rollback}
322
+ db.sqls.should == ['BEGIN', 'SAVEPOINT autopoint_1', 'SELECT * FROM a', 'RELEASE SAVEPOINT autopoint_1', 'ROLLBACK']
323
+ end
324
+
325
+ specify "should correctly handle transactions when sharding" do
326
+ db = Sequel.mock(:servers=>{:test=>{}})
327
+ db.transaction{db.transaction(:server=>:test){db[:a].all; db[:t].server(:test).all}}
328
+ db.sqls.should == ['BEGIN', 'BEGIN -- test', 'SELECT * FROM a', 'SELECT * FROM t -- test', 'COMMIT -- test', 'COMMIT']
329
+ end
330
+
331
+ specify "should yield a mock connection object from synchronize" do
332
+ c = Sequel.mock.synchronize{|conn| conn}
333
+ c.should be_a_kind_of(Sequel::Mock::Connection)
334
+ end
335
+
336
+ specify "should deal correctly with sharding" do
337
+ db = Sequel.mock(:servers=>{:test=>{}})
338
+ c1 = db.synchronize{|conn| conn}
339
+ c2 = db.synchronize(:test){|conn| conn}
340
+ c1.server.should == :default
341
+ c2.server.should == :test
342
+ end
343
+
344
+ specify "should disconnect correctly" do
345
+ db = Sequel.mock
346
+ db.test_connection
347
+ proc{db.disconnect}.should_not raise_error
348
+ end
349
+
350
+ specify "should accept :extend option for extending the object with a module" do
351
+ Sequel.mock(:extend=>Module.new{def foo(v) v * 2 end}).foo(3).should == 6
352
+ end
353
+
354
+ specify "should accept :sqls option for where to store the SQL queries" do
355
+ a = []
356
+ Sequel.mock(:sqls=>a)[:t].all
357
+ a.should == ['SELECT * FROM t']
358
+ end
359
+
360
+ specify "should include :append option in SQL if it is given" do
361
+ db = Sequel.mock(:append=>'a')
362
+ db[:t].all
363
+ db.sqls.should == ['SELECT * FROM t -- a']
364
+ end
365
+
366
+ specify "should append :arguments option to execute to the SQL if present" do
367
+ db = Sequel.mock
368
+ db.execute('SELECT * FROM t', :arguments=>[1, 2])
369
+ db.sqls.should == ['SELECT * FROM t -- args: [1, 2]']
370
+ end
371
+
372
+ specify "should have Dataset#columns take columns to set and return self" do
373
+ db = Sequel.mock
374
+ ds = db[:t].columns(:id, :a, :b)
375
+ ds.should be_a_kind_of(Sequel::Mock::Dataset)
376
+ ds.columns.should == [:id, :a, :b]
377
+ end
378
+ end
@@ -2,16 +2,21 @@ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
3
  describe Sequel::Dataset, " graphing" do
4
4
  before do
5
- dbc = Class.new
6
- @db = dbc.new
7
- @ds1 = Sequel::Dataset.new(@db).from(:points)
8
- @ds2 = Sequel::Dataset.new(@db).from(:lines)
9
- @ds3 = Sequel::Dataset.new(@db).from(:graphs)
10
- dss = {:points=>@ds1, :lines=>@ds2, :graphs=>@ds3}
11
- dbc.send(:define_method, :[]){|ds| dss[ds]}
12
- def @ds1.columns; [:id, :x, :y] end
13
- def @ds2.columns; [:id, :x, :y, :graph_id] end
14
- def @ds3.columns; [:id, :name, :x, :y, :lines_x] end
5
+ @db = Sequel.mock(:columns=>proc do |sql|
6
+ case sql
7
+ when /points/
8
+ [:id, :x, :y]
9
+ when /lines/
10
+ [:id, :x, :y, :graph_id]
11
+ else
12
+ [:id, :name, :x, :y, :lines_x]
13
+ end
14
+ end)
15
+ @ds1 = @db.from(:points)
16
+ @ds2 = @db.from(:lines)
17
+ @ds3 = @db.from(:graphs)
18
+ [@ds1, @ds2, @ds3].each{|ds| ds.columns}
19
+ @db.sqls
15
20
  end
16
21
 
17
22
  it "#graph should not modify the current dataset's opts" do
@@ -187,144 +192,73 @@ describe Sequel::Dataset, " graphing" do
187
192
  end
188
193
 
189
194
  it "#graph_each should split the result set into component tables" do
190
- ds = @ds1.graph(@ds2, :x=>:id)
191
- def ds.fetch_rows(sql, &block)
192
- yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7})
193
- end
194
- results = ds.all
195
- results.length.should == 1
196
- results.first.should == {:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}}
197
-
198
- ds = @ds1.graph(@ds2, :x=>:id).graph(@ds3, :id=>:graph_id)
199
- def ds.fetch_rows(sql, &block)
200
- yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7, :graphs_id=>8, :name=>9, :graphs_x=>10, :graphs_y=>11, :graphs_lines_x=>12})
201
- end
202
- results = ds.all
203
- results.length.should == 1
204
- results.first.should == {:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graphs=>{:id=>8, :name=>9, :x=>10, :y=>11, :lines_x=>12}}
195
+ @db.fetch = [[{:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7}],
196
+ [{:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7, :graphs_id=>8, :name=>9, :graphs_x=>10, :graphs_y=>11, :graphs_lines_x=>12}],
197
+ [{:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7, :graph_id_0=>8, :graph_x=>9, :graph_y=>10, :graph_graph_id=>11}]]
205
198
 
206
- ds = @ds1.graph(@ds2, :x=>:id).graph(@ds2, {:y=>:points__id}, :table_alias=>:graph)
207
- def ds.fetch_rows(sql, &block)
208
- yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7, :graph_id_0=>8, :graph_x=>9, :graph_y=>10, :graph_graph_id=>11})
209
- end
210
- results = ds.all
211
- results.length.should == 1
212
- results.first.should == {:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graph=>{:id=>8, :x=>9, :y=>10, :graph_id=>11}}
199
+ @ds1.graph(@ds2, :x=>:id).all.should == [{:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}}]
200
+ @ds1.graph(@ds2, :x=>:id).graph(@ds3, :id=>:graph_id).all.should == [{:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graphs=>{:id=>8, :name=>9, :x=>10, :y=>11, :lines_x=>12}}]
201
+ @ds1.graph(@ds2, :x=>:id).graph(@ds2, {:y=>:points__id}, :table_alias=>:graph).all.should == [{:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graph=>{:id=>8, :x=>9, :y=>10, :graph_id=>11}}]
213
202
  end
214
203
 
215
204
  it "#ungraphed should remove the splitting of result sets into component tables" do
216
- ds = @ds1.graph(@ds2, :x=>:id).ungraphed
217
- def ds.fetch_rows(sql, &block)
218
- yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7})
219
- end
220
- ds.all.should == [{:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7}]
205
+ @db.fetch = {:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7}
206
+ @ds1.graph(@ds2, :x=>:id).ungraphed.all.should == [{:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7}]
221
207
  end
222
208
 
223
209
  it "#graph_each should give a nil value instead of a hash when all values for a table are nil" do
224
- ds = @ds1.graph(@ds2, :x=>:id)
225
- def ds.fetch_rows(sql, &block)
226
- yield({:id=>1,:x=>2,:y=>3,:lines_id=>nil,:lines_x=>nil,:lines_y=>nil,:graph_id=>nil})
227
- end
228
- results = ds.all
229
- results.length.should == 1
230
- results.first.should == {:points=>{:id=>1, :x=>2, :y=>3}, :lines=>nil}
210
+ @db.fetch = [[{:id=>1,:x=>2,:y=>3,:lines_id=>nil,:lines_x=>nil,:lines_y=>nil,:graph_id=>nil}],
211
+ [{:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7, :graphs_id=>nil, :name=>nil, :graphs_x=>nil, :graphs_y=>nil, :graphs_lines_x=>nil},
212
+ {:id=>2,:x=>4,:y=>5,:lines_id=>nil,:lines_x=>nil,:lines_y=>nil,:graph_id=>nil, :graphs_id=>nil, :name=>nil, :graphs_x=>nil, :graphs_y=>nil, :graphs_lines_x=>nil},
213
+ {:id=>3,:x=>5,:y=>6,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7, :graphs_id=>7, :name=>8, :graphs_x=>9, :graphs_y=>10, :graphs_lines_x=>11},
214
+ {:id=>3,:x=>5,:y=>6,:lines_id=>7,:lines_x=>5,:lines_y=>8,:graph_id=>9, :graphs_id=>9, :name=>10, :graphs_x=>10, :graphs_y=>11, :graphs_lines_x=>12}]]
231
215
 
232
- ds = @ds1.graph(@ds2, :x=>:id).graph(@ds3, :id=>:graph_id)
233
- def ds.fetch_rows(sql, &block)
234
- yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7, :graphs_id=>nil, :name=>nil, :graphs_x=>nil, :graphs_y=>nil, :graphs_lines_x=>nil})
235
- yield({:id=>2,:x=>4,:y=>5,:lines_id=>nil,:lines_x=>nil,:lines_y=>nil,:graph_id=>nil, :graphs_id=>nil, :name=>nil, :graphs_x=>nil, :graphs_y=>nil, :graphs_lines_x=>nil})
236
- yield({:id=>3,:x=>5,:y=>6,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7, :graphs_id=>7, :name=>8, :graphs_x=>9, :graphs_y=>10, :graphs_lines_x=>11})
237
- yield({:id=>3,:x=>5,:y=>6,:lines_id=>7,:lines_x=>5,:lines_y=>8,:graph_id=>9, :graphs_id=>9, :name=>10, :graphs_x=>10, :graphs_y=>11, :graphs_lines_x=>12})
238
- end
239
- results = ds.all
240
- results.length.should == 4
241
- results[0].should == {:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graphs=>nil}
242
- results[1].should == {:points=>{:id=>2, :x=>4, :y=>5}, :lines=>nil, :graphs=>nil}
243
- results[2].should == {:points=>{:id=>3, :x=>5, :y=>6}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graphs=>{:id=>7, :name=>8, :x=>9, :y=>10, :lines_x=>11}}
244
- results[3].should == {:points=>{:id=>3, :x=>5, :y=>6}, :lines=>{:id=>7, :x=>5, :y=>8, :graph_id=>9}, :graphs=>{:id=>9, :name=>10, :x=>10, :y=>11, :lines_x=>12}}
216
+ @ds1.graph(@ds2, :x=>:id).all.should == [{:points=>{:id=>1, :x=>2, :y=>3}, :lines=>nil}]
217
+ @ds1.graph(@ds2, :x=>:id).graph(@ds3, :id=>:graph_id).all.should == [{:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graphs=>nil},
218
+ {:points=>{:id=>2, :x=>4, :y=>5}, :lines=>nil, :graphs=>nil},
219
+ {:points=>{:id=>3, :x=>5, :y=>6}, :lines=>{:id=>4, :x=>5, :y=>6, :graph_id=>7}, :graphs=>{:id=>7, :name=>8, :x=>9, :y=>10, :lines_x=>11}},
220
+ {:points=>{:id=>3, :x=>5, :y=>6}, :lines=>{:id=>7, :x=>5, :y=>8, :graph_id=>9}, :graphs=>{:id=>9, :name=>10, :x=>10, :y=>11, :lines_x=>12}}]
245
221
  end
246
222
 
247
223
  it "#graph_each should not give a nil value instead of a hash when any value for a table is false" do
248
- ds = @ds1.graph(@ds2, :x=>:id)
249
- def ds.fetch_rows(sql, &block)
250
- block.call(:id=>1,:x=>2,:y=>3,:lines_id=>nil,:lines_x=>false,:lines_y=>nil,:graph_id=>nil)
251
- end
252
- ds.all.should == [{:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>nil, :x=>false, :y=>nil, :graph_id=>nil}}]
224
+ @db.fetch = {:id=>1,:x=>2,:y=>3,:lines_id=>nil,:lines_x=>false,:lines_y=>nil,:graph_id=>nil}
225
+ @ds1.graph(@ds2, :x=>:id).all.should == [{:points=>{:id=>1, :x=>2, :y=>3}, :lines=>{:id=>nil, :x=>false, :y=>nil, :graph_id=>nil}}]
253
226
  end
254
227
 
255
228
  it "#graph_each should not included tables graphed with the :select => false option in the result set" do
256
- ds = @ds1.graph(:lines, {:x=>:id}, :select=>false).graph(:graphs, :id=>:graph_id)
257
- def ds.fetch_rows(sql, &block)
258
- yield({:id=>1,:x=>2,:y=>3,:graphs_id=>8, :name=>9, :graphs_x=>10, :graphs_y=>11, :lines_x=>12})
259
- end
260
- results = ds.all
261
- results.length.should == 1
262
- results.first.should == {:points=>{:id=>1, :x=>2, :y=>3}, :graphs=>{:id=>8, :name=>9, :x=>10, :y=>11, :lines_x=>12}}
229
+ @db.fetch = {:id=>1,:x=>2,:y=>3,:graphs_id=>8, :name=>9, :graphs_x=>10, :graphs_y=>11, :lines_x=>12}
230
+ @ds1.graph(:lines, {:x=>:id}, :select=>false).graph(:graphs, :id=>:graph_id).all.should == [{:points=>{:id=>1, :x=>2, :y=>3}, :graphs=>{:id=>8, :name=>9, :x=>10, :y=>11, :lines_x=>12}}]
263
231
  end
264
232
 
265
233
  it "#graph_each should only include the columns selected with #set_graph_aliases and #add_graph_aliases, if called" do
266
- ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :x], :y=>[:lines, :y])
267
- def ds.fetch_rows(sql, &block)
268
- yield({:x=>2,:y=>3})
269
- end
270
- results = ds.all
271
- results.length.should == 1
272
- results.first.should == {:points=>{:x=>2}, :lines=>{:y=>3}}
234
+ @db.fetch = [nil, [{:x=>2,:y=>3}], nil, [{:x=>2}], [{:x=>2, :q=>18}]]
273
235
 
236
+ @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :x], :y=>[:lines, :y]).all.should == [{:points=>{:x=>2}, :lines=>{:y=>3}}]
274
237
  ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :x])
275
- def ds.fetch_rows(sql, &block)
276
- yield({:x=>2})
277
- end
278
- results = ds.all
279
- results.length.should == 1
280
- results.first.should == {:points=>{:x=>2}, :lines=>nil}
281
-
238
+ ds.all.should == [{:points=>{:x=>2}, :lines=>nil}]
282
239
  ds = ds.add_graph_aliases(:q=>[:points, :r, 18])
283
- def ds.fetch_rows(sql, &block)
284
- yield({:x=>2, :q=>18})
285
- end
286
240
  ds.all.should == [{:points=>{:x=>2, :r=>18}, :lines=>nil}]
287
241
  end
288
242
 
289
243
  it "#graph_each should correctly map values when #set_graph_aliases is used with a third argument for each entry" do
290
- ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :z1, 2], :y=>[:lines, :z2, :random.sql_function])
291
- def ds.fetch_rows(sql, &block)
292
- yield({:x=>2,:y=>3})
293
- end
294
- results = ds.all
295
- results.length.should == 1
296
- results.first.should == {:points=>{:z1=>2}, :lines=>{:z2=>3}}
244
+ @db.fetch = [nil, {:x=>2,:y=>3}]
245
+ @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points, :z1, 2], :y=>[:lines, :z2, :random.sql_function]).all.should == [{:points=>{:z1=>2}, :lines=>{:z2=>3}}]
297
246
  end
298
247
 
299
248
  it "#graph_each should correctly map values when #set_graph_aliases is used with a single argument for each entry" do
300
- ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points], :y=>[:lines])
301
- def ds.fetch_rows(sql, &block)
302
- yield({:x=>2,:y=>3})
303
- end
304
- results = ds.all
305
- results.length.should == 1
306
- results.first.should == {:points=>{:x=>2}, :lines=>{:y=>3}}
249
+ @db.fetch = [nil, {:x=>2,:y=>3}]
250
+ @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>[:points], :y=>[:lines]).all.should == [{:points=>{:x=>2}, :lines=>{:y=>3}}]
307
251
  end
308
252
 
309
253
  it "#graph_each should correctly map values when #set_graph_aliases is used with a symbol for each entry" do
310
- ds = @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>:points, :y=>:lines)
311
- def ds.fetch_rows(sql, &block)
312
- yield({:x=>2,:y=>3})
313
- end
314
- results = ds.all
315
- results.length.should == 1
316
- results.first.should == {:points=>{:x=>2}, :lines=>{:y=>3}}
254
+ @db.fetch = [nil, {:x=>2,:y=>3}]
255
+ @ds1.graph(:lines, :x=>:id).set_graph_aliases(:x=>:points, :y=>:lines).all.should == [{:points=>{:x=>2}, :lines=>{:y=>3}}]
317
256
  end
318
257
 
319
258
  it "#graph_each should run the row_proc for graphed datasets" do
320
259
  @ds1.row_proc = proc{|h| h.keys.each{|k| h[k] *= 2}; h}
321
260
  @ds2.row_proc = proc{|h| h.keys.each{|k| h[k] *= 3}; h}
322
- ds = @ds1.graph(@ds2, :x=>:id)
323
- def ds.fetch_rows(sql, &block)
324
- yield({:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7})
325
- end
326
- results = ds.all
327
- results.length.should == 1
328
- results.first.should == {:points=>{:id=>2, :x=>4, :y=>6}, :lines=>{:id=>12, :x=>15, :y=>18, :graph_id=>21}}
261
+ @db.fetch = {:id=>1,:x=>2,:y=>3,:lines_id=>4,:lines_x=>5,:lines_y=>6,:graph_id=>7}
262
+ @ds1.graph(@ds2, :x=>:id).all.should == [{:points=>{:id=>2, :x=>4, :y=>6}, :lines=>{:id=>12, :x=>15, :y=>18, :graph_id=>21}}]
329
263
  end
330
264
  end