sequel 3.35.0 → 3.36.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +78 -0
- data/Rakefile +3 -3
- data/bin/sequel +3 -1
- data/doc/advanced_associations.rdoc +154 -11
- data/doc/migration.rdoc +18 -0
- data/doc/object_model.rdoc +541 -0
- data/doc/opening_databases.rdoc +4 -1
- data/doc/release_notes/3.36.0.txt +245 -0
- data/doc/schema_modification.rdoc +0 -6
- data/lib/sequel/adapters/do/mysql.rb +7 -0
- data/lib/sequel/adapters/jdbc.rb +11 -3
- data/lib/sequel/adapters/jdbc/mysql.rb +3 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +10 -8
- data/lib/sequel/adapters/jdbc/progress.rb +21 -0
- data/lib/sequel/adapters/mock.rb +2 -6
- data/lib/sequel/adapters/mysql.rb +3 -9
- data/lib/sequel/adapters/mysql2.rb +12 -11
- data/lib/sequel/adapters/postgres.rb +32 -40
- data/lib/sequel/adapters/shared/mssql.rb +15 -11
- data/lib/sequel/adapters/shared/mysql.rb +28 -3
- data/lib/sequel/adapters/shared/oracle.rb +5 -0
- data/lib/sequel/adapters/shared/postgres.rb +59 -5
- data/lib/sequel/adapters/shared/sqlite.rb +3 -13
- data/lib/sequel/adapters/sqlite.rb +0 -7
- data/lib/sequel/adapters/swift/mysql.rb +2 -5
- data/lib/sequel/adapters/tinytds.rb +1 -2
- data/lib/sequel/connection_pool/sharded_threaded.rb +5 -1
- data/lib/sequel/connection_pool/threaded.rb +9 -1
- data/lib/sequel/database/dataset_defaults.rb +3 -1
- data/lib/sequel/database/misc.rb +7 -1
- data/lib/sequel/database/query.rb +11 -3
- data/lib/sequel/database/schema_generator.rb +40 -9
- data/lib/sequel/database/schema_methods.rb +6 -1
- data/lib/sequel/dataset/actions.rb +5 -5
- data/lib/sequel/dataset/prepared_statements.rb +3 -1
- data/lib/sequel/dataset/query.rb +1 -1
- data/lib/sequel/extensions/migration.rb +28 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +0 -9
- data/lib/sequel/extensions/pg_inet.rb +89 -0
- data/lib/sequel/extensions/pg_json.rb +178 -0
- data/lib/sequel/extensions/schema_dumper.rb +24 -6
- data/lib/sequel/model/associations.rb +19 -15
- data/lib/sequel/model/base.rb +11 -12
- data/lib/sequel/plugins/composition.rb +1 -2
- data/lib/sequel/plugins/eager_each.rb +59 -0
- data/lib/sequel/plugins/json_serializer.rb +41 -4
- data/lib/sequel/plugins/nested_attributes.rb +72 -52
- data/lib/sequel/plugins/optimistic_locking.rb +8 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +271 -1
- data/spec/adapters/sqlite_spec.rb +11 -0
- data/spec/core/connection_pool_spec.rb +26 -1
- data/spec/core/database_spec.rb +19 -0
- data/spec/core/dataset_spec.rb +45 -5
- data/spec/core/expression_filters_spec.rb +31 -67
- data/spec/core/mock_adapter_spec.rb +4 -0
- data/spec/extensions/core_extensions_spec.rb +83 -0
- data/spec/extensions/eager_each_spec.rb +34 -0
- data/spec/extensions/inflector_spec.rb +0 -4
- data/spec/extensions/json_serializer_spec.rb +32 -1
- data/spec/extensions/migration_spec.rb +28 -0
- data/spec/extensions/nested_attributes_spec.rb +134 -1
- data/spec/extensions/optimistic_locking_spec.rb +15 -1
- data/spec/extensions/pg_hstore_spec.rb +1 -1
- data/spec/extensions/pg_inet_spec.rb +44 -0
- data/spec/extensions/pg_json_spec.rb +101 -0
- data/spec/extensions/prepared_statements_spec.rb +30 -0
- data/spec/extensions/rcte_tree_spec.rb +9 -0
- data/spec/extensions/schema_dumper_spec.rb +195 -7
- data/spec/extensions/serialization_spec.rb +4 -0
- data/spec/extensions/spec_helper.rb +9 -1
- data/spec/extensions/tactical_eager_loading_spec.rb +8 -0
- data/spec/integration/database_test.rb +5 -1
- data/spec/integration/prepared_statement_test.rb +20 -2
- data/spec/model/associations_spec.rb +27 -0
- data/spec/model/base_spec.rb +54 -0
- data/spec/model/model_spec.rb +6 -0
- data/spec/model/record_spec.rb +18 -0
- data/spec/rcov.opts +2 -0
- metadata +14 -3
@@ -13,6 +13,7 @@ describe "An SQLite database" do
|
|
13
13
|
end
|
14
14
|
after do
|
15
15
|
@db.foreign_keys = @fk
|
16
|
+
@db.case_sensitive_like = true
|
16
17
|
Sequel.datetime_class = Time
|
17
18
|
end
|
18
19
|
|
@@ -38,6 +39,16 @@ describe "An SQLite database" do
|
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
42
|
+
specify "should respect case sensitive like false" do
|
43
|
+
@db.case_sensitive_like = false
|
44
|
+
@db.get(Sequel.like('a', 'A')).to_s.should == '1'
|
45
|
+
end
|
46
|
+
|
47
|
+
specify "should respect case sensitive like true" do
|
48
|
+
@db.case_sensitive_like = true
|
49
|
+
@db.get(Sequel.like('a', 'A')).to_s.should == '0'
|
50
|
+
end
|
51
|
+
|
41
52
|
specify "should provide the SQLite version as an integer" do
|
42
53
|
@db.sqlite_version.should be_a_kind_of(Integer)
|
43
54
|
end
|
@@ -187,7 +187,7 @@ describe "A connection pool with a max size of 1" do
|
|
187
187
|
q.push nil
|
188
188
|
q1.pop
|
189
189
|
|
190
|
-
t1.
|
190
|
+
t1.join
|
191
191
|
t2.should be_alive
|
192
192
|
|
193
193
|
c2.should == 'hello'
|
@@ -340,6 +340,31 @@ shared_examples_for "A threaded connection pool" do
|
|
340
340
|
@pool.available_connections.size.should == 5
|
341
341
|
@pool.allocated.should be_empty
|
342
342
|
end
|
343
|
+
|
344
|
+
specify "should store connections in a stack by default" do
|
345
|
+
c2 = nil
|
346
|
+
c = @pool.hold{|cc| Thread.new{@pool.hold{|cc2| c2 = cc2}}.join; cc}
|
347
|
+
@pool.size.should == 2
|
348
|
+
@pool.hold{|cc| cc.should == c}
|
349
|
+
@pool.hold{|cc| cc.should == c}
|
350
|
+
@pool.hold do |cc|
|
351
|
+
cc.should == c
|
352
|
+
Thread.new{@pool.hold{|cc2| cc2.should == c2}}
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
specify "should store connections in a queue if :connection_handling=>:queue" do
|
357
|
+
@pool = Sequel::ConnectionPool.get_pool(@cp_opts.merge(:connection_handling=>:queue)){@invoked_count += 1}
|
358
|
+
c2 = nil
|
359
|
+
c = @pool.hold{|cc| Thread.new{@pool.hold{|cc2| c2 = cc2}}.join; cc}
|
360
|
+
@pool.size.should == 2
|
361
|
+
@pool.hold{|cc| cc.should == c2}
|
362
|
+
@pool.hold{|cc| cc.should == c}
|
363
|
+
@pool.hold do |cc|
|
364
|
+
cc.should == c2
|
365
|
+
Thread.new{@pool.hold{|cc2| cc2.should == c}}
|
366
|
+
end
|
367
|
+
end
|
343
368
|
end
|
344
369
|
|
345
370
|
describe "Threaded Unsharded Connection Pool" do
|
data/spec/core/database_spec.rb
CHANGED
@@ -1996,12 +1996,31 @@ describe "Database#supports_transactional_ddl?" do
|
|
1996
1996
|
end
|
1997
1997
|
end
|
1998
1998
|
|
1999
|
+
describe "Database#global_index_namespace?" do
|
2000
|
+
specify "should be true by default" do
|
2001
|
+
Sequel::Database.new.global_index_namespace?.should == true
|
2002
|
+
end
|
2003
|
+
end
|
2004
|
+
|
1999
2005
|
describe "Database#supports_savepoints?" do
|
2000
2006
|
specify "should be false by default" do
|
2001
2007
|
Sequel::Database.new.supports_savepoints?.should == false
|
2002
2008
|
end
|
2003
2009
|
end
|
2004
2010
|
|
2011
|
+
describe "Database#supports_savepoints_in_prepared_transactions?" do
|
2012
|
+
specify "should be false by default" do
|
2013
|
+
Sequel::Database.new.supports_savepoints_in_prepared_transactions?.should == false
|
2014
|
+
end
|
2015
|
+
|
2016
|
+
specify "should be true if both savepoints and prepared transactions are supported" do
|
2017
|
+
db = Sequel::Database.new
|
2018
|
+
db.meta_def(:supports_savepoints?){true}
|
2019
|
+
db.meta_def(:supports_prepared_transactions?){true}
|
2020
|
+
db.supports_savepoints_in_prepared_transactions?.should == true
|
2021
|
+
end
|
2022
|
+
end
|
2023
|
+
|
2005
2024
|
describe "Database#supports_prepared_transactions?" do
|
2006
2025
|
specify "should be false by default" do
|
2007
2026
|
Sequel::Database.new.supports_prepared_transactions?.should == false
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -1199,6 +1199,17 @@ describe "Dataset#from" do
|
|
1199
1199
|
@dataset.from(@dataset.from(:a)).select_sql.should == "SELECT * FROM (SELECT * FROM a) AS t1"
|
1200
1200
|
end
|
1201
1201
|
|
1202
|
+
specify "should treat string arguments as identifiers" do
|
1203
|
+
@dataset.quote_identifiers = true
|
1204
|
+
@dataset.from('a').select_sql.should == "SELECT * FROM \"a\""
|
1205
|
+
end
|
1206
|
+
|
1207
|
+
specify "should not treat literal strings or blobs as identifiers" do
|
1208
|
+
@dataset.quote_identifiers = true
|
1209
|
+
@dataset.from('a'.lit).select_sql.should == "SELECT * FROM a"
|
1210
|
+
@dataset.from('a'.to_sequel_blob).select_sql.should == "SELECT * FROM 'a'"
|
1211
|
+
end
|
1212
|
+
|
1202
1213
|
specify "should remove all FROM tables if called with no arguments" do
|
1203
1214
|
@dataset.from.sql.should == 'SELECT *'
|
1204
1215
|
end
|
@@ -1262,6 +1273,10 @@ describe "Dataset#select" do
|
|
1262
1273
|
@d.select.sql.should == 'SELECT * FROM test'
|
1263
1274
|
end
|
1264
1275
|
|
1276
|
+
specify "should handle array condition specifiers that are aliased" do
|
1277
|
+
@d.select(Sequel.as([[:b, :c]], :n)).sql.should == 'SELECT (b = c) AS n FROM test'
|
1278
|
+
end
|
1279
|
+
|
1265
1280
|
specify "should accept a hash for AS values" do
|
1266
1281
|
@d.select(:name => 'n', :__ggh => 'age').sql.should =~ /SELECT ((name AS n, __ggh AS age)|(__ggh AS age, name AS n)) FROM test/
|
1267
1282
|
end
|
@@ -2647,6 +2662,11 @@ describe "Dataset#get" do
|
|
2647
2662
|
specify "should raise an error if both a regular argument and block argument are used" do
|
2648
2663
|
proc{@d.get(:name){|o| o.x__b.as(:name)}}.should raise_error(Sequel::Error)
|
2649
2664
|
end
|
2665
|
+
|
2666
|
+
specify "should support false and nil values" do
|
2667
|
+
@d.get(false).should == "SELECT 'f' FROM test LIMIT 1"
|
2668
|
+
@d.get(nil).should == "SELECT NULL FROM test LIMIT 1"
|
2669
|
+
end
|
2650
2670
|
end
|
2651
2671
|
|
2652
2672
|
describe "Dataset#set_row_proc" do
|
@@ -3238,6 +3258,7 @@ describe "Dataset prepared statements and bound variables " do
|
|
3238
3258
|
end
|
3239
3259
|
|
3240
3260
|
specify "#call should take a type and bind hash and interpolate it" do
|
3261
|
+
@ds.filter(:num=>:$n).call(:each, :n=>1)
|
3241
3262
|
@ds.filter(:num=>:$n).call(:select, :n=>1)
|
3242
3263
|
@ds.filter(:num=>:$n).call([:map, :a], :n=>1)
|
3243
3264
|
@ds.filter(:num=>:$n).call([:to_hash, :a, :b], :n=>1)
|
@@ -3247,7 +3268,9 @@ describe "Dataset prepared statements and bound variables " do
|
|
3247
3268
|
@ds.filter(:num=>:$n).call(:update, {:n=>1, :n2=>2}, :num=>:$n2)
|
3248
3269
|
@ds.call(:insert, {:n=>1}, :num=>:$n)
|
3249
3270
|
@ds.call(:insert_select, {:n=>1}, :num=>:$n)
|
3250
|
-
@db.sqls.should == [
|
3271
|
+
@db.sqls.should == [
|
3272
|
+
'SELECT * FROM items WHERE (num = 1)',
|
3273
|
+
'SELECT * FROM items WHERE (num = 1)',
|
3251
3274
|
'SELECT * FROM items WHERE (num = 1)',
|
3252
3275
|
'SELECT * FROM items WHERE (num = 1)',
|
3253
3276
|
'SELECT * FROM items WHERE (num = 1)',
|
@@ -3260,6 +3283,7 @@ describe "Dataset prepared statements and bound variables " do
|
|
3260
3283
|
|
3261
3284
|
specify "#prepare should take a type and name and store it in the database for later use with call" do
|
3262
3285
|
pss = []
|
3286
|
+
pss << @ds.filter(:num=>:$n).prepare(:each, :en)
|
3263
3287
|
pss << @ds.filter(:num=>:$n).prepare(:select, :sn)
|
3264
3288
|
pss << @ds.filter(:num=>:$n).prepare([:map, :a], :sm)
|
3265
3289
|
pss << @ds.filter(:num=>:$n).prepare([:to_hash, :a, :b], :sh)
|
@@ -3269,8 +3293,9 @@ describe "Dataset prepared statements and bound variables " do
|
|
3269
3293
|
pss << @ds.filter(:num=>:$n).prepare(:update, :un, :num=>:$n2)
|
3270
3294
|
pss << @ds.prepare(:insert, :in, :num=>:$n)
|
3271
3295
|
pss << @ds.prepare(:insert_select, :ins, :num=>:$n)
|
3272
|
-
@db.prepared_statements.keys.sort_by{|k| k.to_s}.should == [:dn, :fn, :in, :ins, :sh, :shg, :sm, :sn, :un]
|
3273
|
-
[:sn, :sm, :sh, :shg, :fn, :dn, :un, :in, :ins].each_with_index{|x, i| @db.prepared_statements[x].should == pss[i]}
|
3296
|
+
@db.prepared_statements.keys.sort_by{|k| k.to_s}.should == [:dn, :en, :fn, :in, :ins, :sh, :shg, :sm, :sn, :un]
|
3297
|
+
[:en, :sn, :sm, :sh, :shg, :fn, :dn, :un, :in, :ins].each_with_index{|x, i| @db.prepared_statements[x].should == pss[i]}
|
3298
|
+
@db.call(:en, :n=>1){}
|
3274
3299
|
@db.call(:sn, :n=>1)
|
3275
3300
|
@db.call(:sm, :n=>1)
|
3276
3301
|
@db.call(:sh, :n=>1)
|
@@ -3280,7 +3305,9 @@ describe "Dataset prepared statements and bound variables " do
|
|
3280
3305
|
@db.call(:un, :n=>1, :n2=>2)
|
3281
3306
|
@db.call(:in, :n=>1)
|
3282
3307
|
@db.call(:ins, :n=>1)
|
3283
|
-
@db.sqls.should == [
|
3308
|
+
@db.sqls.should == [
|
3309
|
+
'SELECT * FROM items WHERE (num = 1)',
|
3310
|
+
'SELECT * FROM items WHERE (num = 1)',
|
3284
3311
|
'SELECT * FROM items WHERE (num = 1)',
|
3285
3312
|
'SELECT * FROM items WHERE (num = 1)',
|
3286
3313
|
'SELECT * FROM items WHERE (num = 1)',
|
@@ -3291,6 +3318,11 @@ describe "Dataset prepared statements and bound variables " do
|
|
3291
3318
|
'INSERT INTO items (num) VALUES (1) RETURNING *']
|
3292
3319
|
end
|
3293
3320
|
|
3321
|
+
specify "#call should default to using :all if an invalid type is given" do
|
3322
|
+
@ds.filter(:num=>:$n).call(:select_all, :n=>1)
|
3323
|
+
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
3324
|
+
end
|
3325
|
+
|
3294
3326
|
specify "#inspect should indicate it is a prepared statement with the prepared SQL" do
|
3295
3327
|
@ds.filter(:num=>:$n).prepare(:select, :sn).inspect.should == \
|
3296
3328
|
'<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
|
@@ -3361,7 +3393,7 @@ describe Sequel::Dataset::UnnumberedArgumentMapper do
|
|
3361
3393
|
@ps.first.inspect.should == '<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = ?)">'
|
3362
3394
|
end
|
3363
3395
|
|
3364
|
-
specify "should
|
3396
|
+
specify "should submit the SQL to the database with placeholders and bind variables" do
|
3365
3397
|
@ps.each{|p| p.prepared_sql; p.call(:n=>1)}
|
3366
3398
|
@db.sqls.should == ["SELECT * FROM items WHERE (num = ?) -- args: [1]",
|
3367
3399
|
"SELECT * FROM items WHERE (num = ?) -- args: [1]",
|
@@ -3370,6 +3402,14 @@ describe Sequel::Dataset::UnnumberedArgumentMapper do
|
|
3370
3402
|
"INSERT INTO items (num) VALUES (?) -- args: [1]",
|
3371
3403
|
"UPDATE items SET num = ? WHERE (num = ?) -- args: [1, 1]"]
|
3372
3404
|
end
|
3405
|
+
|
3406
|
+
specify "should handle unrecognized statement types as :all" do
|
3407
|
+
ps = @ds.prepare(:select_all, :s)
|
3408
|
+
ps.extend(Sequel::Dataset::UnnumberedArgumentMapper)
|
3409
|
+
ps.prepared_sql
|
3410
|
+
ps.call(:n=>1)
|
3411
|
+
@db.sqls.should == ["SELECT * FROM items WHERE (num = ?) -- args: [1]"]
|
3412
|
+
end
|
3373
3413
|
end
|
3374
3414
|
|
3375
3415
|
describe "Sequel::Dataset#server" do
|
@@ -212,8 +212,6 @@ describe "Blockless Ruby Filters" do
|
|
212
212
|
@d.l(:x.sql_boolean & :y).should == '(x AND y)'
|
213
213
|
@d.l(:x & :y & :z).should == '(x AND y AND z)'
|
214
214
|
@d.l(:x & {:y => :z}).should == '(x AND (y = z))'
|
215
|
-
@d.l({:y => :z} & :x).should == '((y = z) AND x)'
|
216
|
-
@d.l({:x => :a} & {:y => :z}).should == '((x = a) AND (y = z))'
|
217
215
|
@d.l((:x + 200 < 0) & (:y - 200 < 0)).should == '(((x + 200) < 0) AND ((y - 200) < 0))'
|
218
216
|
@d.l(:x & ~:y).should == '(x AND NOT y)'
|
219
217
|
@d.l(~:x & :y).should == '(NOT x AND y)'
|
@@ -225,8 +223,6 @@ describe "Blockless Ruby Filters" do
|
|
225
223
|
@d.l(:x.sql_boolean | :y).should == '(x OR y)'
|
226
224
|
@d.l(:x | :y | :z).should == '(x OR y OR z)'
|
227
225
|
@d.l(:x | {:y => :z}).should == '(x OR (y = z))'
|
228
|
-
@d.l({:y => :z} | :x).should == '((y = z) OR x)'
|
229
|
-
@d.l({:x => :a} | {:y => :z}).should == '((x = a) OR (y = z))'
|
230
226
|
@d.l((:x.sql_number > 200) | (:y.sql_number < 200)).should == '((x > 200) OR (y < 200))'
|
231
227
|
end
|
232
228
|
|
@@ -267,60 +263,12 @@ describe "Blockless Ruby Filters" do
|
|
267
263
|
@d.l(:x => nil, :y => [1,2,3])[1...-1].split(' AND ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
|
268
264
|
end
|
269
265
|
|
270
|
-
it "should support sql_expr on hashes" do
|
271
|
-
@d.l({:x => 100, :y => 'a'}.sql_expr)[1...-1].split(' AND ').sort.should == ['(x = 100)', '(y = \'a\')']
|
272
|
-
@d.l({:x => true, :y => false}.sql_expr)[1...-1].split(' AND ').sort.should == ['(x IS TRUE)', '(y IS FALSE)']
|
273
|
-
@d.l({:x => nil, :y => [1,2,3]}.sql_expr)[1...-1].split(' AND ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
|
274
|
-
end
|
275
|
-
|
276
|
-
it "should support sql_negate on hashes" do
|
277
|
-
@d.l({:x => 100, :y => 'a'}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x != 100)', '(y != \'a\')']
|
278
|
-
@d.l({:x => true, :y => false}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x IS NOT TRUE)', '(y IS NOT FALSE)']
|
279
|
-
@d.l({:x => nil, :y => [1,2,3]}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x IS NOT NULL)', '(y NOT IN (1, 2, 3))']
|
280
|
-
end
|
281
|
-
|
282
|
-
it "should support ~ on hashes" do
|
283
|
-
@d.l(~{:x => 100, :y => 'a'})[1...-1].split(' OR ').sort.should == ['(x != 100)', '(y != \'a\')']
|
284
|
-
@d.l(~{:x => true, :y => false})[1...-1].split(' OR ').sort.should == ['(x IS NOT TRUE)', '(y IS NOT FALSE)']
|
285
|
-
@d.l(~{:x => nil, :y => [1,2,3]})[1...-1].split(' OR ').sort.should == ['(x IS NOT NULL)', '(y NOT IN (1, 2, 3))']
|
286
|
-
end
|
287
|
-
|
288
|
-
it "should support sql_or on hashes" do
|
289
|
-
@d.l({:x => 100, :y => 'a'}.sql_or)[1...-1].split(' OR ').sort.should == ['(x = 100)', '(y = \'a\')']
|
290
|
-
@d.l({:x => true, :y => false}.sql_or)[1...-1].split(' OR ').sort.should == ['(x IS TRUE)', '(y IS FALSE)']
|
291
|
-
@d.l({:x => nil, :y => [1,2,3]}.sql_or)[1...-1].split(' OR ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
|
292
|
-
end
|
293
|
-
|
294
266
|
it "should support arrays with all two pairs the same as hashes" do
|
295
267
|
@d.l([[:x, 100],[:y, 'a']]).should == '((x = 100) AND (y = \'a\'))'
|
296
268
|
@d.l([[:x, true], [:y, false]]).should == '((x IS TRUE) AND (y IS FALSE))'
|
297
269
|
@d.l([[:x, nil], [:y, [1,2,3]]]).should == '((x IS NULL) AND (y IN (1, 2, 3)))'
|
298
270
|
end
|
299
271
|
|
300
|
-
it "should support sql_expr on arrays with all two pairs" do
|
301
|
-
@d.l([[:x, 100],[:y, 'a']].sql_expr).should == '((x = 100) AND (y = \'a\'))'
|
302
|
-
@d.l([[:x, true], [:y, false]].sql_expr).should == '((x IS TRUE) AND (y IS FALSE))'
|
303
|
-
@d.l([[:x, nil], [:y, [1,2,3]]].sql_expr).should == '((x IS NULL) AND (y IN (1, 2, 3)))'
|
304
|
-
end
|
305
|
-
|
306
|
-
it "should support sql_negate on arrays with all two pairs" do
|
307
|
-
@d.l([[:x, 100],[:y, 'a']].sql_negate).should == '((x != 100) AND (y != \'a\'))'
|
308
|
-
@d.l([[:x, true], [:y, false]].sql_negate).should == '((x IS NOT TRUE) AND (y IS NOT FALSE))'
|
309
|
-
@d.l([[:x, nil], [:y, [1,2,3]]].sql_negate).should == '((x IS NOT NULL) AND (y NOT IN (1, 2, 3)))'
|
310
|
-
end
|
311
|
-
|
312
|
-
it "should support ~ on arrays with all two pairs" do
|
313
|
-
@d.l(~[[:x, 100],[:y, 'a']]).should == '((x != 100) OR (y != \'a\'))'
|
314
|
-
@d.l(~[[:x, true], [:y, false]]).should == '((x IS NOT TRUE) OR (y IS NOT FALSE))'
|
315
|
-
@d.l(~[[:x, nil], [:y, [1,2,3]]]).should == '((x IS NOT NULL) OR (y NOT IN (1, 2, 3)))'
|
316
|
-
end
|
317
|
-
|
318
|
-
it "should support sql_or on arrays with all two pairs" do
|
319
|
-
@d.l([[:x, 100],[:y, 'a']].sql_or).should == '((x = 100) OR (y = \'a\'))'
|
320
|
-
@d.l([[:x, true], [:y, false]].sql_or).should == '((x IS TRUE) OR (y IS FALSE))'
|
321
|
-
@d.l([[:x, nil], [:y, [1,2,3]]].sql_or).should == '((x IS NULL) OR (y IN (1, 2, 3)))'
|
322
|
-
end
|
323
|
-
|
324
272
|
it "should emulate columns for array values" do
|
325
273
|
@d.l([:x, :y]=>[[1,2], [3,4]].sql_array).should == '((x, y) IN ((1, 2), (3, 4)))'
|
326
274
|
@d.l([:x, :y, :z]=>[[1,2,5], [3,4,6]]).should == '((x, y, z) IN ((1, 2, 5), (3, 4, 6)))'
|
@@ -332,21 +280,6 @@ describe "Blockless Ruby Filters" do
|
|
332
280
|
@d.l([:x, :y, :z]=>[[1,2,5], [3,4,6]]).should == '(((x = 1) AND (y = 2) AND (z = 5)) OR ((x = 3) AND (y = 4) AND (z = 6)))'
|
333
281
|
end
|
334
282
|
|
335
|
-
it "should support Array#sql_string_join for concatenation of SQL strings" do
|
336
|
-
@d.lit([:x].sql_string_join).should == '(x)'
|
337
|
-
@d.lit([:x].sql_string_join(', ')).should == '(x)'
|
338
|
-
@d.lit([:x, :y].sql_string_join).should == '(x || y)'
|
339
|
-
@d.lit([:x, :y].sql_string_join(', ')).should == "(x || ', ' || y)"
|
340
|
-
@d.lit([:x.sql_function(1), :y.sql_subscript(1)].sql_string_join).should == '(x(1) || y[1])'
|
341
|
-
@d.lit([:x.sql_function(1), 'y.z'.lit].sql_string_join(', ')).should == "(x(1) || ', ' || y.z)"
|
342
|
-
@d.lit([:x, 1, :y].sql_string_join).should == "(x || '1' || y)"
|
343
|
-
@d.lit([:x, 1, :y].sql_string_join(', ')).should == "(x || ', ' || '1' || ', ' || y)"
|
344
|
-
@d.lit([:x, 1, :y].sql_string_join(:y__z)).should == "(x || y.z || '1' || y.z || y)"
|
345
|
-
@d.lit([:x, 1, :y].sql_string_join(1)).should == "(x || '1' || '1' || '1' || y)"
|
346
|
-
@d.lit([:x, :y].sql_string_join('y.x || x.y'.lit)).should == "(x || y.x || x.y || y)"
|
347
|
-
@d.lit([[:x, :y].sql_string_join, [:a, :b].sql_string_join].sql_string_join).should == "(x || y || a || b)"
|
348
|
-
end
|
349
|
-
|
350
283
|
it "should support StringExpression#+ for concatenation of SQL strings" do
|
351
284
|
@d.lit(:x.sql_string + :y).should == '(x || y)'
|
352
285
|
@d.lit([:x].sql_string_join + :y).should == '(x || y)'
|
@@ -762,6 +695,11 @@ describe "Sequel core extension replacements" do
|
|
762
695
|
l(Sequel.expr([[:a, 1], [:b, 2]]) & nil, "((a = 1) AND (b = 2) AND NULL)")
|
763
696
|
end
|
764
697
|
|
698
|
+
it "Sequel.expr should handle arrays that are not condition specifiers" do
|
699
|
+
l(Sequel.expr([1]), "(1)")
|
700
|
+
l(Sequel.expr([1, 2]), "(1, 2)")
|
701
|
+
end
|
702
|
+
|
765
703
|
it "Sequel.expr should treat blocks/procs as virtual rows and wrap the output" do
|
766
704
|
l(Sequel.expr{1} + 1, "(1 + 1)")
|
767
705
|
l(Sequel.expr{o__a} + 1, "(o.a + 1)")
|
@@ -1078,3 +1016,29 @@ describe "Sequel::SQL::Wrapper" do
|
|
1078
1016
|
@ds.literal(s.sql_string + '1').should == "(foo || '1')"
|
1079
1017
|
end
|
1080
1018
|
end
|
1019
|
+
|
1020
|
+
describe "Sequel::SQL::Blob#to_sequel_blob" do
|
1021
|
+
specify "should return self" do
|
1022
|
+
c = Sequel::SQL::Blob.new('a')
|
1023
|
+
c.to_sequel_blob.should equal(c)
|
1024
|
+
end
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
describe Sequel::SQL::Subscript do
|
1028
|
+
before do
|
1029
|
+
@s = Sequel::SQL::Subscript.new(:a, [1])
|
1030
|
+
@ds = Sequel::Dataset.new(nil)
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
specify "should have | return a new non-nested subscript" do
|
1034
|
+
s = (@s | 2)
|
1035
|
+
s.should_not equal(@s)
|
1036
|
+
@ds.literal(s).should == 'a[1, 2]'
|
1037
|
+
end
|
1038
|
+
|
1039
|
+
specify "should have [] return a new nested subscript" do
|
1040
|
+
s = @s[2]
|
1041
|
+
s.should_not equal(@s)
|
1042
|
+
@ds.literal(s).should == 'a[1][2]'
|
1043
|
+
end
|
1044
|
+
end
|
@@ -442,4 +442,8 @@ describe "Sequel Mock Adapter" do
|
|
442
442
|
specify "should automatically set version for postgres" do
|
443
443
|
Sequel.mock(:host=>'postgres').server_version.should == 90103
|
444
444
|
end
|
445
|
+
|
446
|
+
specify "should stub out the primary_key method for postgres" do
|
447
|
+
Sequel.mock(:host=>'postgres').primary_key(:t).should == :id
|
448
|
+
end
|
445
449
|
end
|
@@ -18,6 +18,89 @@ describe "Sequel core extensions" do
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
+
describe "Array and Hash extensions" do
|
22
|
+
before do
|
23
|
+
db = Sequel::Database.new
|
24
|
+
@d = db[:items]
|
25
|
+
def @d.l(*args, &block)
|
26
|
+
literal(filter_expr(*args, &block))
|
27
|
+
end
|
28
|
+
def @d.lit(*args)
|
29
|
+
literal(*args)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should support sql_expr on arrays with all two pairs" do
|
34
|
+
@d.l([[:x, 100],[:y, 'a']].sql_expr).should == '((x = 100) AND (y = \'a\'))'
|
35
|
+
@d.l([[:x, true], [:y, false]].sql_expr).should == '((x IS TRUE) AND (y IS FALSE))'
|
36
|
+
@d.l([[:x, nil], [:y, [1,2,3]]].sql_expr).should == '((x IS NULL) AND (y IN (1, 2, 3)))'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should support sql_negate on arrays with all two pairs" do
|
40
|
+
@d.l([[:x, 100],[:y, 'a']].sql_negate).should == '((x != 100) AND (y != \'a\'))'
|
41
|
+
@d.l([[:x, true], [:y, false]].sql_negate).should == '((x IS NOT TRUE) AND (y IS NOT FALSE))'
|
42
|
+
@d.l([[:x, nil], [:y, [1,2,3]]].sql_negate).should == '((x IS NOT NULL) AND (y NOT IN (1, 2, 3)))'
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should support ~ on arrays with all two pairs" do
|
46
|
+
@d.l(~[[:x, 100],[:y, 'a']]).should == '((x != 100) OR (y != \'a\'))'
|
47
|
+
@d.l(~[[:x, true], [:y, false]]).should == '((x IS NOT TRUE) OR (y IS NOT FALSE))'
|
48
|
+
@d.l(~[[:x, nil], [:y, [1,2,3]]]).should == '((x IS NOT NULL) OR (y NOT IN (1, 2, 3)))'
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should support sql_or on arrays with all two pairs" do
|
52
|
+
@d.l([[:x, 100],[:y, 'a']].sql_or).should == '((x = 100) OR (y = \'a\'))'
|
53
|
+
@d.l([[:x, true], [:y, false]].sql_or).should == '((x IS TRUE) OR (y IS FALSE))'
|
54
|
+
@d.l([[:x, nil], [:y, [1,2,3]]].sql_or).should == '((x IS NULL) OR (y IN (1, 2, 3)))'
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should support Array#sql_string_join for concatenation of SQL strings" do
|
58
|
+
@d.lit([:x].sql_string_join).should == '(x)'
|
59
|
+
@d.lit([:x].sql_string_join(', ')).should == '(x)'
|
60
|
+
@d.lit([:x, :y].sql_string_join).should == '(x || y)'
|
61
|
+
@d.lit([:x, :y].sql_string_join(', ')).should == "(x || ', ' || y)"
|
62
|
+
@d.lit([:x.sql_function(1), :y.sql_subscript(1)].sql_string_join).should == '(x(1) || y[1])'
|
63
|
+
@d.lit([:x.sql_function(1), 'y.z'.lit].sql_string_join(', ')).should == "(x(1) || ', ' || y.z)"
|
64
|
+
@d.lit([:x, 1, :y].sql_string_join).should == "(x || '1' || y)"
|
65
|
+
@d.lit([:x, 1, :y].sql_string_join(', ')).should == "(x || ', ' || '1' || ', ' || y)"
|
66
|
+
@d.lit([:x, 1, :y].sql_string_join(:y__z)).should == "(x || y.z || '1' || y.z || y)"
|
67
|
+
@d.lit([:x, 1, :y].sql_string_join(1)).should == "(x || '1' || '1' || '1' || y)"
|
68
|
+
@d.lit([:x, :y].sql_string_join('y.x || x.y'.lit)).should == "(x || y.x || x.y || y)"
|
69
|
+
@d.lit([[:x, :y].sql_string_join, [:a, :b].sql_string_join].sql_string_join).should == "(x || y || a || b)"
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should support sql_expr on hashes" do
|
73
|
+
@d.l({:x => 100, :y => 'a'}.sql_expr)[1...-1].split(' AND ').sort.should == ['(x = 100)', '(y = \'a\')']
|
74
|
+
@d.l({:x => true, :y => false}.sql_expr)[1...-1].split(' AND ').sort.should == ['(x IS TRUE)', '(y IS FALSE)']
|
75
|
+
@d.l({:x => nil, :y => [1,2,3]}.sql_expr)[1...-1].split(' AND ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should support sql_negate on hashes" do
|
79
|
+
@d.l({:x => 100, :y => 'a'}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x != 100)', '(y != \'a\')']
|
80
|
+
@d.l({:x => true, :y => false}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x IS NOT TRUE)', '(y IS NOT FALSE)']
|
81
|
+
@d.l({:x => nil, :y => [1,2,3]}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x IS NOT NULL)', '(y NOT IN (1, 2, 3))']
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should support ~ on hashes" do
|
85
|
+
@d.l(~{:x => 100, :y => 'a'})[1...-1].split(' OR ').sort.should == ['(x != 100)', '(y != \'a\')']
|
86
|
+
@d.l(~{:x => true, :y => false})[1...-1].split(' OR ').sort.should == ['(x IS NOT TRUE)', '(y IS NOT FALSE)']
|
87
|
+
@d.l(~{:x => nil, :y => [1,2,3]})[1...-1].split(' OR ').sort.should == ['(x IS NOT NULL)', '(y NOT IN (1, 2, 3))']
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should support sql_or on hashes" do
|
91
|
+
@d.l({:x => 100, :y => 'a'}.sql_or)[1...-1].split(' OR ').sort.should == ['(x = 100)', '(y = \'a\')']
|
92
|
+
@d.l({:x => true, :y => false}.sql_or)[1...-1].split(' OR ').sort.should == ['(x IS TRUE)', '(y IS FALSE)']
|
93
|
+
@d.l({:x => nil, :y => [1,2,3]}.sql_or)[1...-1].split(' OR ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should Hash#& and Hash#|" do
|
97
|
+
@d.l({:y => :z} & :x).should == '((y = z) AND x)'
|
98
|
+
@d.l({:x => :a} & {:y => :z}).should == '((x = a) AND (y = z))'
|
99
|
+
@d.l({:y => :z} | :x).should == '((y = z) OR x)'
|
100
|
+
@d.l({:x => :a} | {:y => :z}).should == '((x = a) OR (y = z))'
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
21
104
|
describe "Array#case and Hash#case" do
|
22
105
|
before do
|
23
106
|
@d = Sequel::Dataset.new(nil)
|