sequel 3.10.0 → 3.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +68 -0
- data/COPYING +1 -1
- data/README.rdoc +87 -27
- data/bin/sequel +2 -4
- data/doc/association_basics.rdoc +1383 -0
- data/doc/dataset_basics.rdoc +106 -0
- data/doc/opening_databases.rdoc +45 -16
- data/doc/querying.rdoc +210 -0
- data/doc/release_notes/3.11.0.txt +254 -0
- data/doc/virtual_rows.rdoc +217 -31
- data/lib/sequel/adapters/ado.rb +28 -12
- data/lib/sequel/adapters/ado/mssql.rb +33 -1
- data/lib/sequel/adapters/amalgalite.rb +13 -8
- data/lib/sequel/adapters/db2.rb +1 -2
- data/lib/sequel/adapters/dbi.rb +7 -4
- data/lib/sequel/adapters/do.rb +14 -15
- data/lib/sequel/adapters/do/postgres.rb +4 -5
- data/lib/sequel/adapters/do/sqlite.rb +9 -0
- data/lib/sequel/adapters/firebird.rb +5 -10
- data/lib/sequel/adapters/informix.rb +2 -4
- data/lib/sequel/adapters/jdbc.rb +111 -49
- data/lib/sequel/adapters/jdbc/mssql.rb +1 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +11 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +4 -7
- data/lib/sequel/adapters/jdbc/postgresql.rb +8 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +12 -0
- data/lib/sequel/adapters/mysql.rb +14 -5
- data/lib/sequel/adapters/odbc.rb +2 -4
- data/lib/sequel/adapters/odbc/mssql.rb +2 -4
- data/lib/sequel/adapters/openbase.rb +1 -2
- data/lib/sequel/adapters/oracle.rb +4 -8
- data/lib/sequel/adapters/postgres.rb +4 -11
- data/lib/sequel/adapters/shared/mssql.rb +22 -9
- data/lib/sequel/adapters/shared/mysql.rb +33 -30
- data/lib/sequel/adapters/shared/oracle.rb +0 -5
- data/lib/sequel/adapters/shared/postgres.rb +13 -11
- data/lib/sequel/adapters/shared/sqlite.rb +56 -10
- data/lib/sequel/adapters/sqlite.rb +16 -9
- data/lib/sequel/connection_pool.rb +6 -1
- data/lib/sequel/connection_pool/single.rb +1 -0
- data/lib/sequel/core.rb +6 -1
- data/lib/sequel/database.rb +52 -23
- data/lib/sequel/database/schema_generator.rb +6 -0
- data/lib/sequel/database/schema_methods.rb +5 -5
- data/lib/sequel/database/schema_sql.rb +1 -1
- data/lib/sequel/dataset.rb +4 -190
- data/lib/sequel/dataset/actions.rb +323 -1
- data/lib/sequel/dataset/features.rb +18 -2
- data/lib/sequel/dataset/graph.rb +7 -0
- data/lib/sequel/dataset/misc.rb +119 -0
- data/lib/sequel/dataset/mutation.rb +64 -0
- data/lib/sequel/dataset/prepared_statements.rb +6 -0
- data/lib/sequel/dataset/query.rb +272 -6
- data/lib/sequel/dataset/sql.rb +186 -394
- data/lib/sequel/model.rb +4 -2
- data/lib/sequel/model/associations.rb +31 -14
- data/lib/sequel/model/base.rb +32 -13
- data/lib/sequel/model/exceptions.rb +8 -4
- data/lib/sequel/model/plugins.rb +3 -13
- data/lib/sequel/plugins/active_model.rb +26 -7
- data/lib/sequel/plugins/instance_filters.rb +98 -0
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/optimistic_locking.rb +25 -9
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +26 -0
- data/spec/adapters/mysql_spec.rb +33 -4
- data/spec/adapters/postgres_spec.rb +24 -1
- data/spec/adapters/spec_helper.rb +6 -0
- data/spec/adapters/sqlite_spec.rb +28 -0
- data/spec/core/connection_pool_spec.rb +17 -5
- data/spec/core/database_spec.rb +101 -1
- data/spec/core/dataset_spec.rb +42 -4
- data/spec/core/schema_spec.rb +13 -0
- data/spec/extensions/active_model_spec.rb +34 -11
- data/spec/extensions/caching_spec.rb +2 -0
- data/spec/extensions/instance_filters_spec.rb +55 -0
- data/spec/extensions/spec_helper.rb +2 -0
- data/spec/integration/dataset_test.rb +12 -1
- data/spec/integration/model_test.rb +12 -0
- data/spec/integration/plugin_test.rb +61 -1
- data/spec/integration/schema_test.rb +14 -3
- data/spec/model/base_spec.rb +27 -0
- data/spec/model/plugins_spec.rb +0 -22
- data/spec/model/record_spec.rb +32 -1
- data/spec/model/spec_helper.rb +2 -0
- metadata +14 -3
- data/lib/sequel/dataset/convenience.rb +0 -326
data/lib/sequel/version.rb
CHANGED
data/spec/adapters/mssql_spec.rb
CHANGED
@@ -375,3 +375,29 @@ context "MSSSQL::Dataset#into" do
|
|
375
375
|
@db.drop_table(:new)
|
376
376
|
end
|
377
377
|
end
|
378
|
+
|
379
|
+
context "A MSSQL database" do
|
380
|
+
before do
|
381
|
+
@db = MSSQL_DB
|
382
|
+
end
|
383
|
+
after do
|
384
|
+
@db.drop_table(:a)
|
385
|
+
end
|
386
|
+
|
387
|
+
specify "should handle many existing types for set_column_allow_null" do
|
388
|
+
@db.create_table!(:a){column :a, 'integer'}
|
389
|
+
@db.alter_table(:a){set_column_allow_null :a, false}
|
390
|
+
@db.create_table!(:a){column :a, 'decimal(24, 2)'}
|
391
|
+
@db.alter_table(:a){set_column_allow_null :a, false}
|
392
|
+
@db.schema(:a).first.last[:column_size].should == 24
|
393
|
+
@db.schema(:a).first.last[:scale].should == 2
|
394
|
+
@db.create_table!(:a){column :a, 'decimal(10)'}
|
395
|
+
@db.schema(:a).first.last[:column_size].should == 10
|
396
|
+
@db.schema(:a).first.last[:scale].should == 0
|
397
|
+
@db.alter_table(:a){set_column_allow_null :a, false}
|
398
|
+
@db.create_table!(:a){column :a, 'nchar(2)'}
|
399
|
+
@db.alter_table(:a){set_column_allow_null :a, false}
|
400
|
+
s = @db.schema(:a).first.last
|
401
|
+
(s[:max_chars] || s[:column_size]).should == 2
|
402
|
+
end
|
403
|
+
end
|
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -107,14 +107,20 @@ if MYSQL_DB.class.adapter_scheme == :mysql
|
|
107
107
|
@db.schema(:booltest, :reload=>true).should == [[:b, {:type=>:integer, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(1)"}, ], [:i, {:type=>:integer, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(4)"}, ]]
|
108
108
|
end
|
109
109
|
|
110
|
-
specify "should return
|
110
|
+
specify "should return tinyint(1)s as bools and tinyint(4)s as integers when set" do
|
111
|
+
Sequel::MySQL.convert_tinyint_to_bool = true
|
111
112
|
@ds.delete
|
112
113
|
@ds << {:b=>true, :i=>10}
|
113
|
-
@ds.all.should == [{:b=>true, :i=>
|
114
|
+
@ds.all.should == [{:b=>true, :i=>10}]
|
114
115
|
@ds.delete
|
115
116
|
@ds << {:b=>false, :i=>0}
|
116
|
-
@ds.all.should == [{:b=>false, :i=>
|
117
|
-
|
117
|
+
@ds.all.should == [{:b=>false, :i=>0}]
|
118
|
+
@ds.delete
|
119
|
+
@ds << {:b=>true, :i=>1}
|
120
|
+
@ds.all.should == [{:b=>true, :i=>1}]
|
121
|
+
end
|
122
|
+
|
123
|
+
specify "should return all tinyints as integers when unset" do
|
118
124
|
Sequel::MySQL.convert_tinyint_to_bool = false
|
119
125
|
@ds.delete
|
120
126
|
@ds << {:b=>true, :i=>10}
|
@@ -244,6 +250,29 @@ context "MySQL datasets" do
|
|
244
250
|
end
|
245
251
|
end
|
246
252
|
|
253
|
+
describe "Dataset#distinct" do
|
254
|
+
before do
|
255
|
+
@db = MYSQL_DB
|
256
|
+
@db.create_table!(:a) do
|
257
|
+
Integer :a
|
258
|
+
Integer :b
|
259
|
+
end
|
260
|
+
@ds = @db[:a]
|
261
|
+
end
|
262
|
+
after do
|
263
|
+
@db.drop_table(:a)
|
264
|
+
end
|
265
|
+
|
266
|
+
it "#distinct with arguments should return results distinct on those arguments" do
|
267
|
+
@ds.insert(20, 10)
|
268
|
+
@ds.insert(30, 10)
|
269
|
+
@ds.order(:b, :a).distinct.map(:a).should == [20, 30]
|
270
|
+
@ds.order(:b, :a.desc).distinct.map(:a).should == [30, 20]
|
271
|
+
# MySQL doesn't respect orders when using the nonstandard GROUP BY
|
272
|
+
[[20], [30]].should include(@ds.order(:b, :a).distinct(:b).map(:a))
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
247
276
|
context "MySQL join expressions" do
|
248
277
|
before do
|
249
278
|
@ds = MYSQL_DB[:nodes]
|
@@ -148,6 +148,29 @@ context "A PostgreSQL dataset" do
|
|
148
148
|
end
|
149
149
|
end
|
150
150
|
|
151
|
+
describe "Dataset#distinct" do
|
152
|
+
before do
|
153
|
+
@db = POSTGRES_DB
|
154
|
+
@db.create_table!(:a) do
|
155
|
+
Integer :a
|
156
|
+
Integer :b
|
157
|
+
end
|
158
|
+
@ds = @db[:a]
|
159
|
+
end
|
160
|
+
after do
|
161
|
+
@db.drop_table(:a)
|
162
|
+
end
|
163
|
+
|
164
|
+
it "#distinct with arguments should return results distinct on those arguments" do
|
165
|
+
@ds.insert(20, 10)
|
166
|
+
@ds.insert(30, 10)
|
167
|
+
@ds.order(:b, :a).distinct.map(:a).should == [20, 30]
|
168
|
+
@ds.order(:b, :a.desc).distinct.map(:a).should == [30, 20]
|
169
|
+
@ds.order(:b, :a).distinct(:b).map(:a).should == [20]
|
170
|
+
@ds.order(:b, :a.desc).distinct(:b).map(:a).should == [30]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
151
174
|
if POSTGRES_DB.pool.respond_to?(:max_size) and POSTGRES_DB.pool.max_size > 1
|
152
175
|
describe "Dataset#for_update support" do
|
153
176
|
before do
|
@@ -194,7 +217,7 @@ if POSTGRES_DB.pool.respond_to?(:max_size) and POSTGRES_DB.pool.max_size > 1
|
|
194
217
|
c = @ds.for_share.filter(:id=>1).first
|
195
218
|
end
|
196
219
|
end
|
197
|
-
sleep 0.
|
220
|
+
sleep 0.1
|
198
221
|
@ds.filter(:id=>1).update(:name=>'Jim')
|
199
222
|
c.should == {:id=>1, :number=>20, :name=>nil}
|
200
223
|
end
|
@@ -36,6 +36,34 @@ context "An SQLite database" do
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
+
specify "should provide the SQLite version as an integer" do
|
40
|
+
@db.sqlite_version.should be_a_kind_of(Integer)
|
41
|
+
end
|
42
|
+
|
43
|
+
specify "should support setting and getting the foreign_keys pragma" do
|
44
|
+
(@db.sqlite_version >= 30619 ? [true, false] : [nil]).should include(@db.foreign_keys)
|
45
|
+
@db.foreign_keys = true
|
46
|
+
@db.foreign_keys = false
|
47
|
+
end
|
48
|
+
|
49
|
+
if SQLITE_DB.sqlite_version >= 30619
|
50
|
+
specify "should enforce foreign key integrity if foreign_keys pragma is set" do
|
51
|
+
@db.foreign_keys = true
|
52
|
+
@db.create_table!(:fk){primary_key :id; foreign_key :parent_id, :fk}
|
53
|
+
@db[:fk].insert(1, nil)
|
54
|
+
@db[:fk].insert(2, 1)
|
55
|
+
@db[:fk].insert(3, 3)
|
56
|
+
proc{@db[:fk].insert(4, 5)}.should raise_error(Sequel::Error)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
specify "should not enforce foreign key integrity if foreign_keys pragma is unset" do
|
61
|
+
@db.foreign_keys = false
|
62
|
+
@db.create_table!(:fk){primary_key :id; foreign_key :parent_id, :fk}
|
63
|
+
@db[:fk].insert(1, 2)
|
64
|
+
@db[:fk].all.should == [{:id=>1, :parent_id=>2}]
|
65
|
+
end
|
66
|
+
|
39
67
|
specify "should provide a list of existing tables" do
|
40
68
|
@db.drop_table(:testing) rescue nil
|
41
69
|
@db.tables.should be_a_kind_of(Array)
|
@@ -240,8 +240,8 @@ shared_examples_for "A threaded connection pool" do
|
|
240
240
|
threads = []
|
241
241
|
stop = nil
|
242
242
|
|
243
|
-
5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.
|
244
|
-
sleep 0.
|
243
|
+
5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.02;end}}; sleep 0.02}
|
244
|
+
sleep 0.04
|
245
245
|
threads.each {|t| t.should be_alive}
|
246
246
|
cc.size.should == 5
|
247
247
|
@invoked_count.should == 5
|
@@ -253,16 +253,16 @@ shared_examples_for "A threaded connection pool" do
|
|
253
253
|
@pool.allocated.should == h
|
254
254
|
|
255
255
|
threads[0].raise "your'e dead"
|
256
|
-
sleep 0.
|
256
|
+
sleep 0.02
|
257
257
|
threads[3].raise "your'e dead too"
|
258
258
|
|
259
|
-
sleep 0.
|
259
|
+
sleep 0.02
|
260
260
|
|
261
261
|
@pool.available_connections.should == [1, 4]
|
262
262
|
@pool.allocated.should == {threads[1]=>2, threads[2]=>3, threads[4]=>5}
|
263
263
|
|
264
264
|
stop = true
|
265
|
-
sleep 0.
|
265
|
+
sleep 0.04
|
266
266
|
|
267
267
|
@pool.available_connections.size.should == 5
|
268
268
|
@pool.allocated.should be_empty
|
@@ -734,6 +734,12 @@ context "A single threaded pool with multiple servers" do
|
|
734
734
|
end
|
735
735
|
|
736
736
|
shared_examples_for "All connection pools classes" do
|
737
|
+
specify "should not raise an error when disconnecting twice" do
|
738
|
+
c = @class.new({}){123}
|
739
|
+
proc{c.disconnect}.should_not raise_error
|
740
|
+
proc{c.disconnect}.should_not raise_error
|
741
|
+
end
|
742
|
+
|
737
743
|
specify "should yield a connection created by the initialize block to hold" do
|
738
744
|
x = nil
|
739
745
|
@class.new({}){123}.hold{|c| x = c}
|
@@ -746,6 +752,12 @@ shared_examples_for "All connection pools classes" do
|
|
746
752
|
x.should == [:default, :default]
|
747
753
|
end
|
748
754
|
|
755
|
+
specify "should have respect an :after_connect proc that is called with each newly created connection" do
|
756
|
+
x = nil
|
757
|
+
@class.new(:after_connect=>proc{|c| x = [c, c]}){|c| 123}.hold{}
|
758
|
+
x.should == [123, 123]
|
759
|
+
end
|
760
|
+
|
749
761
|
specify "should raise a DatabaseConnectionError if the connection raises an exception" do
|
750
762
|
proc{@class.new({}){|c| raise Exception}.hold{}}.should raise_error(Sequel::DatabaseConnectionError)
|
751
763
|
end
|
data/spec/core/database_spec.rb
CHANGED
@@ -209,6 +209,88 @@ context "Database#connect" do
|
|
209
209
|
end
|
210
210
|
end
|
211
211
|
|
212
|
+
context "Database#log_info" do
|
213
|
+
before do
|
214
|
+
@o = Object.new
|
215
|
+
def @o.logs; @logs || []; end
|
216
|
+
def @o.method_missing(*args); (@logs ||= []) << args; end
|
217
|
+
@db = Sequel::Database.new(:logger=>@o)
|
218
|
+
end
|
219
|
+
|
220
|
+
specify "should log message at info level to all loggers" do
|
221
|
+
@db.log_info('blah')
|
222
|
+
@o.logs.should == [[:info, 'blah']]
|
223
|
+
end
|
224
|
+
|
225
|
+
specify "should log message with args at info level to all loggers" do
|
226
|
+
@db.log_info('blah', [1, 2])
|
227
|
+
@o.logs.should == [[:info, 'blah; [1, 2]']]
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context "Database#log_yield" do
|
232
|
+
before do
|
233
|
+
@o = Object.new
|
234
|
+
def @o.logs; @logs || []; end
|
235
|
+
def @o.warn(*args); (@logs ||= []) << [:warn] + args; end
|
236
|
+
def @o.method_missing(*args); (@logs ||= []) << args; end
|
237
|
+
@db = Sequel::Database.new(:logger=>@o)
|
238
|
+
end
|
239
|
+
|
240
|
+
specify "should yield to the passed block" do
|
241
|
+
a = nil
|
242
|
+
@db.log_yield('blah'){a = 1}
|
243
|
+
a.should == 1
|
244
|
+
end
|
245
|
+
|
246
|
+
specify "should raise an exception if a block is not passed" do
|
247
|
+
proc{@db.log_yield('blah')}.should raise_error
|
248
|
+
end
|
249
|
+
|
250
|
+
specify "should log message with duration at info level to all loggers" do
|
251
|
+
@db.log_yield('blah'){}
|
252
|
+
@o.logs.length.should == 1
|
253
|
+
@o.logs.first.length.should == 2
|
254
|
+
@o.logs.first.first.should == :info
|
255
|
+
@o.logs.first.last.should =~ /\A\(\d\.\d{6}s\) blah\z/
|
256
|
+
end
|
257
|
+
|
258
|
+
specify "should log message with duration at warn level if duration greater than log_warn_duration" do
|
259
|
+
@db.log_warn_duration = 0
|
260
|
+
@db.log_yield('blah'){}
|
261
|
+
@o.logs.length.should == 1
|
262
|
+
@o.logs.first.length.should == 2
|
263
|
+
@o.logs.first.first.should == :warn
|
264
|
+
@o.logs.first.last.should =~ /\A\(\d\.\d{6}s\) blah\z/
|
265
|
+
end
|
266
|
+
|
267
|
+
specify "should log message with duration at info level if duration less than log_warn_duration" do
|
268
|
+
@db.log_warn_duration = 1000
|
269
|
+
@db.log_yield('blah'){}
|
270
|
+
@o.logs.length.should == 1
|
271
|
+
@o.logs.first.length.should == 2
|
272
|
+
@o.logs.first.first.should == :info
|
273
|
+
@o.logs.first.last.should =~ /\A\(\d\.\d{6}s\) blah\z/
|
274
|
+
end
|
275
|
+
|
276
|
+
specify "should log message at error level if block raises an error" do
|
277
|
+
@db.log_warn_duration = 0
|
278
|
+
proc{@db.log_yield('blah'){raise Sequel::Error, 'adsf'}}.should raise_error
|
279
|
+
@o.logs.length.should == 1
|
280
|
+
@o.logs.first.length.should == 2
|
281
|
+
@o.logs.first.first.should == :error
|
282
|
+
@o.logs.first.last.should =~ /\ASequel::Error: adsf: blah\z/
|
283
|
+
end
|
284
|
+
|
285
|
+
specify "should include args with message if args passed" do
|
286
|
+
@db.log_yield('blah', [1, 2]){}
|
287
|
+
@o.logs.length.should == 1
|
288
|
+
@o.logs.first.length.should == 2
|
289
|
+
@o.logs.first.first.should == :info
|
290
|
+
@o.logs.first.last.should =~ /\A\(\d\.\d{6}s\) blah; \[1, 2\]\z/
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
212
294
|
context "Database#uri" do
|
213
295
|
before do
|
214
296
|
@c = Class.new(Sequel::Database) do
|
@@ -342,7 +424,7 @@ context "Database#test_connection" do
|
|
342
424
|
@db = Sequel::Database.new{@test = rand(100)}
|
343
425
|
end
|
344
426
|
|
345
|
-
specify "should
|
427
|
+
specify "should pool#hold" do
|
346
428
|
@db.test_connection
|
347
429
|
@test.should_not be_nil
|
348
430
|
end
|
@@ -350,6 +432,10 @@ context "Database#test_connection" do
|
|
350
432
|
specify "should return true if successful" do
|
351
433
|
@db.test_connection.should be_true
|
352
434
|
end
|
435
|
+
|
436
|
+
specify "should raise an error if the attempting to connect raises an error" do
|
437
|
+
proc{Sequel::Database.new{raise Sequel::Error, 'blah'}.test_connection}.should raise_error(Sequel::Error)
|
438
|
+
end
|
353
439
|
end
|
354
440
|
|
355
441
|
class DummyDataset < Sequel::Dataset
|
@@ -875,6 +961,20 @@ context "A Database adapter with a scheme" do
|
|
875
961
|
c.opts[:database].should == 'd[b]'
|
876
962
|
c.opts[:host].should == 'domain\\instance'
|
877
963
|
end
|
964
|
+
|
965
|
+
specify "should test the connection if test parameter is truthy" do
|
966
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d?test=t'}.should raise_error(Sequel::DatabaseConnectionError)
|
967
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d?test=1'}.should raise_error(Sequel::DatabaseConnectionError)
|
968
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d', :test=>true}.should raise_error(Sequel::DatabaseConnectionError)
|
969
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d', :test=>'t'}.should raise_error(Sequel::DatabaseConnectionError)
|
970
|
+
end
|
971
|
+
|
972
|
+
specify "should not test the connection if test parameter is not truthy" do
|
973
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d?test=f'}.should_not raise_error
|
974
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d?test=0'}.should_not raise_error
|
975
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d', :test=>false}.should_not raise_error
|
976
|
+
proc{Sequel.connect 'ccc:///d%5bb%5d', :test=>'f'}.should_not raise_error
|
977
|
+
end
|
878
978
|
end
|
879
979
|
|
880
980
|
context "Sequel::Database.connect" do
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -322,6 +322,16 @@ context "Dataset#where" do
|
|
322
322
|
@d3 = @dataset.where("a = 1")
|
323
323
|
end
|
324
324
|
|
325
|
+
specify "should just clone if given an empty argument" do
|
326
|
+
@dataset.where({}).sql.should == @dataset.sql
|
327
|
+
@dataset.where([]).sql.should == @dataset.sql
|
328
|
+
@dataset.where('').sql.should == @dataset.sql
|
329
|
+
|
330
|
+
@dataset.filter({}).sql.should == @dataset.sql
|
331
|
+
@dataset.filter([]).sql.should == @dataset.sql
|
332
|
+
@dataset.filter('').sql.should == @dataset.sql
|
333
|
+
end
|
334
|
+
|
325
335
|
specify "should work with hashes" do
|
326
336
|
@dataset.where(:name => 'xyz', :price => 342).select_sql.
|
327
337
|
should match(/WHERE \(\(name = 'xyz'\) AND \(price = 342\)\)|WHERE \(\(price = 342\) AND \(name = 'xyz'\)\)/)
|
@@ -735,6 +745,12 @@ context "Dataset#having" do
|
|
735
745
|
@columns = "region, sum(population), avg(gdp)"
|
736
746
|
end
|
737
747
|
|
748
|
+
specify "should just clone if given an empty argument" do
|
749
|
+
@dataset.having({}).sql.should == @dataset.sql
|
750
|
+
@dataset.having([]).sql.should == @dataset.sql
|
751
|
+
@dataset.having('').sql.should == @dataset.sql
|
752
|
+
end
|
753
|
+
|
738
754
|
specify "should affect select statements" do
|
739
755
|
@d1.select_sql.should ==
|
740
756
|
"SELECT #{@columns} FROM test GROUP BY region HAVING (sum(population) > 10)"
|
@@ -1151,6 +1167,28 @@ context "Dataset#select_more" do
|
|
1151
1167
|
end
|
1152
1168
|
end
|
1153
1169
|
|
1170
|
+
context "Dataset#select_append" do
|
1171
|
+
before do
|
1172
|
+
@d = Sequel::Dataset.new(nil).from(:test)
|
1173
|
+
end
|
1174
|
+
|
1175
|
+
specify "should select * in addition to columns if no columns selected" do
|
1176
|
+
@d.select_append(:a, :b).sql.should == 'SELECT *, a, b FROM test'
|
1177
|
+
@d.select_all.select_append(:a, :b).sql.should == 'SELECT *, a, b FROM test'
|
1178
|
+
@d.select(:blah).select_all.select_append(:a, :b).sql.should == 'SELECT *, a, b FROM test'
|
1179
|
+
end
|
1180
|
+
|
1181
|
+
specify "should add to the currently selected columns" do
|
1182
|
+
@d.select(:a).select_append(:b).sql.should == 'SELECT a, b FROM test'
|
1183
|
+
@d.select(:a.*).select_append(:b.*).sql.should == 'SELECT a.*, b.* FROM test'
|
1184
|
+
end
|
1185
|
+
|
1186
|
+
specify "should accept a block that yields a virtual row" do
|
1187
|
+
@d.select(:a).select_append{|o| o.b}.sql.should == 'SELECT a, b FROM test'
|
1188
|
+
@d.select(:a.*).select_append(:b.*){b(1)}.sql.should == 'SELECT a.*, b.*, b(1) FROM test'
|
1189
|
+
end
|
1190
|
+
end
|
1191
|
+
|
1154
1192
|
context "Dataset#order" do
|
1155
1193
|
before do
|
1156
1194
|
@dataset = Sequel::Dataset.new(nil).from(:test)
|
@@ -1484,13 +1522,13 @@ context "Dataset#distinct" do
|
|
1484
1522
|
@dataset.distinct.sql.should == 'SELECT DISTINCT name FROM test'
|
1485
1523
|
end
|
1486
1524
|
|
1487
|
-
specify "should raise an error if columns given and
|
1488
|
-
@dataset.meta_def(:supports_distinct_on?){false}
|
1525
|
+
specify "should raise an error if columns given and DISTINCT ON is not supported" do
|
1489
1526
|
proc{@dataset.distinct}.should_not raise_error
|
1490
1527
|
proc{@dataset.distinct(:a)}.should raise_error(Sequel::InvalidOperation)
|
1491
1528
|
end
|
1492
1529
|
|
1493
|
-
specify "should
|
1530
|
+
specify "should use DISTINCT ON if columns are given and DISTINCT ON is supported" do
|
1531
|
+
@dataset.meta_def(:supports_distinct_on?){true}
|
1494
1532
|
@dataset.distinct(:a, :b).sql.should == 'SELECT DISTINCT ON (a, b) name FROM test'
|
1495
1533
|
@dataset.distinct(:stamp.cast(:integer), :node_id=>nil).sql.should == 'SELECT DISTINCT ON (CAST(stamp AS integer), (node_id IS NULL)) name FROM test'
|
1496
1534
|
end
|
@@ -2541,7 +2579,7 @@ context "Dataset#columns" do
|
|
2541
2579
|
end
|
2542
2580
|
|
2543
2581
|
specify "should ignore any filters, orders, or DISTINCT clauses" do
|
2544
|
-
@dataset.filter!(:b=>100).order!(:b).distinct!
|
2582
|
+
@dataset.filter!(:b=>100).order!(:b).distinct!
|
2545
2583
|
@dataset.columns = nil
|
2546
2584
|
@dataset.columns.should == 'SELECT * FROM items LIMIT 1a'
|
2547
2585
|
end
|